一、反射机制 *
反射可以理解为
- 通过字符串的形式,动态导入模块;
- 利用字符串的形式,在对象(模块)中操作(查找/获取/删除/添加)成员,是一种基于字符串的事件驱动!
反射机制的内置函数
1 # hasattr(object,attr) 2 # 输入两个参数(对象,字符串类型(方法或属性)),判断一个对象里是否有某个属性或方法,返回布尔值,有为True,否则False 3 class Foo: 4 def f1(self): 5 pass 6 obj = Foo() 7 print(hasattr(obj,"f1")) 8 # 运行结果:True 9 10 11 # getattr(object,attr[,default]) 12 # 获取对象的属性或方法,可设置输出默认值, 13 # 如果获取方法,返回的是内存地址,如果需要运行,后面添加一对括号 14 class Foo: 15 def f1(self): 16 print("获取了f1方法") 17 obj = Foo() 18 ret = getattr(obj,"f1") 19 ret() 20 print(ret) 21 # 运行结果:获取了f1方法 22 # <bound method Foo.f1 of <__main__.Foo object at 0x0000024FE505E9B0>> 23 24 # setattr(object,attr,values) 25 # 动态的给对象的属性赋值(内存地址),若属性不存在,则先创建再赋值 26 class Foo: 27 def __init__(self,a1): 28 self.a1 = a1 29 obj = Foo(1) 30 print(getattr(obj,"a1")) 31 #运行结果:1 32 setattr(obj,"a1",2) # 将对象中的属性重新赋值 33 print(getattr(obj,"a1")) 34 #运行结果:2 35 setattr(obj,"a2",3) #在对象中创建一个新的属性a2并赋值 36 print(getattr(obj,"a2")) 37 #运行结果:3 38 39 40 # delattr(object,attr,values) 41 # 动态的删除对象的属性(内存地址) 42 class Foo: 43 def __init__(self,a1): 44 self.a1=a1 45 obj = Foo(1) 46 print(getattr(obj,"a1")) 47 # 运行结果: 1 48 setattr(obj,"a2",2) 49 print(getattr(obj,"a2")) 50 # 运行结果: 2 51 delattr(obj,"a2") 52 print(getattr(obj,"a2")) #删除对象中的属性 53 #运行结果:AttributeError: 'Foo' object has no attribute 'a2'
二、如何正确的判断方法与函数?
目前我们印象中的方法就是封装在类内部的函数,实际上这样说不严谨;
1 # 如何判断方法与函数 2 # tpye 3 # 判断类型 4 class Foo: 5 def f1(self): 6 pass 7 obj = Foo() 8 print(obj,type(obj.f1)) # 当我们用对象调用类中的方法时,我们通过type查看到的是方法 9 # 运行结果:<__main__.Foo object at 0x0000028E0F10E898> <class 'method'> 10 print(Foo,type(Foo.f1)) # 当我们用类调用类中的方法时,我们通过type查看到的是函数 11 # 运行结果:<class '__main__.Foo'> <class 'function'> 12 # 总结:封装在类中的函数通过对象调用时是真正的方法。
三、callattr()、issubclass()、isinstance、type()的使用
callattr()方法是用来判断传入的参数是否可以被调用
1 callable 2 判断输入的参数是否可以被调用 3 class Foo: 4 def f1(self): 5 pass 6 def __call__(self, *args, **kwargs): 7 pass 8 def func(): 9 pass 10 obj = Foo() 11 print(callable(Foo)) # 类是可以被调用的类型 12 # 运行结果: True 13 print(callable(obj.f1)) # 方法是可以被调用的类型 14 # 运行结果: True 15 print(callable(func)) #函数是可以被调用的类型 16 # 运行结果: True 17 print(callable(obj)) #实例化的对象是可以被调用的类型,注:类的内部要有__call__方法 18 # 运行结果: True
issubclass()方法是用判断传入的两个参数,前一个参数是否是后一个参数的派生类
1 # issubclass 2 # 判断传入的两个参数,前一个参数是否是后一个参数的子类 3 class Base: 4 pass 5 class Foo(Base): 6 pass 7 print(issubclass(Foo,Base)) 8 # 运行结果: True
isinstance()方法是判断传入两个参数,第一个传入的参数(对象),是否是第二个参数(类)的实例
1 # isinstance 2 # 判断传入两个参数,第一个传入的参数(对象),是否是第二个参数(类)的实例 3 class Base: 4 def f1(self): 5 pass 6 def f2(self): 7 pass 8 class Foo(Base): 9 def f1(self): 10 pass 11 class Last: 12 pass 13 obj = Foo() 14 print(isinstance(obj,Last)) 15 #运行结果:False 16 print(isinstance(obj,Foo)) # obj是Foo类的一个实例化对象 17 #运行结果:True 18 print(isinstance(obj,Base))# obj也可以是Foo基类的一个实例化对象 19 #运行结果:True 20 # 总结:isinstance可以判断对象是否是类或类的基类中的实例
type()
1 # type 2 # 判断传入的参数(对象)是哪个类的实例化对象 3 class Base: 4 pass 5 class Foo(Base): 6 pass 7 obj = Foo() 8 print(obj,type(obj)) # 获取当前对象是由哪个类创建 9 # 运行结果: <__main__.Foo object at 0x000001567FC9E8D0> <class '__main__.Foo'>