Amirouche B. wrote: > A) type vs object > ----------------- > > 1) object is the base object, it has no bases : len(object.__bases__) > == 0
Correct, but for reference, a more direct test is: object.__bases__ == () (no need for len). > 2) every object in python inherit object : > any_object_except_object.__bases__[-1] is object Excluding old-style objects, I believe you are correct. > 3) object's type is type : object.__class__ is type > 4) type parent object is object : type.__bases__ == (object,) The relationship between type and object is somewhat special, and needs to be bootstrapped by the CPython virtual machine. Arbitrary types (classes) inherit from object. That means the type is a subclass of object: >>> class K(object):pass ... >>> issubclass(K, object) True What's less obvious is that types are themselves objects, and therefore are instances of object: >>> isinstance(K, object) True Since classes are objects, they have a type, namely ``type``. This includes ``type`` itself: * type is an instance of object * object is an instance of type * type is a subclass of object * but object is NOT a subclass of type > B) type vs metaclass > -------------------- > > 1) type is the first metaclass ? Excluding old-style classes, yes, all custom classes (those you create with the class statement) have a default metaclass of type. > 2) type is its own metaclass : type(type) is type ? Yes. Another bit of bootstrapping that the compiler does. >>> type(type) is type True > 3) object's metaclass is type ? Yes. > 4) other metaclasses *MUST* inherit type ? No. Metaclasses can be anything that mimics type. >>> def meta(name, bases, dict): ... class X(object): ... pass ... return X ... >>> class K(object): ... __metaclass__ = meta ... a = 1 ... >>> >>> K <class '__main__.X'> They don't even need to return a type/class. Like decorators, they can return anything. >>> def meta(name, bases, dict): ... return "spam" ... >>> class K(object): ... __metaclass__ = meta ... >>> K 'spam' > 5) type(any_object) == last_metaclass_..., which is, most of the time, > type ? I'm not sure what you mean by "last_metaclass". But no. The type of an object is its class: type(42) => int type("spam") => str type(1.23) => float However, the type of a class is *usually* type. > C) type vs class > ---------------- > > 1) Type is the metaclass of most classes Yes. > 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 }) Except that the syntax won't work, the idea is broadly correct. > 3) Instantiation of any class ``MyClass(*args, **kwargs)`` translates > to:: > > type(MyClass).__call__(MyClass, *args, **kwargs) Like any function call, MyClass(...) becomes type(MyClass).__call__(self, ...) with self=MyClass. Since type(MyClass) is usually ``type``, that gives: type.__call__(MyClass, ...) > This is due to __getattribute__ algorithm (see E) > > 4) It's in type.__call__ that happens calls to __new__ and __init__ If type were written in pure Python, it would probably look something like this: class Type(object): # ... # other methods # ... def __call__(cls, *args, **kwargs): instance = cls.__new__(cls, *args, **kwargs) if isinstance(instance, cls): instance.__init__(*args, **kwargs) return instance But see further on, for more complication. Note that __new__ is special-cased as a staticmethod, hence it needs the first argument to be passed directly. > 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)`` You would need to check the C implementation of type, but if I were doing this in pure Python, I'd have something like this: class Type(object): def __call__(self, *args, **kwargs): if self is Type: if kwargs: raise TypeError('unexpected keyword arguments') # calling type(...) directly if len(args) == 1: # Single argument call, like type(x) return x.__class__ else: # Like type(name, bases, dict) name, bases, dict = *args cls = Type.__new__(Type, name, bases, dict) if isinstance(cls, Type): cls.__init__(name, bases, dict) else: # called from MyClass(...) # which becomes type(MyClass).__call__(MyClass, ...) # self here equals MyClass, which is an instance of type but # not type itself instance = self.__new__(self, *args, **kwargs) if isinstance(instance, self): instance.__init__(*args, **kwargs) return instance def __new__(cls, *args): # magic to actually create a new type object Note that this may not be how ``type`` actually does it. See the source code, and I hope you have better luck reading it than I did! http://hg.python.org/cpython/file/c8e73a89150e/Objects/typeobject.c -- Steven -- http://mail.python.org/mailman/listinfo/python-list