plok February 2016

Mix-in of abstract class and namedtuple

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.

Answers


Wombatz February 2016

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.

Post Status

Asked in February 2016
Viewed 3,903 times
Voted 13
Answered 1 times

Search




Leave an answer