How do you mix old-style and new-style Python classes?

I saw several questions on this topic, but I could not find a definitive answer.

I would like to know the correct way to use old-style classes in the new Python code base. Say, for example, that I have two fixed classes: A and B. If I want to subclass A and B , and convert to new style classes ( A2 and B2 ), this works. However, there is a problem if I want to create a new class C , from A2 and B2 .

Therefore, is it possible to continue this method, or should all classes correspond to the old style if some base class is defined as the old style?

See sample code for explanation:

class A: def __init__(self): print 'class A' class B: def __init__(self): print 'class B' class A2(A,object): def __init__(self): super(A2, self).__init__() print 'class A2' class B2(B,object): def __init__(self): super(B2, self).__init__() print 'class B2' class C(A2, B2): def __init__(self): super(C,self).__init__() print 'class C' A2() print '---' B2() print '---' C() 

Result of this code:

 class A class A2 --- class B class B2 --- class A class A2 class C 

As you can see, the problem is that when calling C() class B2 was not initialized.


Update - an example of a new style class

I think it is unclear what the correct initialization sequence should be when using super . Here is a working example in which the super call executes , initializes all the base classes, and not just the first one it finds.

 class A(object): def __init__(self): super(A, self).__init__() print 'class A' class B(object): def __init__(self): super(B, self).__init__() print 'class B' class A2(A): def __init__(self): super(A2, self).__init__() print 'class A2' class B2(B): def __init__(self): super(B2, self).__init__() print 'class B2' class C(A2, B2): def __init__(self): super(C, self).__init__() print 'class C' C() 

and displays the result:

 class B class B2 class A class A2 class C 
+6
python instantiation class multiple-inheritance
source share
1 answer

It is not a problem to mix old and new style classes. The super () function does not call all the functions of the base classes, it calls the first one found in accordance with the order of resolution of the method. In this case, A2, which in turn calls A.

If you want to call both, do it explicitly:

 class C(A2, B2): def __init__(self): A2.__init__(self) B2.__init__(self) print 'class C' 

This should solve the problem.

Update:

The problem of diamond inheritance that you refer to is the question of what class should be called in the situation of diamond inheritance, for example:

 class A: def method1(self): print 'class A' def method2(self): print 'class A' class B(A): def method1(self): print 'class B' class C(A): def method1(self): print 'class C' def method2(self): print 'class C' class D(B, C): pass 

Now check this out:

 >>> D().method1() 'class B' 

It is right. It calls the implementation of the first class. However, try this with method2:

 >>> D().method2() 'class A' 

Smiles, WRONG! He should have called class C.method2 () here, because although class B does not override method2, class C does. Now make class A a class newstyle:

 class A(object): def method1(self): print 'class A' 

And try again:

 >>> D().method1() 'class B' >>> D().method2() 'class C' 

and hey presto, it works. This is the difference between the method resolution orders between the new and old style classes, and this is what sometimes makes them mix.

Notice that calls B and C are by no means called. This is true even if we call super.

 class D(B, C): def method1(self): super(D, self).method1() def method2(self): super(D, self).method2() >>> D().method1() 'class B' >>> D().method2() 'class C' 

If you want to call both B and C, you MUST call both explicitly.

Now, if you unlock the diamond, as in your example with separate base classes, the result will be different:

 class A1(object): def method1(self): print 'class A1' def method2(self): print 'class A1' class A2(object): def method1(self): print 'class A2' def method2(self): print 'class A2' class B(A1): def method1(self): print 'class B' class C(A2): def method1(self): print 'class C' def method2(self): print 'class C' class D(B, C): def method1(self): super(D, self).method1() def method2(self): super(D, self).method2() >>> D().method1() 'class B' >>> D().method2() 'class A1' 

It is also for design. Nowhere else are two base classes called. If you want this to happen, you still need to call both explicitly.

+6
source share

All Articles