如何从 __get__ 中获取描述符的属性名称?
How to get attribute name of a descriptor from within __get__?
实现描述符时,可以使用__set_name__
注册描述符设置在哪个属性名下。
虽然,假设我们要为同一个描述符设置多个属性,那么似乎没有办法知道在 __get__
和 __set__
中通过哪个名称访问描述符方法。
代码
class Prop:
def __init__(self):
self._names = {}
def __set_name__(self, owner, name):
print(f'Attribute \'{name}\' was set to a Prop')
if owner in self._names:
self._names[owner].append(name)
else:
self._names[owner] = [name]
def __get__(self, instance, owner):
print(f'Prop was accessed through one of those: {self._names[owner]}')
prop = Prop()
class Foo:
bar = prop
baz = prop
foo = Foo()
foo.baz
输出
Attribute 'bar' was set to a Prop
Attribute 'baz' was set to a Prop
Prop was accessed through one of those: ['bar', 'baz']
是否有一种清晰通用的方法来了解从哪个属性访问了描述符?
Is there a clean and general way to know from which attribute a descriptor was accessed?
不,没有干净通用的方法。
然而,如果你想要一个肮脏的 hack(请不要那样做!)你可以避免描述符协议并只传递手动访问它的名称:
class Descriptor:
def __get__(self, instance, owner, name=None):
print(f"Property was accessed through {name}")
return 'foo'
p = Descriptor()
class Test:
a = p
b = p
def __getattribute__(self, name):
for klass in type(self).__mro__:
if name in klass.__dict__ and isinstance(klass.__dict__[name], Descriptor):
return klass.__dict__[name].__get__(self, klass, name)
else:
return object.__getattribute__(self, name)
实现描述符时,可以使用__set_name__
注册描述符设置在哪个属性名下。
虽然,假设我们要为同一个描述符设置多个属性,那么似乎没有办法知道在 __get__
和 __set__
中通过哪个名称访问描述符方法。
代码
class Prop:
def __init__(self):
self._names = {}
def __set_name__(self, owner, name):
print(f'Attribute \'{name}\' was set to a Prop')
if owner in self._names:
self._names[owner].append(name)
else:
self._names[owner] = [name]
def __get__(self, instance, owner):
print(f'Prop was accessed through one of those: {self._names[owner]}')
prop = Prop()
class Foo:
bar = prop
baz = prop
foo = Foo()
foo.baz
输出
Attribute 'bar' was set to a Prop
Attribute 'baz' was set to a Prop
Prop was accessed through one of those: ['bar', 'baz']
是否有一种清晰通用的方法来了解从哪个属性访问了描述符?
Is there a clean and general way to know from which attribute a descriptor was accessed?
不,没有干净通用的方法。
然而,如果你想要一个肮脏的 hack(请不要那样做!)你可以避免描述符协议并只传递手动访问它的名称:
class Descriptor:
def __get__(self, instance, owner, name=None):
print(f"Property was accessed through {name}")
return 'foo'
p = Descriptor()
class Test:
a = p
b = p
def __getattribute__(self, name):
for klass in type(self).__mro__:
if name in klass.__dict__ and isinstance(klass.__dict__[name], Descriptor):
return klass.__dict__[name].__get__(self, klass, name)
else:
return object.__getattribute__(self, name)