Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mix-in of abstract class and namedtuple

Tags:

python

I want to define a mix-in of a namedtuple and a base class with defines and abstract method:

import abc
import collections

class A(object):
    __metaclass__ = abc.ABCMeta

    @abc.abstractmethod
    def do(self):
        print("U Can't Touch This")

B = collections.namedtuple('B', 'x, y')

class C(B, A):
    pass

c = C(x=3, y=4)
print(c)
c.do()

From what I understand reading the docs and other examples I have seen, c.do() should raise an error, as class C does not implement do(). However, when I run it... it works:

B(x=3, y=4)
U Can't Touch This

I must be overlooking something.

like image 627
plok Avatar asked Feb 08 '16 10:02

plok


People also ask

Can abstract class have init?

In object-oriented programming, an abstract class is a class that cannot be instantiated.

Can we create object of abstract class in Python?

An abstract class is a class, but not one you can create objects from directly. Its purpose is to define how other classes should look like, i.e. what methods and properties they are expected to have.

Do you have to implement all methods of an abstract class Python?

Yes, you have to implement all abstract methods in Python to instantiate them as objects (the ones marked with @abstractmethod , etc). How you implement these, however, are completely up to you. If you're not going to be instantiating, you don't need to override all of them.

What is ABCMeta class in Python?

ABCMeta metaclass provides a method called register method that can be invoked by its instance. By using this register method, any abstract base class can become an ancestor of any arbitrary concrete class.


Video Answer


1 Answers

When you take a look at the method resolution order of C you see that B comes before A in that list. That means when you instantiate C the __new__ method of B will be called first.

This is the implementation of namedtuple.__new__

def __new__(_cls, {arg_list}):
    'Create new instance of {typename}({arg_list})'
    return _tuple.__new__(_cls, ({arg_list}))

You can see that it does not support cooperative inheritance, because it breaks the chain and simply calls tuples __new__ method. Like this the ABCMeta.__new__ method that checks for abstract methods is never executed (where ever that is) and it can't check for abstract methods. So the instantiation does not fail.

I thought inverting the MRO would solve that problem, but it strangely did not. I'm gonna investigate a bit more and update this answer.

like image 200
Wombatz Avatar answered Oct 12 '22 18:10

Wombatz