A
Amirouche B.
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/pytho...tes_and_methods.html#attribute-search-summary
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/pytho...tes_and_methods.html#attribute-search-summary