Python描述符属性访问计数:如何从实例获取访问次数?
如何从Python实例访问描述符的访问次数统计属性?
你通过描述符模式实现了Person类属性的访问次数统计,但调用john.first.counter时触发AttributeError,原因是当你访问实例的first属性时,描述符的__get__方法返回的是实例私有属性的具体值(比如字符串'John'),而非描述符自身,自然无法访问描述符的counter属性。
原问题代码
class AttributeAccessCounter: def __init__(self): self._access_count = 0 def __get__(self, instance, owner): self._access_count += 1 return getattr(instance, self.attrib_name) def __set_name__(self, obj, name): self.attrib_name = f'_{name}' @property def counter(self): return self._access_count class Person: first = AttributeAccessCounter() last = AttributeAccessCounter() def __init__(self, first, last): self._first = first self._last = last john = Person('John','Smith') print(john.first) # 'John' print(john.first.counter) # AttributeError: 'str' object has no attribute 'counter'
解决方案
1. 直接从类层面访问描述符的统计属性
当前的描述符是类级别的共享实例,所有Person实例访问first属性都会累加同一个计数器。你可以直接通过类来访问描述符的counter属性:
john = Person('John','Smith') print(john.first) # 输出 'John',计数器+1 print(Person.first.counter) # 输出 1 john.first # 再次访问,计数器+1 print(Person.first.counter) # 输出 2
2. 修改描述符实现,支持实例级别的独立统计
如果需要每个Person实例单独统计属性访问次数,需要把计数器存储在实例自身,而非描述符实例中。修改后的代码如下:
class AttributeAccessCounter: def __set_name__(self, obj, name): self.attrib_name = f'_{name}' # 定义实例存储该属性访问次数的属性名 self.count_attr = f'_access_count_{name}' def __get__(self, instance, owner): if instance is None: return self # 从类访问时返回描述符自身 # 初始化实例的计数器(如果不存在) if not hasattr(instance, self.count_attr): setattr(instance, self.count_attr, 0) # 计数器累加 setattr(instance, self.count_attr, getattr(instance, self.count_attr) + 1) return getattr(instance, self.attrib_name) # 提供方法获取指定实例的访问次数 def get_count(self, instance): return getattr(instance, self.count_attr, 0) class Person: first = AttributeAccessCounter() last = AttributeAccessCounter() def __init__(self, first, last): self._first = first self._last = last # 可选:给类添加便捷方法,直接获取实例的属性访问次数 def get_access_count(self, attr): return getattr(type(self), attr).get_count(self)
使用示例:
john = Person('John','Smith') jane = Person('Jane','Doe') john.first # john的first计数器+1 john.first # john的first计数器+1 jane.first # jane的first计数器+1 # 通过描述符方法获取 print(Person.first.get_count(john)) # 输出 2 print(Person.first.get_count(jane)) # 输出 1 # 通过实例方法获取 print(john.get_access_count('first')) # 输出 2
内容的提问来源于stack exchange,提问作者pemm
相关产品推荐
相关产品推荐

