6.9 KiB
6.9 KiB
反射
Python 中,反射(Reflection)是一种能力,使得程序能够在运行时查看和修改自身的结构和行为。通过反射,您可以动态地访问和操作类的属性和方法,而无需在编写代码时确定它们的确切名称。这在某些情况下非常有用,例如在框架、库或插件系统中。
对对象的反射
class Foo:
f = "类的静态变量"
def __init__(self, name, age):
self.name = name
self.age = age
def say_hi(self):
print("Hi %s" % self.name)
obj = Foo("EaglesLab", 18)
# 检测是否含有某属性
print(hasattr(obj, "name"))
print(hasattr(obj, "say_hi"))
# 获取属性
print(getattr(obj, "name"))
func = getattr(obj, "say_hi")
func()
print(getattr(obj, "job", "不存在啊")) # 报错
# 设置属性
setattr(obj, "job", "teacher")
setattr(obj, "show_name", lambda self: self.name + " 真帅")
print(obj.__dict__)
print(obj.show_name(obj))
# 删除属性
delattr(obj, "age")
delattr(obj, "show_name")
# delattr(obj,'show_name111') # 不存在,则报错
print(obj.__dict__)
对类的反射
class Foo(object):
staticField = "test"
def __init__(self):
self.name = "陈松"
def func(self):
return "func"
@staticmethod
def bar():
return "bar"
print(getattr(Foo, "staticField"))
print(getattr(Foo, "func"))
print(getattr(Foo, "bar"))
案例:基于反射的用户管理
使用反射前
class User:
def login(self):
print('欢迎来到登录页面')
def register(self):
print('欢迎来到注册页面')
def save(self):
print('欢迎来到存储页面')
user = User()
while 1:
choose = input('>>>').strip()
if choose == 'login':
user.login()
elif choose == 'register':
user.register()
elif choose == 'save':
user.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():
pass
print(func)
class A:
def func(self):
pass
print(A.func)
obj = A()
print(obj.func)
通过 types 模块验证
from types import FunctionType
from types import MethodType
def func():
pass
class A:
def func(self):
pass
obj = A()
print(isinstance(func,FunctionType))
print(isinstance(A.func,FunctionType))
print(isinstance(obj.func,FunctionType))
print(isinstance(obj.func,MethodType))
静态方法是函数
from types import FunctionType
from types import MethodType
class A:
def func(self):
pass
@classmethod
def func1(self):
pass
@staticmethod
def func2(self):
pass
obj = A()
# 静态方法其实是函数
print(isinstance(A.func2,FunctionType))
print(isinstance(obj.func2,FunctionType))
函数与方法的区别
那么,函数和方法除了上述的不同之处,我们还总结了一下几点区别。
- 函数的是显式传递数据的。如我们要指明为len()函数传递一些要处理数据。
- 函数则跟对象无关。
- 方法中的数据则是隐式传递的。
- 方法可以操作类内部的数据。
- 方法跟对象是关联的。如我们在用 strip() 方法是,是不是都是要通过 str 对象调用,比如我们有字符串 s,然后 s.strip() 这样调用。是的,strip()方法属于str对象。
我们或许在日常中会口语化称呼函数和方法时不严谨,但是我们心中要知道二者之间的区别。
在其他语言中,如 Java 中只有方法,C 中只有函数,C++ 则取决于是否在类中。
双下方法
__init__
用于初始化类的实例,接收参数并设置实例属性。
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
__len__
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(len(a))
__hash__
class A:
def __init__(self):
self.a = 1
self.b = 2
def __hash__(self):
return hash(str(self.a)+str(self.b))
a = A()
print(hash(a))
__str__
如果一个类中定义了 __str__
方法,那么在 print(obj)
时,默认输出该方法的返回值。
class A:
def __init__(self):
pass
def __str__(self):
return '陈松'
a = A()
print(a)
print('%s' % a)
__repr__
如果一个类中定义了 __repr__
方法,那么在 repr(obj)
时,默认输出该方法的返回值。
class A:
def __init__(self):
pass
def __repr__(self):
return '陈松'
a = A()
print(repr(a))
print('%r'%a)
__call__
通过 obj()
触发执行。
class Foo:
def __init__(self):
print('__init__')
def __call__(self, *args, **kwargs):
print('__call__')
obj = Foo() # 执行 __init__
obj() # 执行 __call__
__eq__
通过 ==
触发类中的 __eq__
方法
class A:
def __init__(self):
self.a = 1
self.b = 2
def __eq__(self,obj):
if self.a == obj.a and self.b == obj.b:
return True
a = A()
b = A()
print(a == b)
__del__
析构方法,当对象在内存中被释放时,自动触发执行。
注:此方法一般无须定义,因为 Python 是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给 Python 解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。
__new__
在 Python 中,__new__
是一个控制对象创建过程的魔术方法,它比 __init__
更早执行。
- 优先级:
__new__
是对象创建的第一步,负责生成实例;__init__
是第二步,负责初始化实例。 - 返回值:
__new__
必须返回实例对象(否则__init__
不会执行),而__init__
无返回值。 - 静态方法:
__new__
隐式作为静态方法存在,第一个参数是类本身cls
,而非实例self
- 继承链:若未重写
__new__
,Python 会沿继承链调用父类的__new__
,直至object.__new__
class A:
def __new__(cls, *args, **kwargs):
print("in new function")
return object.__new__(A, *args, **kwargs) # 调用父类的 __new__ 创建实例并返回实例
def __init__(self):
self.x = 1
print("in init function")
a = A()
print(a.x)