简体   繁体   中英

Where does the `__mro__` attribute of a Python's class come from?

Let's say there is some class:

class Test():
    pass 

(1) Somewhere on SO and in documentation i read next:

mro() called at class instantiation, and its result is stored in __mro__ .

Okay, that is still clear to me, cause in __mro__ something is really stored:

Test.__mro__                                                         
Out[48]: (__main__.Test, object)

Again, somewhere i read this:

To look up an attribute name Python searches:
a)Search the __dict__ of all metaclasses on the __mro__ found at C's __class__ .
b)If a data descriptor was found in step a, call its __get__() and exit.
c)Else, call a descriptor or return a value in the __dict__ of a class on C's own __mro__ .
d)Call a non-data descriptor found in step a.
e)Else, return Metaclass-tree values

I can find out that there is no __mro__ in Test.__dict__ :

'__mro__' in Test.__dict__                                           
Out[49]: False

So accordingly to e clause from previous quote i guess that __mro__ should be taken from "Metaclass-tree values" and hence from type.__dict__

Really, there is __mro__ in type.__dict__ :

["mro:<method 'mro' of 'type' objects>",
"__mro__:<member '__mro__' of 'type' objects>"]
  1. So what was mentioned above in (1) about mro() result stored in __mro__ attribute from documentation doesn't really works this way?

  2. How does <member '__mro__' of 'type' objects> results to (__main__.Test, object) ?

Maybe you could show some source code to understand what really happens when i call Test.__mro__ ..

The __mro__ "attribute" is a data descriptor , similar toproperty . Instead of fetching the __mro__ attribute value from __dict__ , the descriptor fetches the value from another place or computes it. In specific, a <member '...' of '..' objects> indicates a descriptor that fetches the value from an VM-internal location – this is the same mechanism used by __slots__ .

>>> class Bar:
...     __slots__ = "foo",
...
>>> Bar.foo
<member 'foo' of 'Bar' objects>
>>> 'foo' in Bar.__dict__
True

Descriptors are inherited without duplication, and thus do not appear explicitly on subclasses.

>>> class Foo(Bar):
...     __slots__ = ()
...
>>> Foo.foo
<member 'foo' of 'Bar' objects>
>>> 'foo' in Foo.__dict__
False

The precise working of such a member data descriptor is implementation defined. However, logically they work the same as a property using an internal storage:

class FooBar:
    def __init__(self, foo, bar):
        # attributes stored internally
        # the "_data" of a member is not visible
        self._data = [foo, bar]

    @property
    def foo(self):
        return self._data[0]

    @foo.setter
    def foo(self, value):
        self._data[0] = value

    @property
    def bar(self):
        return self._data[1]

    @bar.setter
    def bar(self, value):
        self._data[1] = value

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM