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