反射

python中面向对象的反射:通过字符串形式操作对象的相关属性。python中一切事物都是对象(都可以使用反射)

四个可以实现自省的函数:hasattr 、 getattr 、 setattr 、delattr

对对象的反射

  1. class Person:
  2. s = "静态变量"
  3. def __init__(self, name, age):
  4. self.name = name
  5. self.age = age
  6. def say_hi(self):
  7. print("hi,%s" % self.name)
  8. obj = Person("小明", 18)
  9. ================================================
  10. # 检测是否含有某种属性
  11. print(hasattr(obj, 'name'))
  12. print(hasattr(obj, 'say_hi'))
  13. # 运行结果
  14. True
  15. True
  16. ================================================
  17. # 获取属性
  18. n = getattr(obj, 'name')
  19. print(n)
  20. func = getattr(obj, 'say_hi')
  21. func()
  22. print(getattr(obj,'aaaaaaaa','不存在啊')) # 报错
  23. # 运行结果
  24. 小明
  25. hi,小明
  26. ================================================
  27. # 设置属性
  28. setattr(obj, 'smart', True)
  29. setattr(obj, 'show_name', lambda self: self.name + 'smart')
  30. print(obj.__dict__)
  31. print(obj.show_name(obj))
  32. # 运行结果
  33. {'name': '小明', 'age': 18, 'smart': True, 'show_name': <function <lambda> at 0x000001A703627168>}
  34. 小明smart
  35. ================================================
  36. # 删除属性
  37. delattr(obj, 'age')
  38. delattr(obj, 'show_name')
  39. # delattr(obj,'show_name111') # 不存在,则报错
  40. print(obj.__dict__)
  41. # 运行结果
  42. {'name': '小明', 'smart': True}

对类的反射

  1. class Person:
  2. s = "静态变量"
  3. def __init__(self, name, age):
  4. self.name = name
  5. self.age = age
  6. def say_hi(self):
  7. print("hi,%s" % self.name)
  8. def func(self):
  9. return 'func'
  10. @staticmethod
  11. def learn():
  12. return 'go to learn'
  13. print(getattr(Person, 's'))
  14. print(getattr(Person, 'func'))
  15. print(getattr(Person, 'learn'))
  16. # 运行结果
  17. 静态变量
  18. <function Person.func at 0x0000014D85D2D558>
  19. <function Person.learn at 0x0000014D85D2D5E8>

当前模块的反射

  1. import sys
  2. def s1():
  3. print('s1')
  4. def s2():
  5. print('s2')
  6. this_module = sys.modules[__name__]
  7. print(hasattr(this_module, 's1'))
  8. print(getattr(this_module, 's2'))
  9. # 运行结果
  10. True
  11. <function s2 at 0x000001C1E08E70D8>

其他模块的反射

  • 程序目录:
    • module_test.py
    • test.py
  • 当前文件:
    • test.py
  1. import module_test as obj
  2. obj.test()
  3. print(hasattr(obj,'test'))
  4. getattr(obj,'test')()

举例

使用反射前

  1. class User:
  2. def login(self):
  3. print('欢迎来到登录页面')
  4. def register(self):
  5. print('欢迎来到注册页面')
  6. def save(self):
  7. print('欢迎来到存储页面')
  8. while 1:
  9. choose = input('>>>').strip()
  10. if choose == 'login':
  11. obj = User()
  12. obj.login()
  13. elif choose == 'register':
  14. obj = User()
  15. obj.register()
  16. elif choose == 'save':
  17. obj = User()
  18. obj.save()

使用反射后

  1. class User:
  2. def login(self):
  3. print('欢迎来到登录页面')
  4. def register(self):
  5. print('欢迎来到注册页面')
  6. def save(self):
  7. print('欢迎来到存储页面')
  8. user = User()
  9. while 1:
  10. choose = input('>>>').strip()
  11. if hasattr(user, choose):
  12. func = getattr(user, choose)
  13. func()
  14. else:
  15. print('输入错误。。。。')

函数 vs 方法

通过打印函数(方法)名确定

  1. def func():
  2. pass
  3. print(func)
  4. class A:
  5. def func(self):
  6. pass
  7. print(A.func)
  8. obj = A()
  9. print(obj.func)
  10. # 运行结果
  11. <function func at 0x0000029C8F2270D8>
  12. <function A.func at 0x0000029C8F2F80D8>
  13. <bound method A.func of <__main__.A object at 0x0000029C8ED9E988>>

由此可见,类实例化为对象后里面是方法,直接定义或在类内定义的是函数。

通过types模块确定

  1. from types import FunctionType
  2. from types import MethodType
  3. def func():
  4. pass
  5. class A:
  6. def func(self):
  7. pass
  8. obj = A()
  9. print(isinstance(func, FunctionType))
  10. print(isinstance(A.func, FunctionType))
  11. print(isinstance(obj.func, FunctionType))
  12. print(isinstance(obj.func, MethodType))
  13. #运行结果
  14. True
  15. True
  16. False
  17. True

静态方法是函数

