元类级变量是否像类级变量那样级联到元类的实例化类的实例化对象?

问题描述 投票:0回答:1

我一直在深入查阅 Python 文档中的描述符,但我无法理解其中关于描述符调用和给定 Python 等价于

object.__getattribute__()
.

的一些要点

给出的纯 Python 等价物(请参见下面代码中的“object_getattribute”)假定通过调用 __getattribute__() 调用

getattr()
type
版本,其中类对象作为第一个参数提供,这导致调用 type
__getattribute__()
。问题是,让 type 的属性查找(在
type.__getattribute__()
中实现)参与实例调用的查找应该会把事情搞砸,因为它会桥接到不同的关系线,其中类是对象,元类是类.当类的
MRO
耗尽时,由 object.__getattribute__() 进行的查找搜索应该终止(此时将使用 getattr()),但是调用
__getattribute__()
type 将不合逻辑地级联搜索到覆盖元类的 dict 并可能取回一个类似名称的属性,这是错误的,因为元类定义的是类,而不是对象。 下面是一个创建名为“mytype”的元类的示例,一个名为“base”的基类使用 Python 等效项提供于:https://docs.python.org/3/howto/descriptor.html#technical-tutorial ,和一个实例类,“myclass”,来自“mytype”:

class mytype(type):
    cls_var = 11

class base:
    def object_getattribute(obj, name):
        null = object()
        objtype = type(obj)
        cls_var = getattr(objtype, name, null)
        descr_get = getattr(type(cls_var), '__get__', null)
        if descr_get is not null:
            if (hasattr(type(cls_var), '__set__') or hasattr(type(cls_var), '__delete__')):
                return descr_get(cls_var, obj, objtype)
        if hasattr(obj, '__dict__') and name in vars(obj):
            return vars(obj [name]
        if descr_get is not null:
            return descr_get(cls_var, obj, objtype)
        if cls_var is not null:
            return cls_var
        raise AttributeError(name)
    
    def __init__(s, v):
        s.core = v

    @property
    def core(s):
        return '-- ' + s._core + ' --'

    @core.setter
    def core(s, v):
        s._core = v

myclass = mytype('myclass', (base, ), {'a':97})

o = myclass('IRON')

(注意:我不知道如何在创建类时将方法定义添加到类中,抛出调用 typenew(),所以我想出了类“base”作为提供“object_getattribute”的方法()”文档中的方法)

现在,如果我跑:

print(o.__getattribute__('cls_var'))

或者,更简单地说:

print(o.cls_var

我得到:

...
AttributeError: 'myclass' object has no attribute 'cls_var'

[Program finished]

结果是我通常期望的。搜索不在元类中查找以评估名称 - 这是不同的领域。但是,如果我使用文档中的纯 Python 等效项,如下所示:

print(o.object_getattribute('cls_var'))

然后我得到:

11

哪个在mytype.

总结:文档中提供的纯Python版本,错了吗?

python metaclass getattribute python-descriptors python-datamodel
1个回答
0
投票

文档中的示例不正确。

如果你现在看那里 -

https://docs.python.org/3/howto/descriptor.html#technical-tutorial
你会看到在类中获取名称,检查它是否是一个描述符,不使用
type(obj).__getattribute__
- 相反,他们写了一个辅助函数
find_name_in_mro
它准确地模拟了检索属性的机制。

当打开旧 Python 版本的相同 URL 时,例如 https://docs.python.org/3.9/howto/descriptor.html#technical-tutorial,您会注意到粘贴在问题 - 事实上,这是不正确的。

所以,换句话说,它有可能让最终的读者更清楚地了解事情: 在 Python 中检索 any 实例中的属性时,会调用该实例的

__getattribute__
。通常这将默认为
object.__getattribute__
,它的作用是:

  1. 尝试在类命名空间或任何超类中检索对象。此搜索不在类上使用
    __getattribute__
    - 它是自定义搜索,它将在类'
    __dict__
    中搜索属性,然后在其所有线性化超类的
    __dict__
    中搜索(mro - “方法决议顺序)到“对象”。
    1. 如果在类中找到该属性,则将其保存以备后用,并立即检查它是否是“数据描述符”:即在其自己的类中具有
      __set__
      __del__
      特征的对象。此查找是非递归的,并直接检查(检索到的对象的)类
      slots
      -“非数据描述符”存在这种差异,因为-描述符仅具有
      __get__
      ,因为它们可以被实例中设置的值遮蔽。数据描述符永远不会被实例中的值遮蔽。
    2. 如果存在数据描述符,则在描述符实例上调用
      __get__
      ,其返回值用作
      __getattribute__
    3. 的结果
  2. 如果该值不在类命名空间或超类中,则 Python 会搜索该类的
    __dict__
    本身。请注意,如果在类定义中使用了
    __dict__
    ,则用户定义类中的属性可以存在于其实例没有
    __slots__
    的类中。然而,
    __slots__
    中的属性访问本身是通过专门的描述符执行的——因此,Python 将使用上面的案例 1.1。
  3. 如果实例中有一个属性
    __dict__
    被返回
  4. 否则,如果存在非数据描述符,则在描述符对象中调用
    __get__
    。这种情况用于检索包装在绑定方法中的类中的函数(函数中的
    .__get__()
    方法这样做)。
  5. 作为最后一个资源,
    __getattr__
    在同一实例中被调用 - 如果已定义 - 它的返回值,或
    AttributeError
    异常被用作
    __getattribute__
  6. 的结果
  7. AttributeError
    被提出来。
© www.soinside.com 2019 - 2024. All rights reserved.