Наследование наследования Python, метаклассы и функция type()

Я не понимаю, почему следующий код ведет себя определенным образом, который описан ниже:

from abc import ABCMeta   

class PackageClass(object):
    __metaclass__ = ABCMeta        

class MyClass1(PackageClass):
    pass

MyClass2 = type('MyClass2', (PackageClass, ), {})

print MyClass1
print MyClass2

>>> <class '__main__.MyClass1'> 
>>> <class 'abc.MyClass2'>

Почему repr(MyClass2) говорит abc.MyClass2 (что, кстати, неверно)? Спасибо!

Ответ 1

Проблема связана с тем, что ABCMeta переопределяет __new__ и называет его конструктор суперкласса (type()). type() выводит __module__ для нового класса из его вызывающего контекста 1; в этом случае вызов type появляется из модуля abc. Следовательно, новый класс имеет __module__, установленный в abc (так как type() не знает, что фактическая конструкция класса имела место в __main__).

Легкий способ - просто установить __module__ самостоятельно после создания типа:

MyClass2 = type('MyClass2', (PackageClass, ), {})
MyClass2.__module__ = __name__

Я бы также рекомендовал подать отчет об ошибке.

Связано: переопределение базового метакласса __new__ генерирует классы с неправильным __module__, странное наследование с метаклассами

1: type - объект типа, определенный в C. Его новый метод использует текущий глобальный __name__ как __module__, если он не вызывает конструктор метакласса.