即使在实例化对象里,静态方法也是函数。

  1. from types import FunctionType
  2. from types import MethodType
  3. class A:
  4. def func(self):
  5. pass
  6. @classmethod
  7. def func1(self):
  8. pass
  9. @staticmethod
  10. def func2(self):
  11. pass
  12. obj = A()
  13. # 静态方法其实是函数
  14. print(isinstance(A.func2,FunctionType))
  15. print(isinstance(obj.func2,FunctionType))
  16. # 运行结果
  17. True
  18. True

函数与方法的区别

  1. 函数是显式传递数据的,例如我们要为 len() 函数传递需要处理的数据。
  2. 函数与对象无关
  3. 方法是隐式传递数据的,方法可操作类内部的数据。
  4. 方法与对象相关联。如在使用 strip() 方法时要通过str对象调用。

    双下方法

    len

    ```python class B: def len(self):
    1. 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

  1. <a name="kOEOo"></a>
  2. ## __hash__
  3. ```python
  4. class A:
  5. def __init__(self):
  6. self.a = 1
  7. self.b = 2
  8. def __hash__(self):
  9. print(str(self.a)+str(self.b))
  10. return hash(str(self.a)+str(self.b))
  11. a = A()
  12. print(hash(a))
  13. # 运行结果
  14. 12
  15. -1326642716895049178

str

如果一个类中定义了str方法,那么在打印 对象 时,默认输出该方法的返回值。

  1. class A:
  2. def __init__(self):
  3. pass
  4. def __str__(self):
  5. return 'jack'
  6. a = A()
  7. print(a)
  8. print('%s' % a)
  9. # 运行结果
  10. jack
  11. jack

repr

如果一个类中定义了repr方法,那么在repr(对象) 时,默认输出该方法的返回值。

  1. class A:
  2. def __init__(self):
  3. pass
  4. def __repr__(self):
  5. return 'jack'
  6. a = A()
  7. print(repr(a))
  8. print('%r'%a)
  9. #运行结果
  10. jack
  11. jack

call

对象后加括号,触发执行。

注意:new方法的执行是由创建对象触发的,即:对象 = 类名() ;而call方法是 对象() 或 类()() 触发调用的。

  1. class Foo:
  2. def __init__(self):
  3. print('__init__')
  4. def __call__(self, *args, **kwargs):
  5. print('__call__')
  6. obj = Foo() # 执行 __init__
  7. obj() # 执行 __call__
  8. # 运行结果
  9. __init__
  10. __call__

eq

判断两个对象是否相等时调用

  1. class A:
  2. def __init__(self):
  3. self.a = 1
  4. self.b = 2
  5. def __eq__(self,obj):
  6. if self.a == obj.a and self.b == obj.b:
  7. return True
  8. a = A()
  9. b = A()
  10. print(a == b)
  11. # 运行结果
  12. True

del

析构方法,当对象在内存中被释放时,自动触发执行。

注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,
因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触
发执行的。

new

  • new() 方法是在类准备将自身实例化时调用。
  • new() 方法始终都是类的静态方法,即使没有被加上静态方法装饰器。
  • 通常来说,新式类开始实例化时, new() 方法会返回cls(cls指代当前类)的实例,然后该类的 init() 方法作为构造方法会接收这个实例(即self)作为自己的第一个参数,然后依次传入 new() 方法中接收的位置参数和命名参数。 ```python class A:

    def init(self):

    1. self.x = 1
    2. print('in init function')

    def new(cls, args, *kwargs):

    1. print('in new function')
    2. return object.__new__(A, *args, **kwargs)

a = A() print(a.x)

运行结果

in new function in init function 1

  1. <a name="zUTDC"></a>
  2. ## __item__系列
  3. ```python
  4. class Foo:
  5. def __init__(self, name):
  6. self.name = name
  7. def __getitem__(self, item):
  8. print(self.__dict__[item])
  9. def __setitem__(self, key, value):
  10. self.__dict__[key] = value
  11. print('赋值成功')
  12. def __delitem__(self, key):
  13. print('del obj[key]时,我执行')
  14. self.__dict__.pop(key)
  15. def __delattr__(self, item):
  16. print('del obj.key时,我执行')
  17. self.__dict__.pop(item)
  18. f1 = Foo('sb')
  19. f1['age'] = 18
  20. f1['age1'] = 19
  21. print(f1.__dict__)
  22. del f1.age1
  23. del f1['age']
  24. f1['name'] = 'mingzi'
  25. print(f1.__dict__)
  26. # 运行结果
  27. 赋值成功
  28. 赋值成功
  29. {'name': 'sb', 'age': 18, 'age1': 19}
  30. del obj.key时,我执行
  31. del obj[key]时,我执行
  32. 赋值成功
  33. {'name': 'mingzi'}

上下文管理器相关

enterexit

  1. class A:
  2. def __init__(self, text):
  3. self.text = text
  4. def __enter__(self): # 开启上下文管理器对象时触发此方法
  5. self.text = self.text + '您来啦'
  6. return self # 将实例化的对象返回f1
  7. def __exit__(self, exc_type, exc_val, exc_tb): # 执行完上下文管理器对象f1时触发此方法
  8. self.text = self.text + '这就走啦'
  9. with A('大爷') as f1:
  10. print(f1.text)
  11. print(f1.text)
  12. # 运行结果
  13. 大爷您来啦
  14. 大爷您来啦这就走啦