2016-10-28 5 views
1

単純な例親はバージョン属性を持つクラスです。私はこのクラスを継承したいが、すべての継承クラス間でバージョン属性を共有しないようにする。異なるクラスからの上書きを避けるために、クラスごとにクラス属性を別々にする方法はありますか?

class Parent(object): 
    versions = [] 

    @classmethod 
    def add_version(cls, version): 
     cls.versions.append(version) 

class P1(Parent): 
    pass 

class P2(Parent): 
    pass 

class Thing(object): 
    pass 

P1.add_version(Thing) 
# should be Thing 
print(P1.versions) 
# should be empty [] by my design but it works other way in Python 
# how to achieve to different versions fields without coding it in child classes? 
print(P2.versions) 

このような結果は、クラス間で共有されているため、どのように回避するのですか?

[<class '__main__.Thing'>] 
[<class '__main__.Thing'>] 

答えて

1

あなたはそれぞれの子クラスでversionsを再宣言する必要があります。

class P1(Parent): 
    versions = [] 

class P2(Parent): 
    versions = [] 

これをやって回避する唯一の方法は、あなたが必要とするよりもはるかに面倒である、メタクラスを使用することです。

+0

良いアイデアかもしれませんが、もっと簡単な解決策がありますが、あなたは正しいメタクラスです。 – Chameleon

+0

"はあなたよりもはるかに面倒です" =>うまく、文脈によって異なります。これが同じモジュール内にある2つの子クラスのためのものであり、他の誰かがこれらのクラスを拡張することは期待できません。実際には 'versions'属性を手動で追加するだけです。ライブラリやフレームワークのコードで、 'Parent'がライブラリやフレームワークのユーザによって拡張されていると仮定した場合、5行のメタクラスは本当に"面倒 "の価値があります;) –

2

技術的にはあなたが必要メタクラスいけない - 単純なクラスのデコレータも動作します(まあ、一種の...):

def versions_container(cls): 
    if "versions" not in cls.__dict__: 
     print("adding versions to class {}".format(cls.__name__)) 
     cls.versions = [] 
    return cls 


@versions_container # this one is useless but anyway... 
class Parent(object): 
    versions = [] 
    @classmethod 
    def add_version(cls, version): 
     cls.versions.append(version) 

@versions_container 
class P1(Parent): 
    pass 

@versions_container 
class P2(Parent): 
    pass 

class Thing(object): 
    pass 

P1.add_version(Thing) 
print(P1.versions) 
print(P2.versions) 

しかし、これは手動でversions属性を追加するよりもかろうじて良いですが各子クラス。

は、カスタムのメタクラス・ソリューションは、このような大したことではなく、あなたのコードの確認、ユーザーが期待中断されませんようになります。代わりに、各クラスのクラス属性、することができますようにバージョンを保存する

class VersionsContainer(type): 
    def __new__(meta, name, bases, attrs): 
     if "versions" not in attrs: 
      attrs["versions"] = [] 
     return type.__new__(meta, name, bases, attrs) 

class Parent(object, metaclass=VersionContainer): 
    @classmethod 
    def add_version(cls, version): 
     cls.versions.append(version) 

class P1(Parent): 
    pass 

class P2(Parent): 
    pass 

class Thing(object): 
    pass 

P1.add_version(Thing) 
print(P1.versions) 
print(P2.versions) 
1

を1つの辞書にそれらをすべて格納します。

class Parent(object): 

    _versions = {} # class -> version_list 

    @classproperty 
    def versions(cls): 
     return cls._versions.setdefault(cls, []) 

    @classmethod 
    def add_version(cls, version): 
     cls.versions.append(version) 

class P1(Parent): 
    pass 
class P2(Parent): 
    pass 

P1.add_version(1) 
print(P1.versions) 
print(P2.versions) 

classpropertyは非常に有用な非組み込み構造です。あなたはthis answerでそれを見つけることができます)

私はneccessarilyこれが最善か、最もエレガントなアプローチで言っていないんだけど、それは本当に簡単で、このアプローチの明らかな欠点は、サブクラス用のデータを格納するクラスが必要であることです。これは設計上の大きな問題ではありません。

+1

私はclasspropertyをよく知っています。少し違うコードを実行しようとします。 – Chameleon

関連する問題