5

I have two classes inheriting from the same parent P:

from abc import ABCMeta, abstractmethod class P(object): __metaclass__ = ABCMeta @abstractmethod def foo(self): pass class C(P): pass class D(tuple, P): pass 

The only difference is that D inherited from tuple and P while C inherits from P only.

Now this is the behavior: c = C() got error, as expected:

TypeError: Can't instantiate abstract class C with abstract methods foo 

but d = D() works without error!

I can even call d.foo(). How can I explain this behaviour?

4
  • FYI, with Python 3 they both instantiate just fine. Commented Jul 28, 2014 at 7:49
  • Is that capital case Class working for you? Are you not getting any syntax error? Commented Jul 28, 2014 at 7:52
  • @Keith is that preferred? why doesn't abstractmethod work? Commented Jul 28, 2014 at 7:52
  • 1
    @Keith: that's because in Python 3 you need to adjust the metaclass syntax; class P(metaclass=ABCMeta):. Once you do so you'll see the same issue on Python 3, C() throws an exception, D() does not. Commented Jul 28, 2014 at 7:52

1 Answer 1

9

Abstract methods are tested for in the object.__new__ method; when you inherit from tuple, which has its own __new__ method, object.__new__ is not called and the test for abstract methods is not made.

In other words, mixing abstract methods with any of the built-in immutable types will cause this problem.

The only solution that works is to do your own test in __new__ and then only if you put your abstract class before tuple when mixing in the two bases in a subclass.

class P(object): __metaclass__ = ABCMeta def __new__(cls, *args, **kwargs): super_new = super(P, cls).__new__ if super_new.__self__ is not object: # immutable mix-in used, test for abstract methods if getattr(cls, '__abstractmethods__'): raise TypeError( "Can't instantiate abstract class %s " "with abstract methods %s" % ( cls.__name__, ', '.join(sorted(cls.__abstractmethods__)))) return super_new(cls, *args, **kwargs) @abstractmethod def foo(self): pass class D(P, tuple): pass 
Sign up to request clarification or add additional context in comments.

1 Comment

Man, you're a legend :)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.