4

I am using Python3.3 and noticed the following : metaclass works perfectly with user defined classes and multiple inheritance, but when a class inherits from a built-in type (such as list, tuple, complex...) the behaviour changes unexpectedly.

First, an example with the correct behaviour:

from abc import ABCMeta, abstractmethod

class A(metaclass=ABCMeta):    
    @abstractmethod
    def say_hello(self):
        print("hello")

class B:
    pass

class C(A, B):
    pass

Since the abstract method say_hello has not been overriden, this is the correct result when instanciating class C :

>>> c = C()
Traceback (most recent call last):
  File "<pyshell#42>", line 1, in <module>
    c=C()
TypeError: Can't instantiate abstract class C with abstract methods say_hello

I have tried this also with B as a metaclass and it works fine.

Now for the weird part. Let's substitute B by a built-in (list in this example):

from abc import ABCMeta, abstractmethod

class A(metaclass=ABCMeta):    
    @abstractmethod
    def say_hello(self):
        print("hello")

class C(A, list):
    pass

Instantiation works, which is not what one should expect:

>>> c = C()
>>>

And, even worse, the abstract method is callable without any super():

>>> c.say_hello()
hello

What am I doing wrong ? If this is a documented behaviour I would be thankful if someone has a reference to it.

EDIT I just add a comment because consequences are worse than I expected :

>>> import numbers
>>> b = 2
>>> isinstance(b, numbers.Integral)
True
>>> isinstance(b, int)
True
>>> b.real
2
>>> class A(numbers.Integral, int):
    pass

>>> a = A()
>>> isinstance(a, int)
True
>>> isinstance(a, numbers.Integral)
True
>>> a.real
Traceback (most recent call last):
  File "<pyshell#114>", line 1, in <module>
    a.real
  File "C:\Python33\lib\numbers.py", line 258, in real
    return +self
  File "C:\Python33\lib\numbers.py", line 89, in __pos__
    raise NotImplementedError
NotImplementedError
Dragoon
  • 41
  • 3

0 Answers0