反射
python中面向对象的反射:通过字符串形式操作对象的相关属性。python中一切事物都是对象(都可以使用反射)
四个可以实现自省的函数:hasattr 、 getattr 、 setattr 、delattr
对对象的反射
class Person:s = "静态变量"def __init__(self, name, age):self.name = nameself.age = agedef say_hi(self):print("hi,%s" % self.name)obj = Person("小明", 18)================================================# 检测是否含有某种属性print(hasattr(obj, 'name'))print(hasattr(obj, 'say_hi'))# 运行结果TrueTrue================================================# 获取属性n = getattr(obj, 'name')print(n)func = getattr(obj, 'say_hi')func()print(getattr(obj,'aaaaaaaa','不存在啊')) # 报错# 运行结果小明hi,小明================================================# 设置属性setattr(obj, 'smart', True)setattr(obj, 'show_name', lambda self: self.name + 'smart')print(obj.__dict__)print(obj.show_name(obj))# 运行结果{'name': '小明', 'age': 18, 'smart': True, 'show_name': <function <lambda> at 0x000001A703627168>}小明smart================================================# 删除属性delattr(obj, 'age')delattr(obj, 'show_name')# delattr(obj,'show_name111') # 不存在,则报错print(obj.__dict__)# 运行结果{'name': '小明', 'smart': True}
对类的反射
class Person:s = "静态变量"def __init__(self, name, age):self.name = nameself.age = agedef say_hi(self):print("hi,%s" % self.name)def func(self):return 'func'@staticmethoddef learn():return 'go to learn'print(getattr(Person, 's'))print(getattr(Person, 'func'))print(getattr(Person, 'learn'))# 运行结果静态变量<function Person.func at 0x0000014D85D2D558><function Person.learn at 0x0000014D85D2D5E8>
当前模块的反射
import sysdef s1():print('s1')def s2():print('s2')this_module = sys.modules[__name__]print(hasattr(this_module, 's1'))print(getattr(this_module, 's2'))# 运行结果True<function s2 at 0x000001C1E08E70D8>
其他模块的反射
- 程序目录:
- module_test.py
- test.py
- 当前文件:
- test.py
import module_test as objobj.test()print(hasattr(obj,'test'))getattr(obj,'test')()
举例
使用反射前
class User:def login(self):print('欢迎来到登录页面')def register(self):print('欢迎来到注册页面')def save(self):print('欢迎来到存储页面')while 1:choose = input('>>>').strip()if choose == 'login':obj = User()obj.login()elif choose == 'register':obj = User()obj.register()elif choose == 'save':obj = User()obj.save()
使用反射后
class User:def login(self):print('欢迎来到登录页面')def register(self):print('欢迎来到注册页面')def save(self):print('欢迎来到存储页面')user = User()while 1:choose = input('>>>').strip()if hasattr(user, choose):func = getattr(user, choose)func()else:print('输入错误。。。。')
函数 vs 方法
通过打印函数(方法)名确定
def func():passprint(func)class A:def func(self):passprint(A.func)obj = A()print(obj.func)# 运行结果<function func at 0x0000029C8F2270D8><function A.func at 0x0000029C8F2F80D8><bound method A.func of <__main__.A object at 0x0000029C8ED9E988>>
由此可见,类实例化为对象后里面是方法,直接定义或在类内定义的是函数。
通过types模块确定
from types import FunctionTypefrom types import MethodTypedef func():passclass A:def func(self):passobj = A()print(isinstance(func, FunctionType))print(isinstance(A.func, FunctionType))print(isinstance(obj.func, FunctionType))print(isinstance(obj.func, MethodType))#运行结果TrueTrueFalseTrue
静态方法是函数
即使在实例化对象里,静态方法也是函数。
from types import FunctionTypefrom types import MethodTypeclass A:def func(self):pass@classmethoddef func1(self):pass@staticmethoddef func2(self):passobj = A()# 静态方法其实是函数print(isinstance(A.func2,FunctionType))print(isinstance(obj.func2,FunctionType))# 运行结果TrueTrue
函数与方法的区别
- 函数是显式传递数据的,例如我们要为 len() 函数传递需要处理的数据。
- 函数与对象无关
- 方法是隐式传递数据的,方法可操作类内部的数据。
- 方法与对象相关联。如在使用 strip() 方法时要通过str对象调用。
双下方法
len
```python class B: def len(self):return 666
b = B() print(len(b)) # len 一个对象就会触发 len方法。
class A: def init(self): self.a = 1 self.b = 2 def len(self): return len(self.dict)
a = A() print(a.dict) print(len(a))
运行结果
666 {‘a’: 1, ‘b’: 2} 2
<a name="kOEOo"></a>## __hash__```pythonclass A:def __init__(self):self.a = 1self.b = 2def __hash__(self):print(str(self.a)+str(self.b))return hash(str(self.a)+str(self.b))a = A()print(hash(a))# 运行结果12-1326642716895049178
str
如果一个类中定义了str方法,那么在打印 对象 时,默认输出该方法的返回值。
class A:def __init__(self):passdef __str__(self):return 'jack'a = A()print(a)print('%s' % a)# 运行结果jackjack
repr
如果一个类中定义了repr方法,那么在repr(对象) 时,默认输出该方法的返回值。
class A:def __init__(self):passdef __repr__(self):return 'jack'a = A()print(repr(a))print('%r'%a)#运行结果jackjack
call
对象后加括号,触发执行。
注意:new方法的执行是由创建对象触发的,即:对象 = 类名() ;而call方法是 对象() 或 类()() 触发调用的。
class Foo:def __init__(self):print('__init__')def __call__(self, *args, **kwargs):print('__call__')obj = Foo() # 执行 __init__obj() # 执行 __call__# 运行结果__init____call__
eq
判断两个对象是否相等时调用
class A:def __init__(self):self.a = 1self.b = 2def __eq__(self,obj):if self.a == obj.a and self.b == obj.b:return Truea = A()b = A()print(a == b)# 运行结果True
del
析构方法,当对象在内存中被释放时,自动触发执行。
注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,
因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触
发执行的。
new
- new() 方法是在类准备将自身实例化时调用。
- new() 方法始终都是类的静态方法,即使没有被加上静态方法装饰器。
通常来说,新式类开始实例化时, new() 方法会返回cls(cls指代当前类)的实例,然后该类的 init() 方法作为构造方法会接收这个实例(即self)作为自己的第一个参数,然后依次传入 new() 方法中接收的位置参数和命名参数。 ```python class A:
def init(self):
self.x = 1print('in init function')
def new(cls, args, *kwargs):
print('in new function')return object.__new__(A, *args, **kwargs)
a = A() print(a.x)
运行结果
in new function in init function 1
<a name="zUTDC"></a>## __item__系列```pythonclass Foo:def __init__(self, name):self.name = namedef __getitem__(self, item):print(self.__dict__[item])def __setitem__(self, key, value):self.__dict__[key] = valueprint('赋值成功')def __delitem__(self, key):print('del obj[key]时,我执行')self.__dict__.pop(key)def __delattr__(self, item):print('del obj.key时,我执行')self.__dict__.pop(item)f1 = Foo('sb')f1['age'] = 18f1['age1'] = 19print(f1.__dict__)del f1.age1del f1['age']f1['name'] = 'mingzi'print(f1.__dict__)# 运行结果赋值成功赋值成功{'name': 'sb', 'age': 18, 'age1': 19}del obj.key时,我执行del obj[key]时,我执行赋值成功{'name': 'mingzi'}
上下文管理器相关
enter和exit
class A:def __init__(self, text):self.text = textdef __enter__(self): # 开启上下文管理器对象时触发此方法self.text = self.text + '您来啦'return self # 将实例化的对象返回f1def __exit__(self, exc_type, exc_val, exc_tb): # 执行完上下文管理器对象f1时触发此方法self.text = self.text + '这就走啦'with A('大爷') as f1:print(f1.text)print(f1.text)# 运行结果大爷您来啦大爷您来啦这就走啦
