diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -1376,21 +1376,51 @@ With three arguments, return a new type object. This is essentially a dynamic form of the :keyword:`class` statement. The *name* string is the class name and becomes the :attr:`__name__` attribute; the *bases* tuple - itemizes the base classes and becomes the :attr:`__bases__` attribute; - and the *dict* dictionary is the namespace containing definitions for class - body and becomes the :attr:`__dict__` attribute. For example, the - following two statements create identical :class:`type` objects: + itemizes the base classes and becomes the :attr:`__bases__` attribute; and + the *dict* dictionary is the namespace containing definitions for class body + and becomes the :attr:`__dict__` attribute. + + For example, the following two statements create identical :class:`type` + objects: >>> class X: ... a = 1 ... >>> X = type('X', (object,), dict(a=1)) + However, when any of the base classes is using metaclasses, there is a + difference between definition of a derived class using the :keyword:`class` + statement, and definition of the derived class using :func:`type`. In the + later case, any `__prepare__` functions defined in the metaclass (cf. + :ref:`class-namespace-preparation`) are *not* executed. + + The following example demonstrates the difference: + + >>> class CustomMetaclass(type): + ... @classmethod + ... def __prepare__(cls, name, bases): + ... return { 'prepared_for': name } + ... + >>> class ParentClass(metaclass=CustomMetaclass): + ... pass + ... + >>> class ClassOne(ParentClass): + ... pass + ... + >>> ClassTwo = type('ClassTwo', (ParentClass,), {}) + >>> ClassOne.prepared_for + 'ClassOne' + >>> ClassTwo.prepared_for + 'ParentClass' + >>> 'prepared_for' in ClassOne.__dict__ + True + >>> 'prepared_for' in ClassTwo.__dict__ + False + See also :ref:`bltin-type-objects`. - .. function:: vars([object]) - + Return the :attr:`__dict__` attribute for a module, class, instance, or any other object with a :attr:`__dict__` attribute. diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -1619,6 +1619,8 @@ that criterion, then the class definition will fail with ``TypeError``. +.. _class-namespace-preparation: + Preparing the class namespace ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^