Issue963246
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.
Created on 2004-05-30 19:52 by glchapman, last changed 2022-04-11 14:56 by admin. This issue is now closed.
Messages (2) | |||
---|---|---|---|
msg20929 - (view) | Author: Greg Chapman (glchapman) | Date: 2004-05-30 19:52 | |
I'm not sure if this constitutes a bug or a limitation (which should be documented?), but the following doesn't work with Python 2.3.4. Assume CMeta is a type defined in C, with tp_base = PyType_Type tp_new = some C function which uses the mro to call the inherited tp_new tp_flags includes Py_TPFLAGS_BASETYPE class PyMeta(type): def __new__(meta, name, bases, attrs): return super(PyMeta, meta).__new__(meta, name, bases, attrs) class MetaTest(CMeta, PyMeta): pass class Test: __metaclass__ = MetaTest The attempt to define Test generates a TypeError: "type.__new__(MetaTest) is not safe, use CMeta.__new__()". The above error is generated (in tp_new_wrapper) by the super call in PyMeta.__new__, but this is only reached as a result of an initial call to CMeta.tp_new (which, using the mro to find the next "__new__" method, finds and calls PyMeta.__new__). It may be there is no good way to allow the above scenario, but I just thought I'd point it out in case someone can think of a workaround. |
|||
msg20930 - (view) | Author: PJ Eby (pje) * | Date: 2004-06-05 20:19 | |
Logged In: YES user_id=56214 There are two things that can cause the error message you got. One is calling a Python __new__ from a C type, such as your code is doing. The only workaround is "don't do that". A C type must always call only C __new__ methods. You can avoid this in your example by moving CMeta *after* PyMeta in the __bases__, but it will fail if CMeta is ever placed anywhere but the end of the list. The alternative is to change CMeta to call its tp_base->tp_new instead of using the mro to find the next base. This will silently ignore any Python __new__ methods in the mro, instead of causing a TypeError. Another multiple inheritance situation that can cause the same error is if you define a C type which subtypes another C type and does not increase its tp_basicsize, *and* the C type is placed anywhere but first in the __bases__ of a Python subclass. You can work around that by ensuring that its tp_basicsize is larger than that of its base C type, so that Python will always pick it as the __base__ (aka tp_base) even if it is not listed first in __bases__. I have written the following additions to the Extending and Embedding manual for future reference: \note{If you want your type to be subclassable from Python, and your type has the same \member{tp_basicsize} as its base type, you may have problems with multiple inheritance. A Python subclass of your type will have to list your type first in its \member{__bases__}, or else it will not be able to call your type's \method{__new__} method without getting an error. You can avoid this problem by ensuring that your type has a larger value for \member{tp_basicsize} than its base type does. Most of the time, this will be true anyway, because either your base type will be \class{object}, or else you will be adding data members to your base type, and therefore increasing its size.} and... \note{If you are creating a co-operative \member{tp_new} (one that calls a base type's \member{tp_new} or \method{__new__}), you must \emph{not} try to determine what method to call using method resolution order at runtime. Always statically determine what type you are going to call, and call its \member{tp_new} directly, or via \code{type->tp_base->tp_new}. If you do not do this, Python subclasses of your type that also inherit from other Python-defined classes may not work correctly. (Specifically, you may not be able to create instances of such subclasses without getting a \exception{TypeError}.)} For more discussion on this, you can also see: A thread on Python-Dev that touches on these issues: http://mail.python.org/pipermail/python-dev/2003-April/034633.html Some notes on ZODB4 running afoul of the same issues: http://collector.zope.org/Zope3-dev/86 |
History | |||
---|---|---|---|
Date | User | Action | Args |
2022-04-11 14:56:04 | admin | set | github: 40310 |
2004-05-30 19:52:23 | glchapman | create |