使用点符号访问MyClass.my_attribute时调用何方法?如何实现访问提示?
问题解答
为啥之前的代码没效果?
你写的__getattr__和__getattribute__是实例专属方法,只有访问类的实例对象属性时才会触发。但你是直接访问类本身的属性,类其实是元类(默认是type)的实例,这时候只会调用元类的属性访问逻辑,跟你在类里定义的那俩方法没关系。
访问类属性时到底调用啥方法?
直接访问MyClass.my_attribute这类类属性时,会调用该类元类的__getattribute__方法(默认元类是type,所以调用的是type.__getattribute__)。要是访问的属性不存在,才会触发元类的__getattr__(不过默认type没实现这个方法,所以直接报错)。
实现需求的两种实用方法
方法1:自定义元类(通用型)
自己写个元类,重写它的__getattribute__方法,就能在访问任何类属性时添加打印逻辑:
class MyMeta(type): def __getattribute__(cls, name): # 跳过特殊属性(比如__class__、__name__),防止无限递归 if not name.startswith('__'): print(f"getting {name} attr") return super().__getattribute__(name) class MyClass(metaclass=MyMeta): my_attribute = "abc" print(MyClass.my_attribute)
运行输出:
getting my_attribute attr abc
方法2:类装饰器(针对特定属性)
如果只需要给部分类属性加提示,用类装饰器结合property也能实现:
def track_class_attrs(cls): # 遍历类里的非特殊属性 for attr_name, attr_val in list(cls.__dict__.items()): if not attr_name.startswith('__'): # 包装属性获取逻辑 def wrapper(name=attr_name): print(f"getting {name} attr") return cls.__dict__[name] # 把原属性换成property setattr(cls, attr_name, property(wrapper)) return cls @track_class_attrs class MyClass: my_attribute = "abc" print(MyClass.my_attribute)
运行输出:
getting my_attribute attr abc
注意:方法2里用了property,之后要是修改类属性的值,得重新设置property才会继续触发打印;而元类的方法更灵活,哪怕后续动态添加类属性也能生效。
内容的提问来源于stack exchange,提问作者Benjamin_Mourgues
相关产品推荐
相关产品推荐

