1

In the code, new_type is a class created with members from class X and derived from class A. Any workaround for the TypeError?

class A:
    def __init__(self):
        pass

    def B(self):
        pass
    def C(self):
        pass

class X:
    def __init__(self):
        print(type(self).__bases__)
        super().__init__()

    def B(self):
        self.B()
    def Z(self):
        pass

a = X()
print('ok')
new_type = type("R", ( A,), dict(X.__dict__))
some_obj = new_type()

Program output:

(<class 'object'>,)
ok
(<class '__main__.A'>,)
Traceback (most recent call last):
  File "c:\Evobase2005\Main\EvoPro\dc\tests\sandbox.py", line 37, in <module>
    some_obj = new_type()
  File "c:\Evobase2005\Main\EvoPro\dc\tests\sandbox.py", line 27, in __init__
    super().__init__()
TypeError: super(type, obj): obj must be an instance or subtype of type

In production code, class A does not exist either, but is created dynamically as well because it uses resources from a c++ library for class construction. hence the twisted code. ;)

EDIT This fails too.

class X:
    def __init__(self):
        print(type(self).__bases__)
        super().__init__()

    def Z(self):
        pass

new_type = type("R", (object, ), dict(X.__dict__))
some_obj = new_type()
goldcode
  • 633
  • 8
  • 21

1 Answers1

0

super() has two forms, two-argument form and zero argument form, quoting standard library docs:

The two argument form specifies the arguments exactly and makes the appropriate references. The zero argument form only works inside a class definition, as the compiler fills in the necessary details to correctly retrieve the class being defined, as well as accessing the current instance for ordinary methods.

The zero argument form will not work as it automatically searches the stack frame for the class (__class__) and the first argument and gets confused.

However, when you use the two-argument form of super(), the code works fine:

class A:
    def __init__(self):
        pass

class X:
    def __init__(self):
        print(type(self).__bases__)
        super(self.__class__, self).__init__()

x = X()

R = type("R", (A,), dict(X.__dict__))
obj = R()

Output:

(<class 'object'>,)
(<class '__main__.A'>,)

You cannot use super(self.__class__, self) more than once though in the call hierarchy or you run into infinite recursion, see this SO answer.

mrts
  • 16,697
  • 8
  • 89
  • 72