This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: documentation on metaclasses is incomplete and misleading
Type: Stage:
Components: Interpreter Core Versions: Python 2.5
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: georg.brandl Nosy List: amaury.forgeotdarc, georg.brandl, lpd
Priority: normal Keywords:

Created on 2008-01-04 05:50 by lpd, last changed 2022-04-11 14:56 by admin. This issue is now closed.

Messages (6)
msg59216 - (view) Author: L. Peter Deutsch (lpd) Date: 2008-01-04 05:50
In the following, dir(Node) should include the name 'z', and Node.z
should be 'Node'. However, dir(Node) does not include 'z', and Node.z is
undefined (AttributeError). This is directly contrary to the Python
documentation, which says "metaclasses can modify dict".

class MetaNode(type):
    def __init__(cls, name, bases, cdict):
        cdict['z'] = name
        type.__init__(name, bases, cdict)
class Node(object):
    __metaclass__ = MetaNode

print dir(Node)
print Node.z
msg59218 - (view) Author: Amaury Forgeot d'Arc (amaury.forgeotdarc) * (Python committer) Date: 2008-01-04 08:39
When designing a metaclass, you should override __new__, not __init__:

class MetaNode(type):
   def __new__(cls, name, bases, cdict):
       cdict['z'] = name
       return type.__new__(cls, name, bases, cdict)

class Node(object):
   __metaclass__ = MetaNode
msg59245 - (view) Author: L. Peter Deutsch (lpd) Date: 2008-01-04 17:35
Please reopen this issue as a documentation bug.

The documentation for __new__ in section 3.4.1 says:

__new__() is intended mainly to allow subclasses of immutable types
(like int, str, or tuple) to customize instance creation.

The documentation for metaclasses in 3.4.3 says nothing about __new__
vs. __init__. It says the metaclass will be "called" for class creation,
and it says the metaclass can be any "callable". This would imply the
use of __call__ rather than __new__ or __init__.

I think 3.4.1 should say:

__new__() is intended mainly to allow subclasses of immutable types
(like int, str, or tuple) to customize instance creation. It is also
used for custom metaclasses (q.v.).

I think 3.4.3 should be reviewed in its entirety to replace the
misleading language about "called" and "callable" with language that
explicitly mentions __new__.
msg59302 - (view) Author: Georg Brandl (georg.brandl) * (Python committer) Date: 2008-01-05 19:05
I'll look into it.
msg59312 - (view) Author: L. Peter Deutsch (lpd) Date: 2008-01-05 19:35
Actually, "called" and "callable" are OK, if the documentation says
somewhere that the normal effect of "calling" a type object is to invoke
__new__. The places I looked first (sections 3.1, 3.3, and 3.4.1) do not
say this. 5.3.4 does say that the result of calling a class object is a
new instance of that class, but it doesn't mention __new__. So perhaps
it would OK to just add something like the following to 3.4.3:

Note that if a metaclass is a subclass of <code>type</code>, it should
override <code>__new__</code>, not <code>__call__</code>.
msg59482 - (view) Author: Georg Brandl (georg.brandl) * (Python committer) Date: 2008-01-07 19:17
This should now be appropriately explained in the trunk, r59837. I also
added an example of using __new__ in a metaclass.
History
Date User Action Args
2022-04-11 14:56:29adminsetgithub: 46075
2008-01-07 19:17:35georg.brandlsetstatus: open -> closed
resolution: fixed
messages: + msg59482
2008-01-05 19:35:30lpdsetmessages: + msg59312
2008-01-05 19:05:32georg.brandlsetassignee: georg.brandl
2008-01-05 19:05:23georg.brandlsetstatus: closed -> open
nosy: + georg.brandl
resolution: not a bug -> (no value)
messages: + msg59302
2008-01-04 17:35:17lpdsetmessages: + msg59245
title: no effect if metaclass modifies dict -> documentation on metaclasses is incomplete and misleading
2008-01-04 08:39:42amaury.forgeotdarcsetstatus: open -> closed
resolution: not a bug
messages: + msg59218
nosy: + amaury.forgeotdarc
2008-01-04 05:50:39lpdcreate