#!/usr/bin/env python # coding:utf-8 # 反射 # 对象的自省 # python中四种方法 hasattr getattr setattr delattr 都可用于类和对象, 因为python中一切皆对象, 类也是对象。
# python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射) class black_intro: feture = 'Ugly' def __init__(self, name, addr): self.name = name self.addr = addr def sell_house(self): print('%s 正在卖房子,SB才买呢。' % self.name) def rent_house(self): print('%s 正在租房子,SB才租。' % self.name) b1 = black_intro('众家地产', '苏州') print(hasattr(b1, 'name')) print(hasattr(b1, 'rent_house')) print(hasattr(b1, 'sale_house')) # False print(getattr(b1, 'name')) r = getattr(b1, 'rent_house') r() print(getattr(b1, 'age', '没找到它.')) setattr(b1, 'group', '二货') setattr(b1, 'age', '11') print(b1.__dict__) setattr(b1, 'agea', lambda x: x + 3) setattr(b1, 'func', lambda self: self.name + 'SB公司') print(b1.func(b1)) print(b1.agea(12)) delattr(b1, 'name') delattr(b1, 'age') print(b1.__dict__) ### 反射的应用场景 可插拨设计 # 可以事先定义好接口,接口只有在被完成后才会真正执行,这实现了即插即用 from ftp_client import FtpClient f1 = FtpClient('1.1.1.1') # f1.put()
### hasattr 和 getattr 通常是配合使用,如果有xx方法,才去执行xx方法。 if hasattr(f1, 'put'): func_get = getattr(f1, 'put') func_get() else: print('其他的逻辑') import sys obj = sys.modules[__name__] # 当前模块 即自己所在模块 print('--------->',hasattr(obj,'black_intro')) # 判断当前模块是否有属性
上面代码中用到的一个示例模块:
class FtpClient: 'ftp客户端,但是还么有实现具体的功能' def __init__(self,addr): print('正在连接服务器[%s]' %addr) self.addr=addr # def put(self): # print('正在上传文件')
类中使用的带有双下划线的 几个: __getattr__ __delattr__ __setattr__
#!/usr/bin/env python # coding:utf-8 # 类中内置的 __getattr__ __delattr__ __setattr__ # 只有 __getattr__ 最常用 class Foo: x = 1 def __init__(self,y): self.y = y def __getattr__(self, item): # 调用不存在的属性的时候会被执行 print("---------------------") def __delattr__(self, item): # 删除的时候会调用 print("执行了删除操作__delattr__") self.__dict__.pop(item) # def __setattr__(self, key, value): # print("执行了__setattr__") # # self.key=value # 这样会无限递归, 溢出 # self.__dict__[key] = value # 直接操作字典,才是正确方式 f1 = Foo(9) # 当设置了__setattr__ 时,实例化的同时会自动执行它 print(f1.x) f1.xxx # 触发 __getattr__ del f1.y # 删除时触发 __delattr__ f1.y1 = 33 # 设置时触发 __setattr__ print(f1.__dict__)
#!/usr/bin/env python # coding:utf-8 class Foo: x = 1 def __init__(self,name): self.name = name # def __getattr__(self, item): # 调用不存在的属性的时候会被执行 # print("---------------------") # # def __delattr__(self, item): # 删除的时候会调用 # print("执行了删除操作__delattr__") # self.__dict__.pop(item) def __setattr__(self, k, v): print('设置操作 __setattr__ ') # self.key=value # 这样会无限递归, 溢出 # self.__dict__[k] = v # 直接操作字典 是正确方式 if type(v) is str: print('可以设置') self.__dict__[k] = v.lower() # 且可以加上可控制的方法 else: print('值 必须是字符串') f2 = Foo('Alex') f2.age =18 f2.gender ='Male' print(f2.__dict__)
#!/usr/bin/env python # coding:utf-8 class Foo: x = 1 def __init__(self,name): self.name = name # def __getattr__(self, item): # 调用不存在的属性的时候会被执行 # print("---------------------") def __delattr__(self, item): # 删除的时候会调用 # print("执行了删除操作__delattr__") # self.__dict__.pop(item) print('不允许删除%s'% item) # 可以控制不允许删除 def __setattr__(self, k, v): print('设置操作 __setattr__ ') # self.key=value # 这样会无限递归, 溢出 # self.__dict__[k] = v # 直接操作字典 if type(v) is str: print('可以设置') self.__dict__[k] = v.lower() # 且可以加上可控制的方法 else: print('值 必须是字符串') f2 = Foo('Alex') f2.age =18 f2.gender ='Male' print(f2.__dict__) del f2.name print(f2.__dict__)
#!/usr/bin/env python # coding:utf-8 # 包装,来自于继承和派生的概念,根源是基于继承的标准类型。用来定制自己的方法 class List(list): def show_middle(self): mid_index = int(len(self)/2) return self[mid_index] # 自定义的append def append(self, obj): if type(obj) is str: super().append(obj) else: print("只能添加字符串") l2 = list("azkaban") print(l2,type(l2)) l3 = List(l2) print(l3.show_middle()) l3.append('232') print(l3)
#!/usr/bin/env python # coding:utf-8 # 二次加工标准类型(包装) class Foo: x = 1 def __init__(self,y): self.y = y def __getattr__(self, item): # 调用不存在的属性的时候会被执行 print("[%s]属性不存在" % item) def __getattribute__(self, item): # 不管是否找到属性都会执行。 print("执行了getattribute") raise AttributeError('抛出异常了。') # 而在使用抛出异常之后,才会去执行 __getattr__ f2 = Foo(9) print(f2.y) # print(f2.age)
授权
#!/usr/bin/env python # coding:utf-8 import time ## 类似于组合的方法 class FH: def __init__(self,na,mo,ec="utf-8"): self.file = open(na,mo,encoding=ec) self.mode = mo self.encoding = ec def write(self,line): t = time.strftime('%Y-%m-%d %X ') self.file.write('%s %s'%(t,line)) def __getattr__(self, item): return getattr(self.file,item) f1 = FH('a.txt', 'r+') f1.write('aaaaaaaaaaaaaaa ') f1.write('CPU温度过高 ') f1.write('内存不足 ') f1.write('硬盘剩余空间警告 ') f1.seek(0) # 其实执行的是打开的文件对象的seek方法 print(f1.read())
判断实例是否属于类:
#!/usr/bin/env python # coding:utf-8 class Foo: pass class bar(Foo): pass f1 = Foo() print(isinstance(f1,Foo)) # 实例是否属于类 print(issubclass(bar,Foo)) # 参数1 是否 参数2 的子类 b1 = bar() print(isinstance(b1,Foo)) # 也是True print(type(b1)) # 查看实例的类是谁
动态导入模块:
#!/usr/bin/env python # coding:utf-8 # 动态导入的方法: # mt = __import__('m1.t') # 只能导入最顶级模块 点后面的不会被导入 # print(mt) # m1.t.test1() # # from m1.t import test1,_test2 # # test1() # _test2() import importlib m = importlib.import_module('m1.t') # 动态导入就是基于反射的 print(m) m.test1() m.test2() ''' 动态导入模块方法1: __import__ 说明: 1. 函数功能用于动态的导入模块,主要用于反射或者延迟加载模块。 2. __import__(module)相当于import module 举例说明: 首先创建一个模块目录lib,然后在目录内创建一个模块为:aa.py 模块代码为: class c(object): def __str__(self): return 'C language' 在lib目录平级新建一个测试的模块,使用 __import__ 动态以字符串形式导入lib下的aa模块。 lib = __import__('lib.aa') # 相当于import lib c = lib.aa.c() print(c) 动态导入模块方法2:import importlib 实例还是上面的lib.aa模块,这里使用importlib进行动态导入(这个方法好理解,也是官方建议使用的) import importlib aa = importlib.import_module('lib.aa') c = aa.c() print(c) '''