You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 09:10:19