Everything in python is an object. All objects have a type. Most objects have
an instance dictionary. Types can be constructed by calling
type("name for type", (parents for type,), {instance dict for type})
.
Types have a method resolution order which is determined from their parents
using http://en.wikipedia.org/wiki/C3_linearization. All operators in python
can be overridden including the "." operator. So a.b
is really finding a
__getattribute__
in one of the types of a
and calling it. However
CPython needs an internal mechanism for finding the __getattribute__
.
This mechanism isn't exposed as a builtin but would look something like
this in python code:
def get_override(object_instance, name):
for mro_type in type(object_instance).mro():
if name in mro_type.__dict__:
return mro_type.__dict__[name]
The implementation of __getattribute__
on objects can be further customised
by descriptors and through __getattr__
. The object.__getattribute__
in
CPython looks something like:
def object_get_attribute(object_instance, name):
if name in object_instance.__dict__:
return object_instance.__dict__[name]
type_instance = type(object_instance)
for mro_type in type_instance.mro():
if name in mro_type.__dict__:
entry = mro_type.__dict__[name]
__get__ = get_override(entry, "__get__")
if __get__:
return __get__(entry, object_instance, type_instance)
else:
return entry
__getattr__ = get_override(object_instance, "__getattr__")
if __getattr__:
return __getattr__(object_instance, name)
else:
raise AttributeError()
While the type.__getattribute__
in CPython looks something like:
def type_get_attribute(type_instance):
for mro_type in type_instance.mro():
if name in mro_type.__dict__:
entry = mro_type.__dict__[name]
__get__ = get_override(entry, "__get__")
if __get__:
return __get__(entry, None, type_instance)
else:
return entry
metatype_instance = type(type_instance)
for mro_metatype in metatype_instance.mro():
if name in mro_metatype.__dict__:
entry = mro_metatype.__dict__[name]
__get__ = get_override(entry, "__get__")
if __get__:
return __get__(entry, type_instance, metatype_instance)
else:
return entry
__getattr__ = get_override(type_instance, "__getattr__")
if __getattr__:
return __getattr__(type_instance, name)
else:
raise AttributeError()
Defining a class A
:
class A(my_parent):
__metaclass__ = my_meta_class
my_class_variable = 42
def my_method(self):
pass
Is the same as:
def A():
__metaclass__ = my_meta_class
my_class_variable = 42
def my_method(self):
pass
return locals()
A = my_meta_class("A", (my_parent,), A())
Defining a decorated function:
@outer
@inner
def f():
pass
Is the same as:
def f():
pass
f = inner(f)
f = outer(f)
Operator | Overrides |
---|---|
a.name |
a.__getattribute__("name") , a.name.__get__(a, type(a)) , a.__getattr__("name") |
a.name = b |
a.__setattr__("name", b) , a.name.__set__(a, type(a), b) |
del a.name |
a.__delattr__("name") , a.name.__del__(a, type(a)) |
if a: |
a.__nonzero__ , a.__len__ |
i in a |
bool(a.__contains__(i)) |
a[i] |
a.__getitem__(i) |
a[i:j:k] |
a.__getitem__(slice(i, j, k)) |
a[i] = b |
a.__setitem__(i, b) |
del a[i] |
a.__delitem__(i) |
a + b |
a.__add__(b) , b.__radd__(a) |
a(*b,**c) |
a.__call__(*b, **c) |
with a as b: |
b = a.__enter__(), a.__exit__(*sys.exc_info()) |
for _ in a: |
b = a.__iter__(), b.__next__() |