I found a weird behavior with cpython 2.5, 2.7, 3.2 and pypy with metaclass that override __new__
when using the python 2 / python 3 compatible way of using metaclass :
Given a module m1:
class C1Meta(type):
def __new__(cls, name, bases, dct):
return type.__new__(cls, name, bases, dct)
C1 = C1Meta('C1', (object,), {})
class C2Meta(type):
pass
C2 = C2Meta('C2', (object,), {})
And the following main program:
import m1
C10 = m1.C1Meta('C10', (m1.C1,), {})
class C11Meta(m1.C1Meta):
pass
C11 = C11Meta('C11', (m1.C1,), {})
class C12Meta(m1.C1Meta):
def __new__(cls, name, bases, dct):
return m1.C1Meta.__new__(cls, name, bases, dct)
C12 = C12Meta('C12', (m1.C1,), {})
class C13Meta(m1.C1Meta):
def __new__(cls, name, bases, dct):
return type.__new__(cls, name, bases, dct)
C13 = C13Meta('C13', (m1.C1,), {})
C20 = m1.C2Meta('C20', (m1.C2,), {})
class C21Meta(m1.C2Meta):
pass
C21 = C21Meta('C21', (m1.C2,), {})
class C22Meta(m1.C2Meta):
def __new__(cls, name, bases, dct):
return m1.C2Meta.__new__(cls, name, bases, dct)
C22 = C22Meta('C22', (m1.C2,), {})
class C23Meta(m1.C2Meta):
def __new__(cls, name, bases, dct):
return type.__new__(cls, name, bases, dct)
C23 = C23Meta('C23', (m1.C2,), {})
print(C10)
print(C11)
print(C12)
print(C13)
print(C20)
print(C21)
print(C22)
print(C23)
Running the script will produce the following output (with all the mentioned python versions) :
<class 'm1.C10'>
<class 'm1.C11'>
<class 'm1.C12'>
<class '__main__.C13'>
<class '__main__.C20'>
<class '__main__.C21'>
<class '__main__.C22'>
<class '__main__.C23'>
-> the C10, C11 and C12 classes module is wrong !
Is it an expected behavior ?
Is there a way to override new that will not raise the issue ?
Thanks,
Christophe
Apparently the
__module__
attribute is set when the metaclass executes. In your case, the metaclass executes insidem1
. With a normally defined class, the__module__
attribute is automatically generated and passed to the metaclass. However, you are creating your classes with a manual call to the metaclass, and passing in an empty attribute dictionary. Thus your classes do not provide a__module__
attribute. The__module__
attribute is created automatically, but not untiltype.__new__
is called. Since this happens inside modulem1
, the__module__
created at that time refers tom1
.I'm not exactly sure why you're calling the metaclass explicitly. The whole point of metaclasses is to allow you to customize what happens when you use a
class
statement to define a class. If you don't want to use aclass
statement, you can just use regular functions to create your classes, and don't need to bother with a metaclass at all.That said, I believe you can get your desired behavior, by doing, e.g.,