在 Python 中禁用描述符对象
Disable descriptor object in Python
这是 descriptor 在 Python 中用法的简单示例:
class MyDescriptor(object):
def __get__(self, obj, objtype):
return 42
class MyClass(object):
d = MyDescriptor()
print MyClass().d # 42
但是如果我希望描述符对象成为 class 的 actual 属性怎么办,那么 MyClass().d
将是 MyDescriptor
实例, 不是 42.
有很多方法可以得到你想要的,这取决于你到底想要什么。
如果您只想访问描述符对象(即,您不关心它是否实际上作为属性直接存储在 class 上),那么只需将其存储在列表或其他内容中:
class Foo(object):
descriptor = [MyDescriptor()]
这将需要额外的间接级别来访问它,但在实践中,这可能比替代方案更简单。
如 the documentation 中所述,描述符是通过 object.__getattribute__
激活的。所以如果你真的想让它成为一个属性,你可以在包含描述符(MyClass
)的class上覆盖__getattribute__
,从而阻止描述符机制生效:
class MyClass(object):
d = MyDescriptor()
def __getattribute__(self, attr):
if attr=='d':
return self.__class__.__dict__['d']
else:
return super(MyClass, self).__getattribute__(attr)
>>> MyClass().d
<__main__.MyDescriptor object at 0x0000000002843E80>
getattr_static() does not resolve descriptors, for example slot
descriptors or getset descriptors on objects implemented in C. The
descriptor object is returned instead of the underlying attribute.
>>> import inspect
>>> inspect.getattr_static(MyClass, 'd')
<__main__.MyDescriptor object at 0x105678c18>
>>> inspect.getattr_static(MyClass(),"d")
<__main__.MyDescriptor object at 0x105678c18>
如果您想将此设置为实例的默认行为,您可以将 __getattribute__
重写为 getattr_static
:
class MyClass(object):
from inspect import getattr_static as __getattribute__
d = MyDescriptor()
>>> MyClass().d
<__main__.MyDescriptor object at 0x105678c18>
坦率地说,我不明白你为什么想要这个,将描述符存储在不调用描述符的数据结构中更有意义 dict
:
descriptors = {"d": MyDescriptor()}
然后您可以查找 descriptors["d"]
而无需调用描述符的风险。
我最简单的想法是将这个描述符包装到另一个描述符中。它会起作用,因为只会调用一个 __get__
。
class TrivialDescriptor(object):
def __init__(self, data):
self._data = data
def __get__(self, obj, objtype):
return self._data
class MyDescriptor(object):
def __get__(self, obj, objtype):
return 42
class MyClass(object):
d = TrivialDescriptor(MyDescriptor())
这是 descriptor 在 Python 中用法的简单示例:
class MyDescriptor(object):
def __get__(self, obj, objtype):
return 42
class MyClass(object):
d = MyDescriptor()
print MyClass().d # 42
但是如果我希望描述符对象成为 class 的 actual 属性怎么办,那么 MyClass().d
将是 MyDescriptor
实例, 不是 42.
有很多方法可以得到你想要的,这取决于你到底想要什么。
如果您只想访问描述符对象(即,您不关心它是否实际上作为属性直接存储在 class 上),那么只需将其存储在列表或其他内容中:
class Foo(object):
descriptor = [MyDescriptor()]
这将需要额外的间接级别来访问它,但在实践中,这可能比替代方案更简单。
如 the documentation 中所述,描述符是通过 object.__getattribute__
激活的。所以如果你真的想让它成为一个属性,你可以在包含描述符(MyClass
)的class上覆盖__getattribute__
,从而阻止描述符机制生效:
class MyClass(object):
d = MyDescriptor()
def __getattribute__(self, attr):
if attr=='d':
return self.__class__.__dict__['d']
else:
return super(MyClass, self).__getattribute__(attr)
>>> MyClass().d
<__main__.MyDescriptor object at 0x0000000002843E80>
getattr_static() does not resolve descriptors, for example slot descriptors or getset descriptors on objects implemented in C. The descriptor object is returned instead of the underlying attribute.
>>> import inspect
>>> inspect.getattr_static(MyClass, 'd')
<__main__.MyDescriptor object at 0x105678c18>
>>> inspect.getattr_static(MyClass(),"d")
<__main__.MyDescriptor object at 0x105678c18>
如果您想将此设置为实例的默认行为,您可以将 __getattribute__
重写为 getattr_static
:
class MyClass(object):
from inspect import getattr_static as __getattribute__
d = MyDescriptor()
>>> MyClass().d
<__main__.MyDescriptor object at 0x105678c18>
坦率地说,我不明白你为什么想要这个,将描述符存储在不调用描述符的数据结构中更有意义 dict
:
descriptors = {"d": MyDescriptor()}
然后您可以查找 descriptors["d"]
而无需调用描述符的风险。
我最简单的想法是将这个描述符包装到另一个描述符中。它会起作用,因为只会调用一个 __get__
。
class TrivialDescriptor(object):
def __init__(self, data):
self._data = data
def __get__(self, obj, objtype):
return self._data
class MyDescriptor(object):
def __get__(self, obj, objtype):
return 42
class MyClass(object):
d = TrivialDescriptor(MyDescriptor())