【问题标题】:__dict__ Attribute of Ultimate Base Class, object in Python__dict__ Ultimate Base Class 的属性,Python 中的对象
【发布时间】:2020-10-24 14:21:41
【问题描述】:

以下代码按排序顺序列出了名为“A”的类的属性:-

>>> class A():
        def __init__(self, i):
            self.at = i

>>> sorted(vars(A))
['__dict__', '__doc__', '__init__', '__module__', '__weakref__']

现在,打印键的值 '__dict__' 会产生以下结果:-

>>> vars(A)['__dict__']                 #Value of '__dict__'
<attribute '__dict__' of 'A' objects>

根据文档,vars([object])

为具有__dict__ 属性的模块、类、实例或任何其他对象返回__dict__ 属性。


我不明白的是列表中的'__dict__' 属性是vars() 用来返回A 的属性的相同属性 还是不同属性,它有一些其他目标,例如按照'__dict__' 持有的值建议(根据我) 实现A 的对象的命名空间


编辑:-

问题的第一部分与other question 非常相关(@eliotness 也提到了),但第二部分(如下所述)我找不到任何答案或相关问题,因此,更改问题的标题。


让我们考虑另一个在 Python 中生成最终基类属性列表的代码,object:-

>>> sorted(vars(object))
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', ...., '__str__', '__subclasshook__']
>>> hasattr(object, '__dict__')
True
>>> sorted(getattr(object, '__dict__')) == sorted(vars(object))
True

另一个关于object.__dict__的文档引用

用于存储对象(可写)属性的字典或其他映射对象。


这一次,'__dict__' 没有出现在object 的列表中。那么,__dict__ 属性是否是 只读 属性以防object 或任何其他原因?

另外,是否有可能以任何方式在 Python 中获取 只读属性列表


【问题讨论】:

    标签: python dictionary magic-methods


    【解决方案1】:

    linked answer 已经回答了您问题的第一部分:实例的__dict__ 存储为类上的descriptor。这是A.__dict__['__dict__']。另一方面,A.__dict__ 存储了A 类的所有属性——它本身就是type 的一个实例。所以实际上是 type.__dict__['__dict__'] 提供了这些变量:

    >>> type.__dict__['__dict__']
    <attribute '__dict__' of 'type' objects>
    >>> A.__dict__ == type.__dict__['__dict__'].__get__(A)
    True
    

    object 上看不到__dict__ 属性的原因是它没有。这意味着您不能在 object 实例上设置实例变量:

    >>> o = object()
    >>> o.x = 1
    
    AttributeError: 'object' object has no attribute 'x'
    

    通过定义__slots__,自定义类可以实现类似的行为:

    >>> class B:
    ...     __slots__ = ()
    ... 
    >>> vars(B)
    mappingproxy({'__module__': '__main__', '__slots__': (), '__doc__': None})
    >>> 
    >>> b = B()
    >>> b.x = 1
    
    AttributeError: 'B' object has no attribute 'x'
    

    【讨论】:

    • 我认为我不能同意这一点,即“您没有在对象上看到 __dict__ 属性的原因是因为它没有属性”,因为在这种情况下,@ 987654338@ 将返回 False 但相反,它返回 True ,因此,vars(object) 返回一个 mappingproxy 类型的字典“它可以防止直接字典更新”(如文档中所述)。我强烈认为object__dict__ 是一个只读属性,因此,没有实例变量可以设置为object 实例,也不会出现在vars(object) 中.
    • @Perspicacious 我的意思是object 没有__dict__ 描述符(类似于A.__dict__['__dict__'])。当然对象object 有自己的__dict__,类似于A.__dict__。它们都源自提供相应描述符的typeobject.__dict__ 确实是只读的,因为它是一个映射代理,但这适用于 type 的任何实例。但是,您不能在object 实例上设置实例变量的原因实际上是因为它们没有__dict__。请尝试以下操作:o = object(); o.__dict__。你会得到一个 AttributeError。
    • (只是为了确认)这样说,“它们都来自提供相应描述符的type。”你指的是这个type.__dict__['__dict__']??另外,正如我在问题中所问的那样,有没有办法查看只读属性列表,因为__dict__ 只显示对象的可写属性。
    • @Perspicacious 我指的是A.__dict__object.__dict__。两者都是type 的实例,因此__dict__ 属性来自描述符type.__dict__['__dict__']。关于object.__dict__,文档的意思是这是保存可写属性的地方——尽管并非所有可写属性都必须出现在那里。您可以在类上定义一个属性,它不会出现在__dict__ 中。只读属性始终是类的描述符,因此它们永远不会出现在__dict__ 中。您可以查看dir(obj),然后查看那里有什么可用的。
    • dir(obj) 虽然考虑了对象的基础属性。
    【解决方案2】:

    首先我想说我只知道部分答案。关于 python 的行为,第二部分可能并不完全正确。但首先,我想澄清一些事情:您引用的文档涉及普通对象,可能不适用于元类,因为它们的内部行为完全用 C 编码。

    vars(A)['dict']

    据我了解 python 是如何工作的,我怀疑你在这里看到的__dict__

    >>> vars(A)['__dict__']                 #Value of '__dict__'
    <attribute '__dict__' of 'A' objects>
    

    我怀疑它是该类未来实例的__dict__ 属性的示例。我目前没有更好的答案,但让我们继续挖掘。

    元类的__dict__ 属性

    由于object 属于type 类,所以没有__dict__ 是很正常的,因为无法在int、float 或str 等基本类型上添加属性。那么,如果不使用这些类型,为什么会有__dict__ 属性呢?

    最后,是的。类和元类的__dict__ 属性存在限制。这些限制的形式就像 vars documentation 中所说的 MappingProxy 类:

    模块和实例等对象具有可更新的__dict__ 属性;但是,其他对象可能对其__dict__ 属性有写入限制(例如,类使用 types.MappingProxyType 来防止直接字典更新)。

    但这种行为在doc of the class object中也有明确说明

    编辑:我开始找到关于怪异vars(A)['__dict__'] 的好信息。看看here

    【讨论】:

    • @eliotness,在查看了你最后给出的链接之后,'__dict__' 似乎是一个不同的属性,将用于类的实例。但是在阅读文档中关于object 基类的内容后,它末尾给出的注释让我有点困惑。 > 注意:对象没有__dict__,所以不能为对象类的实例分配任意属性。
    • Continuing....我的意思是代码hasattr(object, '__dict__') 返回True(我也写在问题中)。此外,vars(object) 工作正常。那么“object 没有__dict__ 属性”这句话的准确率是多少?
    • @Perspicacious,我们确定的一件事是 object 类的文档是模棱两可的,因此我们不知道他们是在谈论 object 的实例还是类本身.关于object类的__dict__属性,可能与类的描述符有关。我正在检查我是否在我的书中找到了一些东西,但我担心我们将不得不在 CPython 中寻找 object 类的 __call____new__ 的基本实现。
    • @eliotness,我认为关于object 的文档是关于object 本身的类而不是关于它的实例,但即使它是关于object 本身的实例(Python 中的每个对象是),这对我来说似乎不准确。
    • 此时,我认为人们可以使用每种标准方式查看__dict__ attr 的object,否则,用于访问任何其他正常的__dict__目的。只是它是一个 read-only 属性(我的意思是像类对象一样,打印它的 __dict__ 也给出了一个 mappingproxy 对象),直到现在,我找不到一种方法来获得对象的只读属性列表.
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-06-20
    • 2011-11-21
    • 2019-12-02
    • 1970-01-01
    • 1970-01-01
    • 2017-12-20
    相关资源
    最近更新 更多