2016-11-15 109 views
1

我想寫一個Mixin,它可以擴展最終的父類屬性,而不是替換它。例如:用Mixin擴展類屬性

class Base(object): 
    my_attr = ['foo', 'bar'] 

class MyMixin(object): 
    my_attr = ['baz'] 

class MyClass(MyMixin, Base): 
    pass 

print(MyClass.my_attr) 

[ '巴茲']

如何寫MyMixinMyClass.my_attr['foo', 'bar', 'baz']作爲值?

答案可以做MyClass合併,但我想知道是否有可能在MyMixin做到這一點。像MetaClass或其他東西?

回答

1

如果你真的想這樣做的類與混合料攪拌屬性,你必須使用自定義的元類,把混入Base後的MRO(這意味着它不會重寫基類的東西,只是給它添加):

class Base(object): 
    my_attr = ['foo', 'bar'] 

class MyMixinBase(type): 
    def __init__(cls, name, parents, attribs): 
     my_attr = getattr(cls, "my_attr", None) 
     if my_attr is None: 
      cls.my_attr = ["baz"] 
     elif "baz" not in my_attr: 
      my_attr.append("baz") 


class MyMixin(object): 
    __metaclass__ = MyMixinBase 

class MyClass(Base, MyMixin): 
    pass 

print(MyClass.my_attr) 

這使得相當費解的代碼...在這一點上,僅使用MyMixinBase作爲MyClass的元類將產生相同的結果:

class MyOtherClass(Base): 
    __metaclass__ = MyMixinBase 

print(MyOtherClass.my_attr) 

,並於這種用途的情況下,一類裝飾工程只是罰款:

def with_baz(cls): 
    my_attr = getattr(cls, "my_attr", None) 
    if my_attr is None: 
     cls.my_attr = ["baz"] 
    elif "baz" not in my_attr: 
     my_attr.append("baz") 
    return cls 

@with_baz 
class AnotherClass(Base): 
    pass 

print(AnotherClass.my_attr) 
+0

你的回答正是我所希望的。 – bux

+0

@bux很高興有任何幫助 - 現在(只是出於好奇)你會關心分享哪三個「解決方案」解決你的問題?) –

+0

我添加了python3版本到您的答案 – bux

0
class Base(object): 
    my_attr = ['foo', 'bar'] 

class MyMixin(object): 
    my_attr = ['baz'] 

class MyClass(MyMixin, Base): 
    my_attr = MyMixin.my_attr + Base.my_attr 


print(MyClass.my_attr) 

[ '巴茲', '富', '酒吧']

您必須手動將它們合併。

0

你不能這樣做,因爲你的第二類不能訪問第一個類。一種方法是從每個課程中獲取my_attr內的my_calss並將它們添加在一起。如果你不想以任何理由,你可以訪問所有基地my_attr,做這個鏈條他們:

In [20]: from itertools import chain 

In [21]: list(chain.from_iterable(cls.my_attr for cls in MyClass.__bases__)) 
Out[21]: ['baz', 'foo', 'bar']