没有任何描述符魔法的 python 属性查找?

标签 python python-datamodel descriptor

我已经开始在我编写的代码中更广泛地使用 python 描述符协议(protocol)。通常,默认的 python 查找魔术是我想要发生的事情,但有时我发现我想获取描述符对象本身而不是其 __get__ 方法的结果。想知道描述符的类型,或存储在描述符中的访问状态,或类似的东西。

我编写了下面的代码,以我认为正确的顺序遍历 namespace ,并返回原始属性,无论它是否是描述符。尽管我在标准库中找不到内置函数或其他东西来执行此操作,但我感到很惊讶——我认为它必须存在,但我只是没有注意到它或用谷歌搜索正确的搜索词。

在 python 发行版中的某处是否有功能已经做到了这一点(或类似的东西)?

谢谢!

from inspect import isdatadescriptor

def namespaces(obj):
    obj_dict = None
    if hasattr(obj, '__dict__'):
        obj_dict = object.__getattribute__(obj, '__dict__')

    obj_class = type(obj)
    return obj_dict, [t.__dict__ for t in obj_class.__mro__]

def getattr_raw(obj, name):
    # get an attribute in the same resolution order one would normally,
    # but do not call __get__ on the attribute even if it has one
    obj_dict, class_dicts = namespaces(obj)

    # look for a data descriptor in class hierarchy; it takes priority over
    # the obj's dict if it exists
    for d in class_dicts:
        if name in d and isdatadescriptor(d[name]):
            return d[name]

    # look for the attribute in the object's dictionary
    if obj_dict and name in obj_dict:
        return obj_dict[name]

    # look for the attribute anywhere in the class hierarchy
    for d in class_dicts:
        if name in d:
            return d[name]

    raise AttributeError

编辑 2009 年 10 月 28 日,星期三。

Denis 的回答给了我一个在我的描述符类中使用的约定来获取描述符对象本身。但是,我有一个完整的描述符类层次结构,我不想开始每个 __get__ 函数的样板

def __get__(self, instance, instance_type):
    if instance is None: 
        return self
    ...

为了避免这种情况,我使描述符类树的根继承自以下内容:

def decorate_get(original_get):
    def decorated_get(self, instance, instance_type):
        if instance is None:
            return self
        return original_get(self, instance, instance_type)
    return decorated_get

class InstanceOnlyDescriptor(object):
    """All __get__ functions are automatically wrapped with a decorator which
    causes them to only be applied to instances. If __get__ is called on a 
    class, the decorator returns the descriptor itself, and the decorated
    __get__ is not called.
    """
    class __metaclass__(type):
        def __new__(cls, name, bases, attrs):
            if '__get__' in attrs:
                attrs['__get__'] = decorate_get(attrs['__get__'])
            return type.__new__(cls, name, bases, attrs)

最佳答案

大多数描述符只在作为实例属性访问时完成它们的工作。所以类访问的时候返回自己很方便:

class FixedValueProperty(object):
    def __init__(self, value):
        self.value = value
    def __get__(self, inst, cls):
        if inst is None:
            return self
        return self.value

这允许您获取描述符本身:

>>> class C(object):
...     prop = FixedValueProperty('abc')
... 
>>> o = C()
>>> o.prop
'abc'
>>> C.prop
<__main__.FixedValueProperty object at 0xb7eb290c>
>>> C.prop.value
'abc'
>>> type(o).prop.value
'abc'

请注意,这也适用于(大多数?)内置描述符:

>>> class C(object):
...     @property
...     def prop(self):
...         return 'abc'
... 
>>> C.prop
<property object at 0xb7eb0b6c>
>>> C.prop.fget
<function prop at 0xb7ea36f4>

当您需要在子类中扩展它时,访问描述符可能很有用,但是有一个 better way做这个。

关于没有任何描述符魔法的 python 属性查找?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1628137/

相关文章:

python - 显示所有 jinja 对象属性

python - 动态导入 Python 模块

python - 检查 python 字典是否包含值,如果是则返回相关值

python - 计算 python 中列表值的 95 个百分点

sql - 如何查看数据库对象定义的注释?

c++ - OpenCV HOGDescriptor 返回值

python - 充当无限序列的对象的 __len__ 的正确返回值

python - 如何通过类访问类本身的weakref对象?

Python 反射和类型转换

python - 向类添加装饰函数