I'm learning a bit of python internals lately and I'm trying to figure out the relationship between type, objects, class, callables and __getattribute__ resolution.
While understanding Python mechanics/concepts, I'm trying to figure how it translates in CPython. This post is Python centric. Questions about the implementation of this concepts might be the subject of a future post [1]. I will proceed this way: I will write statements about each subject. Don't hesitate to pick one and provide more information or better phrasing, or explaining why it's not true. Be aware that I'm considering only new-style class. A) type vs object ----------------- 1) object is the base object, it has no bases : len(object.__bases__) == 0 2) every object in python inherit object : any_object_except_object.__bases__[-1] is object 3) object's type is type : object.__class__ is type 4) type parent object is object : type.__bases__ == (object,) B) type vs metaclass -------------------- 1) type is the first metaclass ? 2) type is its own metaclass : type(type) is type ? 3) object's metaclass is type ? 4) other metaclasses *MUST* inherit type ? 5) type(any_object) == last_metaclass_..., which is, most of the time, type ? C) type vs class ---------------- 1) Type is the metaclass of most classes 2) The class statement:: class MyClass(object): attribute = 1 def method(self): pass translates to:: MyClass = type('MyClass', (object,), {'attribute': 1, 'method': def method: pass }) 3) Instantiation of any class ``MyClass(*args, **kwargs)`` translates to:: type(MyClass).__call__(MyClass, *args, **kwargs) This is due to __getattribute__ algorithm (see E) 4) It's in type.__call__ that happens calls to __new__ and __init__ 5) 3) => classes are instance of type 6) Since type.__call__ is used to instantiate instance of instance of type (rephrased: __call__ is used to instantiate classes) where is the code which is executed when we write ``type(myobject)`` or ``type('MyClass', bases, attributes)`` __getattribute__ resolution algorithm (see E) tells me that it should be type.__call__ but type.__call__ is already used to class instatiation. C') class vs class instances aka. objects ----------------------------------------- 1) A class type is a metaclass : issubclass(type(MyClass), type), MyClass.__class__ == type(MyClass) 2) An object type is a class : most of the time isinstance(type(my_object), type) generally issubclass(type(type(my_object)), type) D) builtin types ---------------- 1) builtin types are their own metaclass ? 2) why function builtin type can not be subclassed ? 3) how does builtin function type relate to callable objects ? 4) int(1) is the same as int.__call__(1), since type(int) is type, shouldn't int(1) translates to type.__call__(int, 1) ? E) __getattribute__ ------------------- 1) ``my_object.attribute`` always translates to ``my_object.__getattribute__('attribute')`` 2) Is the following algorithm describing __getattribute__ correct [2], beware that I've added a comment: a) If attrname is a special (i.e. Python-provided) attribute for objectname, return it. # what does it mean to be Python-provided ? b ) Check objectname.__class__.__dict__ for attrname. If it exists and is a data-descriptor, return the descriptor result. Search all bases of objectname.__class__ for the same case. c) Check objectname.__dict__ for attrname, and return if found. d) If it is a class and a descriptor exists in it or its bases, return the descriptor result. d) Check objectname.__class__.__dict__ for attrname. If it exists and is a non-data descriptor, return the descriptor result. If it exists, and is not a descriptor, just return it. If it exists and is a data descriptor, we shouldn't be here because we would have returned at point 2. Search all bases of objectname.__class__ for same case. e) Raise AttributeError Thanks in advance, Regards, Amirouche [1] or maybe you can point me to the right direction before I ask stupid questions. I'm a bit familiar with Jython code, which seems to be easier than PyPy and CPython to read even if there is some magic due to the fact that Jython use some JVM API that hides somewhat how it works. [2] this is a rewritten version of http://www.cafepy.com/article/python_attributes_and_methods/python_attributes_and_methods.html#attribute-search-summary -- http://mail.python.org/mailman/listinfo/python-list