2016-04-19 18 views
5

現状の一部

として、私はnumpyの配列の形式でデータをホストし、抽象基本クラスを持って、このデータを操作する方法を知っており、これは、描画する方法matplotlibのを説明することができますそれ。異なるタイプのデータを収容するためには、このように多くのサブクラスました:は、クラスメソッドの呼び出し初期化

class PlotData(): 
    """Base Class""" 
    subclasslist = [] 

    @classmethod 
    def register(cls): 
     super().subclasslist.append(cls) 

    def __new__(self, initdata, *args, **kwargs): 
     for subclass in subclasslist: 
      try: 
       subclass.__test__(initdata) 
      except AssertionError: 
       continue 
      else: 
       break 
     else: 
      raise TypeError("Initdata does not fit any known subclass") 
     return subclass(initdata, *args, **kwargs) 

class Plot3D(PlotData): 
    """Subclass for 3d-plotting data""" 
    def __test__(initdata): 
     assert Data_is_the_right_kind 

class Plot_XY(PlotData): 
    """Subclass for for plotting X-Y relations of data""" 
    def __test__(initdata): 
     assert Data_is_the_right_kind 

号今

、問題がsubclasslistにクラス参照を取得する方法です。最初はクラス本体にsuper().register()を呼びたいと思いましたが、クラス自体への参照を取得できませんでした。これはリストに格納したいものです。小規模な検索では2つの可能な解決策が得られました。そして、私は最高のものが何かを考えていました。 - クラス構造の非常に重要な部分である

class Plot_XY(PlotData): 
    """Subclass for for plotting X-Y relations of data""" 
    def __test__(initdata): 
     assert Data_is_the_right_kind 
Plot_XY.register() 

これは動作しますが、私には非常に汚いソリューションのように思える:このような各クラス定義の後に呼び出しを追加、

ソリューション1

体の外側に位置する。

解決策2

また、クラスデコレータも可能です。しかし、以前はこれまで使ったことはありませんでした。私が見つけた例は、一般的にメソッドにオーバーライド/機能を追加するために使用されています。 (例えば、hereおよびhere)。でも、私は、関数デコレータに精通していて、次は大体私が目指してるものを明確にしなければならない(とダウン易しく書き直さバージョンはインタプリタで動作します):

def some_creative_decorator_name(cls): 
    cls.register() 
    return cls 

または少なくとも、ソリューション1のように機能何かしかし、次のようになります:

@some_creative_decorator_name 
class Plot_XY(PlotData): 
    """Subclass for for plotting X-Y relations of data""" 
    def __test__(initdata): 
     assert Data_is_the_right_kind 

これはうまくいくようですが、このようなものは継承のようなものでしょうか?それはリンクされたページで指摘されている懸念の一つであり、私はそれほど多くのことを敢えて思いません。 (私はさらにそれをサブクラス化するために人々を期待していないのですが、私は実際にそれを望むなら、それを不可能にする必要はありません。)

(もちろん、他のソリューションも同様に歓迎されている。)何をやっている

答えて

6

それはすでに提供されますので、無用です:

>>> class A(object):pass 
... 
>>> class B(A):pass 
... 
>>> class C(A): pass 
... 
>>> A.__subclasses__() 
[<class '__main__.B'>, <class '__main__.C'>] 
>>> 

Pythonはすでにあなたのための1を提供する場合subclasslistあなた自身を維持する必要はありません。あなたがしたい場合は、これは言っ

>>> def all_subclasses(klass): 
...  for sub in klass.__subclasses__(): 
...   yield sub 
...   yield from all_subclasses(sub) 
... 
>>> list(all_subclasses(A)) 
[<class '__main__.B'>, <class '__main__.D'>, <class '__main__.C'>] 

:このサブクラスのサブクラスが含まれていないこと

注:

>>> class D(B):pass 
... 
>>> A.__subclasses__() 
[<class '__main__.B'>, <class '__main__.C'>] 

は、しかし、すべてのサブクラスを見つけるために十分に簡単ですこの機能を複製すると、デフォルトのメソッドがどのように機能するかがわかります。そして、あなたはそれを発見したい:

>>> '__subclasses__' in dir(object) 
False 
>>> '__subclasses__' in dir(type) 
True 

だからここにあなたがそれをメタクラスobjectあるtypeの方法であることがわかります。これを適切に複製する方法は、カスタムメタクラスを書くことです。

基本的にメタクラスは、しかし、デコレータのアプローチに似ています:クラスが作成される前に、あなたがものを行うことができますので、それがより一般的である

  • 、それが作成される方法を制御し、その後何かをします。デコレータが完了した時点でクラスオブジェクトを受け取り、作成後の作業のみを行うことができます
  • これらは継承されているため、各クラスに明示的に追加する必要はありません。

ここでは詳しくは触れません。メタクラスの詳細についてはWhat is a metaclass in Python?をご覧ください。

+0

ありがとうございます!それは役に立ちます。私は前に '__subclasses__'について知りませんでした。私の仕事はずっと楽になっています。また、私には新しいメタクラスについて少しお読みになります。 – Gloweye

関連する問題