反射
一:isinstance, type, issubclass
1. issubclass(),这个内置函数可以判断xxx类是否是yyy类的型的子类。
例:
class Base:
pass
class Foo(Base):
pass
class Bar(Foo):
pass
print(issubclass(Bar,Foo)) # True
print(issubclass(Foo,Bar)) # False
print(issubclass(Bar,Base)) # True
2. 前面学习过type(),查看obj是由哪个类创建的。
例:
class Foo:
pass
obj = Foo()
print(obj,type(obj)) # 查看obj的类
# <__main__.Foo object at 0x00000000024B8160> <class '__main__.Foo'>
2.1 现在type()可以判断xxx是否是xxx数据类型的。
例:
class Boy:
pass
class Girl:
pass
# 统计传进来的男生和女生分别有多少
def func(*args):
b = 0
g = 0
for obj in args:
if type(obj) == Boy:
b += 1
elif type(obj) == Girl:
g += 1
return b, g
ret = func(Boy(),Girl(),Boy(),Girl(),Boy(),Girl(),Boy(),Girl())
print(ret)
# (4,4)
2.2 也可以先判断好数据类型必须是int或者float,进行有意义的计算。
例:
def add(a,b):
if (type(a) == int or type(a) == float) and (type(b) == int or type(b) == float):
return a + b
else:
print('报错')
3. isinstance 也可以判断xxx是否是yyy类型的数据,但是isinstance没有typename精准。
例:
class Base:
pass
class Foo(Base):
pass
class Bar(Foo):
pass
print(isinstance(Foo(),Foo)) # True
print(isinstance(Foo(),Base)) # True
print(isinstance(Foo(),Bar)) # False
注:isinstance可以判断该对象是否是xxx家族体系的(只能往上判断,不能往下判断)
二:区分函数和方法
如何区分函数和方法
例:
def func():
pass
print(func) # <function func at 0x0000000002071E18>
class Foo:
def chi(self):
print('1')
f = Foo()
print(f.chi) # <bound method Foo.chi of <__main__.Foo object at 0x00000000024E83C8>>
函数下打印的时候,显示的是function;方法在打印的时候现实的method.
但其实不一定是这样的。
例:
class Foo:
def chi(self):
print('我是吃')
@staticmethod
def ststic_method():
pass
@classmethod
def class_method(cls):
pass
f = Foo()
print(f.chi) # <bound method Foo.chi of <__main__.Foo object at 0x00000000024C83C8>>
print(f.ststic_method) # <function Foo.ststic_method at 0x00000000022F7950>
print(f.class_method) # <bound method Foo.class_method of <class '__main__.Foo'>>
print(Foo.chi) # <function Foo.chi at 0x00000000024F78C8>
print(Foo.ststic_method) # <function Foo.ststic_method at 0x00000000024B7950>
print(Foo.class_method) # <bound method Foo.class_method of <class '__main__.Foo'>>
注: function 表示是函数
method 表示是方法
结论:
1.类方法,不论任何情况都是方法。
2.静态方法,不论任何情况都是函数。
3.实例方法,如果是实例(对象)访问就是方法,类名访问就
是函数。
如何用程序分辨方法和函数,借助于types模块。
例:
# 所有的方法都是MethodType的实例
#所有的函数都是FunctionType的实例
from types import MethodType ,FunctionType
def func():
pass
# print(isinstance(func,FunctionType)) # True
# print(isinstance(func,MethodType)) # False
class Foo:
def chi(self):
print('我是吃')
@staticmethod
def static_method():
pass
@classmethod
def class_method(cls):
pass
obj = Foo()
print(type(obj.chi)) # <class 'method'>
print(type(Foo.chi)) # <class 'function'>
print(isinstance(obj.chi,MethodType)) # True
print(isinstance(Foo.chi,FunctionType)) # True
print(isinstance(Foo.static_method,FunctionType)) # False
print(isinstance(Foo.static_method,MethodType)) # True
print(isinstance(Foo.class_method,MethodType)) # True
print(isinstance(Foo.class_method,FunctionType)) # False
注:用types中的FunctionType和MethofType可以区分当前内容是方法还是函数。
三:反射
例:
我们需要用别人写的代码,但是我们并不清楚代码中的功能,这时就需要我们自己去测试,来拿到自己想用的功能。
首先拿到 代码:某人.py
def chi():
print('某人能吃一头牛')
def he():
print('某人能喝一条河')
def chui():
print('某人能八天吹破')
def shui():
print('某人能睡一年')
# 现在需要自己一个一个的调用,在调用之前已经知道代码中的功能。
import moster
while 1:
print('''代码中功能有
chi
he
chui
shui
大概其就这么多
''')
gn = input('请输入你想测试的功能:')
if gn == 'chi':
master.chi()
elif gn == 'he':
master.he()
elif gn == 'chui':
master.chui()
elif gn == 'shui':
master.shui()
else:
print('一共四个功能')
现在某人.py文件里有100个功能,我们需要进行100次测试,工程有点浩大。但是我们可以使用反射来简单的完成这个好大的工程,
如果能通过字符串动态来访问模块中的功能,就能解决这个问题。
根据上面的操作来进行逆向操作,我们先输入自己想要的功能,然后去代码模块里找,这就叫:反射
例:
import moster
while 1:
print('''代码中功能有
chi
he
chui
shui
大概其就这么多
''')
gn = input('请输入你想测试的功能:')
func = getattr(moster,gn)
func()
getattr(对象.字符串): 从对象里获取到xxx功能,此时xxx是一个字符串,get表示找,attr表示属性(功能)。
但是如果在代码里找不到我想要的内容,就会报错,所以在获取attr之前先判断一下,代码里有没有attr。
例:
import master
from types import FunctionType
while 1:
print('''代码中功能有
chi
he
chui
shui
大概其就这么多
''')
gn = input('请输入你想测试的功能:')
if hasattr(master,gn): # 如果master里有你功能,获取这个功能并执行。
attr = getattr(master,gn) # 判断是否是函数,只有函数才可以被调用
if isinstance(attr,FunctionType):
attr()
else:
print(attr)
这里讲到两个函数,一个是getattr(),一个是hasattr()。getattr()用来获取信息,hasattr()用来判断xxx中否包含了xxx功能。
例:
class Preson:
country = '大清'
def chi(self):
pass
# 类中的内容可以这样动态地进行获取
print(getattr(Preson,'country'))
print(getattr(Preson,'chi')) # 相当于 类名.'静态属性' 函数
# 对象一样可以
obj = Preson()
print(getattr(obj,'country'))
print(getattr(obj,'chi')) # 相当于 对象.'方法名' 方法
总结:
getattr可以从模块中获取内容,也可以从类中获取内容,也可以从对象中获取内容。
在python中一切皆为对象,那就可以认为getattr从对象中动态的获取成员。
补充:
反射一共有4个函数:
1:getattr(obj.str) 从obj中获取str成员
2: hasattr(obj.str) 判断obj中是否包含str成员
3: setattr(obj,str,value) 把obj中的成员设置成value,注:这里的value可以是值,也可以是函数或者方法。
4:delattr(obj,str) 把obj中的str成员删除
注:以上操作都是在内存中进行,不会影响源代码。
class Foo:
pass
f = Foo()
print(hasattr(f,'chi')) # False
setattr(f,'chi','123')
print(f.chi) # 添加了一个属性信息
setattr(f,'chi',lambda x : x + 1)
print(f.chi(3)) # 4
print(f.chi) # 此时chi既不是静态方法,也不是实例方法,也不是类方法,而是相当于在类中写了一个self.chi = lambda
print(f.__dict__) # {'chi': <function <lambda> at 0x0000000002081E18>}
delattr(f,'chi') # 删除 chi
print(hasattr(f,'chi')) # 判断f中是否还包含'chi' 结果:False