2016-04-22 16 views
4

私はモジュールにPythonクラスを持っていますが、同じモジュール内に他のクラスのリストが必要ないくつかのメソッドがあります。ここではどのように私は今それをやっているされていますPython:クラスが定義される前にモジュール内のクラスを見つけよう

module.py

class Main: 
    @staticmethod 
    def meth1(): 
    for c in classes: 
     #do something 

    @staticmethod 
    def meth2(): 
    for c in classes: 
     #do something 

class Class1: 
    pass 

class Class2: 
    pass 

class Class3: 
    pass 

classes = [Class1, Class3] 

いくつかのことを私は改善したいと思います:

  1. 私はどこかclassesリストを入れたいのですがより一般的です。理想的には、すべてのクラスの外側であるが、モジュールファイルの先頭、またはクラス属性がMainであるが、meth1またはmeth2の外にある。その目的は、誰かが別のクラス定義を追加する必要がある場合、見つけやすくすることです。
  2. 可能であれば、これをプログラムで実行したいので、まずはリストを明示的に定義する必要はありません。これは#1の必要性を排除します(ただし、私はまだ普及していたいと思いますが)。これを行うには、同じモジュール内で定義されたすべてのクラスをリストする方法が必要です。私が最も近かったのはdir()またはlocals()ですが、インポートされたクラス、メソッド、およびモジュールもリストされています。また、私が欲しいクラスを特定するには何らかの方法が必要です。私はクラスの属性だけでそれを行うことができますが、もっとエレガントなやり方があればいいでしょう。

私も可能なことをしようとしていますか?

+0

あなたの例では、モジュール内の2つのクラスを対象としたが、その後、あなたがプログラムでそれをやりたいと言います。それがどのように働くと思いますか? – 7stud

+0

@ 7stud私はいくつかのクラスを追加することができますが、そのうちのいくつかはターゲットにされていますが、クラスのいくつかの機能に基づいてそれをターゲットにするかどうかを決定することができます。 [ここに例があります](http://pastebin.com/ALd0YdcU)問題は1です。私は 'get_all_local_classes()'を知る方法がわかりません。2.すべてのクラスに 'is_a_target()'メソッドを定義させるよりも、フィルタリングする方がいいです。 – ewok

+0

@ 7stud上記の例ではフィルタを行う方法がありません。私はそれについての提案を探しています – ewok

答えて

4

個人的には、私はdecoratorを使用して、重要なクラスをマークします。目立つようなファイルの上部にそれらを保持するリストを置くことができます。ここで

は簡単な例です:

# Classes are added here if they are important, because... 
important_classes = [] 


def important(cls): 
    important_classes.append(cls) 
    return cls 


@important 
class ClassA(object): 
    pass 


class ClassB(object): 
    pass 


@important 
class ClassC(object): 
    pass 

# Now you can use the important_classes list however you like. 
print(important_classes) 
# => [<class '__main__.ClassA'>, <class '__main__.ClassC'>] 
+0

ああ!これはまさに私が探していたものです。 – ewok

+0

私はちょうどバグ@ewokを修正しました。私はデコレータから 'cls'を返すのを忘れました。 –

1

私はこれがベストプラクティスであるかどうかわからないのですが、これは何が必要でしょう。

class Main: 
    def __init__(self, locals): 
     self.classes = [] 
     for (c, val) in locals.iteritems(): 
      try: 
       if c[:5] == 'Class': 
        self.classes.append(val) 
      except: 
       pass 

    def meth1(self): 
     for c in self.classes: 
      pass 

    def meth2(self): 
     for c in self.classes: 
      pass 

class Class1: 
    pass 

class Class2: 
    pass 

class Class3: 
    pass 

main = Main(locals()) 
print main.classes 
+0

半有用。これはインスタンスでは動作しますが、 'meth1'と' meth2'が静的でない場合は動作しません。私はそれを含めるべきだったし、私は質問を更新します。 – ewok

2

あなたが検査を使用することができます。

まず、ローカル変数のリストを得る:

local_vars = locals().values() 

その後、我々は一つ一つ検査する必要があります。

を: cls.__module__ == __name__場合は、次のように確認し、ローカルに定義されたクラスのみを取得するには

import inspect 
local_vars = [i for i in local_vars if inspect.isclass(i)] 

def get_classes(): 
    global_vars = list(globals().values()) 
    classes = [i for i in global_vars if inspect.isclass(i)] 
    return [i for i in classes if i.__module__ == __name__] 

全体的な考え方は次のとおりです。inspectはyo uを使用してライブオブジェクトを検査し、すべてのローカル変数を反復処理することで、現在のネームスペース内のすべてを検査できます。ローカルクラスで定義されている最後の部分は、モジュール名が現在の名前空間と同じかどうか、つまりcls.__module__ == __name__であるかどうかを調べることによって行うことができます。

最後に、Python3との互換性のために、辞書のサイズがリストの理解の間に変更されるため、list(globals().values()を追加しました。 Python2では、dict.values()がリストを返すので、これは省略することができます。

EDIT:さらにフィルタリングするための

コメントで述べたように、あなたはまた、特定のクラスの属性やその他を使用することができます。後でモジュールをパッケージに再構成することを心配している場合は、これは素晴らしいことです。

def get_classes(name='target'): 
    global_vars = list(globals().values()) 
    classes = [i for i in global_vars if inspect.isclass(i)] 
    return [i for i in classes if hasattr(i, name)] 
+0

これにはインポートされたクラスも含まれませんか? – ewok

+1

私はそれを試してみました。インポートされたクラスは含まれています。 'inspect'はクラスではなくモジュールであるため、' inspect'は含まれません – ewok

+1

うわー、私はコーヒーが必要です。ごめんなさい。これで少し遊んでみましょう。 –

2

あり、これを達成するためのより良い方法かもしれませんが、私はホルダーのこれらのサブクラスのすべてになるだろうし、それらすべてを引っ張って__subclasses__()を使用します。

class Main: 
    def meth1(self): 
     for c in Holder._subclasses__(): 
      #do something 

    def meth2(self): 
     for c in Holder._subclasses__(): 
      #do something 

class Holder(object): 
    pass 

class Class1(Holder): 
    pass 

class Class2(Holder): 
    pass 

class Class3(Holder): 
    pass 

あなたも、それらのサブクラスの作ることができますMainあなたがしたかった、そしてクラスメソッドでそれらを引く場合:

class Main(object): 
    @classmethod 
    def meth1(cls): 
     for c in cls._subclasses__(): 
      #do something 

class Class1(Main): pass 

あなたが仕事に、このためのPython 2とobjectから継承する必要があります。

2

あなたのリストは、モジュール内の使用可能なクラスのサブセットをターゲットにしているようです。したがって、ある時点で、ターゲットとするクラスを指定する必要があります。

import sys 

target_classes = ["Class1", "Class3"] 

class Main: 
    def __init__(self, classes): 
     self.target_classes = classes 

    def meth1(self): 
     for s in self.target_classes: 
      C = getattr(sys.modules[__name__], s) 
      C().speak() 

    def meth2(self): 
     for c in classes: 
      print c 
      #do something 

class Class1: 
    def speak(self): 
     print "woof" 

class Class2: 
    def speak(self): 
     print "squeak" 

class Class3: 
    def speak(self): 
     print "meow" 


Main(target_classes).meth1() 

--output:-- 
woof 
meow 
関連する問題