Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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__..

like image 342
pospolitaki Avatar asked Aug 12 '20 10:08

pospolitaki


People also ask

What is __ MRO __ in Python?

The Method Resolution Order (MRO) is the set of rules that construct the linearization. In the Python literature, the idiom "the MRO of C" is also used as a synonymous for the linearization of the class C.

How do I get the attribute of a class in Python?

Attributes of a class can also be accessed using the following built-in methods and functions : getattr() – This function is used to access the attribute of object. hasattr() – This function is used to check if an attribute exist or not. setattr() – This function is used to set an attribute.

What is the __ dict __ attribute of an object in Python?

All objects in Python have an attribute __dict__, which is a dictionary object containing all attributes defined for that object itself. The mapping of attributes with its values is done to generate a dictionary.

What is MRO in OOP concept of Python write a codes to demonstrate the concepts both )?

Method Resolution Order(MRO) it denotes the way a programming language resolves a method or attribute. Python supports classes inheriting from other classes. The class being inherited is called the Parent or Superclass, while the class that inherits is called the Child or Subclass.


1 Answers

The __mro__ "attribute" is a data descriptor, similar to property. 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
like image 176
MisterMiyagi Avatar answered Oct 18 '22 07:10

MisterMiyagi