Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python: Metaclass properties override class attributes, sometimes?

The result of the below code boggles me:

class MyClass(type):
    @property
    def a(self):
        return 1

class MyObject(object):
    __metaclass__ = MyClass

    a = 2

print MyObject.a
print object.__getattribute__(MyObject, 'a')
print type.__getattribute__(MyObject, 'a')
print MyObject.__dict__['a']
print MyObject().a

I really expect this to just print 2 repeatedly, but it prints 1 1 1 2 2. Is there a way this makes any intuitive sense?


To clarify: I understand that this behavior is well documented (here, "data descriptors"), but I want to have an understanding of why this makes sense, and why the core devs implemented descriptors this way.

like image 521
bukzor Avatar asked Mar 23 '14 02:03

bukzor


People also ask

What is the use of metaclass in Python?

A metaclass in Python is a class of a class that defines how a class behaves. A class is itself an instance of a metaclass. A class in Python defines how the instance of the class will behave. In order to understand metaclasses well, one needs to have prior experience working with Python classes.

Are metaclasses inherited?

Every object and class in Python is either an instance of a class or an instance of a metaclass. Every class inherits from the built-in basic base class object , and every class is an instance of the metaclass type .

Does Python have metaprogramming?

The term metaprogramming refers to the potential for a program to have knowledge of or manipulate itself. Python supports a form of metaprogramming for classes called metaclasses. Metaclasses are an esoteric OOP concept, lurking behind virtually all Python code.

What is __ bases __ in Python?

Python provides a __bases__ attribute on each class that can be used to obtain a list of classes the given class inherits. The __bases__ property of the class contains a list of all the base classes that the given class inherits. The above output shows that the Human class has object as a base class.


1 Answers

Properties are data descriptors; in attribute lookups, they take priority over identically-named entries in the dict of an instance of the class with the property. That means that with

MyObject.a

the a property in MyClass takes priority over the a entry in MyObject's dict. Similarly,

object.__getattribute__(MyObject, 'a')
type.__getattribute__(MyObject, 'a')

object.__getattribute__ and type.__getattribute__ both respect the priority of data descriptors over instance dict entries, so the property wins.

On the other hand,

MyObject.__dict__['a']

this explicitly does a dict lookup. It only sees things in MyObject's dict, ignoring the normal attribute lookup mechanisms.

For the last line:

MyObject().a

the MyClass descriptor only applies to instances of MyClass, not instances of its instances. The attribute lookup mechanism doesn't see the property.

like image 98
user2357112 supports Monica Avatar answered Sep 27 '22 20:09

user2357112 supports Monica