不确定这是否可行。 下面的实现/示例是虚拟的,仅供参考。
我有一个Python 类,Person。每个人都有一个公共名字和一个公共姓氏属性以及相应的私有属性 - 我正在使用描述符模式来管理对底层私有属性的访问。
我使用描述符来计算属性被访问的次数并获取底层结果。
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
从类 Person 的实例中,如何访问
_access_count
或属性 counter
?
john = Person('John','Smith')
print(john.first) # 'John'
print(john.first.counter) # AttributeError: 'str' object has no attribute 'counter'
正如您在这里看到的:
https://docs.python.org/3/howto/descriptor.html#customized-names
可以选择使用
print(vars(Person)['first']._access_count)
这将为您提供底层对象,而不会触发 get
注意我们在对象的类上调用变量
无法通过
john.first.counter
直接访问,因为描述符 __get__
将返回 str
及其完成方式。 有一种方法可以解决这个问题,可以按照this answer修改方法。
def __get__(self, instance, owner):
if instance is None:
return self
self._access_count += 1
return getattr(instance, self.attrib_name)
计数器的值可以根据问题通过
type(john).first.counter
或 Person.first.counter
检索。 请注意,在此实现中,属性访问的计数器在底层对象的所有实例之间共享,因为计数器存储在描述符对象本身上:
john = Person('John','Smith')
mary = Person('Mary','Jane')
print(john.first)
print(mary.first)
print(type(john).first.counter)
print(type(mary).first.counter)
上面现在将输出以下内容:John
Mary
2
2
如果您希望每个实例都有单独的计数器,则相关计数器也需要存储到实例上,如果两者都需要,可能是这样的:
class AttributeAccessCounter:
def __init__(self):
self._access_count = 0
def __get__(self, instance, owner):
if instance is None:
return self
self._access_count += 1
setattr(
instance,
f'{self.attrib_name}_counter',
getattr(instance, f'{self.attrib_name}_counter', 0) + 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
def count(self, instance):
return getattr(instance, f'{self.attrib_name}_counter', 0)
有了这个新的测试程序:
john = Person('John','Smith')
mary = Person('Mary','Jane')
print(john.first)
print(mary.first)
print(mary.first)
print(Person.first.counter)
print(Person.first.count(john))
print(Person.first.count(mary))
生成以下输出:
John
Mary
Mary
3
1
2