2010-06-09 39 views
56

Tại sao điều này:metaclass đa kế thừa mâu thuẫn

class MyType(type): 
    def __init__(cls, name, bases, attrs): 
     print 'created', cls 
class MyMixin: 
    __metaclass__ = MyType 
class MyList(list, MyMixin): pass 

sao, và làm việc như mong đợi:

created <class '__main__.MyMixin'> 
created <class '__main__.MyList'> 

Nhưng điều này:

class MyType(type): 
    def __init__(cls, name, bases, attrs): 
     print 'created', cls 
class MyMixin: 
    __metaclass__ = MyType 
class MyObject(object, MyMixin): pass 

là không ổn, và thổi lên thusly ?:

created <class '__main__.MyMixin'> 
Traceback (most recent call last): 
    File "/tmp/junk.py", line 11, in <module> 
    class MyObject(object, MyMixin): pass 
TypeError: Error when calling the metaclass bases 
    Cannot create a consistent method resolution 
order (MRO) for bases object, MyMixin 

Trả lời

81

Nó không phải là một vấn đề tùy chỉnh metaclass (mặc dù nó chẩn đoán ở giai đoạn metaclass):

>>> class Normal(object): pass 
... 
>>> class MyObject(object, Normal): pass 
... 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: Error when calling the metaclass bases 
    Cannot create a consistent method resolution 
order (MRO) for bases object, Normal 

và vấn đề chỉ là tương tự như thế này một:

>>> class Derived(Normal): pass 
... 
>>> class Ok(Derived, Normal): pass 
... 
>>> class Nope(Normal, Derived): pass 
... 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: Error when calling the metaclass bases 
    Cannot create a consistent method resolution 
order (MRO) for bases Normal, Derived 

tức là, không thể nhân kế thừa từ một lớp cơ sở theo sau là một lớp dẫn xuất - không thể xác định một MRO nhất quán đáp ứng các ràng buộc/bảo đảm MRO thông thường.

May mắn thay, bạn không muốn để làm điều đó - các lớp con có lẽ sẽ ghi đè một số phương thức của lớp cơ sở (đó là những gì lớp con bình thường làm ;-), và có lớp cơ sở "trước" sẽ có nghĩa là "che khuất ghi đè".

Đặt lớp cơ sở sau nguồn gốc là khá vô ích, nhưng ít nhất nó vô hại (và phù hợp với bảo đảm MRO bình thường).

ví dụ đầu tiên của bạn tất nhiên làm việc vì MyMixinkhông có nguồn gốc từ list:

>>> MyMixin.__mro__ 
(<class '__main__.MyMixin'>, <type 'object'>) 

... nhưng nó được có nguồn gốc từ object (như mỗi lớp Python hiện đại mang phong cách), do đó ví dụ thứ hai không thể hoạt động (hoàn toàn độc lập với MyMixin có metaclass tùy chỉnh).

-1

Ở đây, bạn đang kế thừa lớp cha và lớp cha đã kế thừa một lớp khác, vì vậy không cần kế thừa lớp mà lớp cha đã kế thừa.

Ví dụ:

class A(object): 
. 
. 
class B(object, A): 
. 
. 

Nó sẽ ném ra một lỗi vì A được kế thừa đối tượng lớp và B được kế thừa A, do đó gián tiếp B được kế thừa đối tượng, do đó không cần phải kế thừa đối tượng. . . .

Giải pháp là chỉ xóa lớp đối tượng khỏi danh sách đối số lớp B ....

Các vấn đề liên quan