【问题标题】:The __getattribute__ method and descriptors__getattribute__ 方法和描述符
【发布时间】:2014-09-11 21:08:42
【问题描述】:

根据本指南关于 python 描述符 https://docs.python.org/howto/descriptor.html

新样式类中的方法对象是使用描述符实现的,以避免在属性查找中对它们进行特殊封装。

我的理解是有一种方法对象类型实现__get__,并在使用实例调用时返回绑定的方法对象,在没有实例且仅使用类调用时返回未绑定的方法对象。文章还指出,这个逻辑是在object.__getattribute__ 方法中实现的。像这样:

def __getattribute__(self, key):
    "Emulate type_getattro() in Objects/typeobject.c"
    v = object.__getattribute__(self, key)
    if hasattr(v, '__get__'):
       return v.__get__(None, self)
    return v

然而object.__getattribute__ 本身就是一种方法!那么它如何绑定到一个对象(没有无限递归)?如果它在属性查找中是特殊大小写的,这不会破坏删除旧样式特殊大小写的目的吗?

【问题讨论】:

标签: python attributes python-internals


【解决方案1】:

实际上,在 CPython 中默认的 __getattribute__ 实现不是 Python 方法,而是在 C 中实现。它可以直接访问对象槽(C 结构中表示 Python 对象的条目),无需费心通过讨厌的属性访问例程。

仅仅因为您的 Python 代码必须这样做,并不意味着 C 代码必须这样做。 :-)

如果您确实实现了 Python __getattribute__ 方法,只需使用 object.__getattribute__(self, attrname),或者更好的是 super().__getattribute__(attrname) 来访问 self 上的属性。这样你也不会遇到递归。

在 CPython 实现中,属性访问实际上由 C 类型对象中的 tp_getattro slot 处理,并回退到 tp_getattr slot

为了详尽并充分展示 C 代码的功能,当您对 实例 使用属性访问时,以下是调用的完整函数集:

当您访问类本身的属性时,而不是_PyObject_GenericGetAttrWithDicttype->tp_getattro 插槽由type_getattro() function 提供服务,这也考虑了元类。此版本也调用__get__,但将实例参数设置为None

此代码无需递归调用__getattribute__ 即可访问__dict__ 属性,因为它可以直接访问C 结构。

【讨论】:

  • 我不认为我完全理解。你的意思是说 __getattribute__ 不被视为对象的方法,而不是作为常规方法查找?那么谁将它从函数转换为方法呢?
  • @user3848844: object.__getattribute__() 是对内置类object 的未绑定方法的调用,所以不,它不是通过您所谓的常规方法查找的。​​span >
  • @user3848844:我已对其进行了重新设计以使其更准确。 __getattribute__ 未实现为 Python 代码。它是一个 C 函数(C 中没有方法,C 不是面向对象的)。 CPython 解释器用 C 编码,调用其他 C 函数。
  • 旁注:虽然hg.python.org 链接仍然有效,但我想知道是否应该更新它以使用 github CPython。 (但这是很多工作......)
  • @torek:fate of hg.python.org 仍然是一个悬而未决的问题。目前,它将继续存在。我根据需要更新答案以指向 github 视图(通常当我遇到使用旧链接并收到 cmets 或投票的答案时)。
猜你喜欢
  • 2014-05-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-10
  • 1970-01-01
相关资源
最近更新 更多