2016-08-29 7 views
1

私はパッケージに異なるサブモジュールで定義されたクラスC1, C2, CInvalid3, C4を含んでいます。いくつかの特定のクラスをPythonモジュールで収集します

my_package/ 
    __init__.py 
    sub_package1/ 
     __init__.py 
     sub_module1.py # contains C1, C2 
    sub_package2/ 
     __init__.py 
     sub_module2.py # contains CInvalid3, C4 

あるクラスの名前を含む文字列を指定すると、対応するクラスを初期化します。例えば、

some_valid_class_name = 'C1' 
some_valid_class = all_valid_classes[some_valid_class_name]() 

は現在、私は

all_valid_classes = {} # I want the dict contain C1, C2 and C4 

def this_is_a_valid_class(cls): 
    all_valid_classes[cls.__name__] = cls 
    return cls 

を含むモジュールmy_packageall_classes.pyを作成し、sub_module1.pysub_module2.pyに、私は

from my_package.all_classes import this_is_a_valid_class 

@this_is_a_valid_class 
class C1(object): 
    pass 

を使用して

from .sub_package1 import sub_module1 
from .sub_package2 import sub_module2 
を追加します

~my_package/__init__.py

これを処理する方法はありますか?私はmy_package/__init__.pyにすべてのものをインポートします。新しいsub_package3.sub_module3.C99を追加するときは、from .sub_package3 import sub_module3my_package/__init__.pyに追加することを覚えておく必要があります。私はこれらが良い考えだとは思わない。あなたは何ができるか、あなたが探しているものを手に入れる

答えて

1

はクラス属性を持つマーク有効なクラスにある:

class C1(object): 
    _valid = True 

そして動的に個別に有効なクラスを格納し、パッケージ内のすべてのモジュールをインポートします処理中にall_valid_classes辞書に追加してください。

重要なことは何に関係なく使用したいすべてのクラスのモジュールをインポートする必要があるため、手動で(今やっているように)や動的に(モジュールのファイル名それらをインポートする)。

このスニペットはコンセプトを示しています(実際には醜いことをご了承ください。は概念実証のみを意図しています。それはあなたのmy_module/__init__.pyファイルに行くだろう:

import os 
import fnmatch 
from importlib import import_module 
from types import TypeType 

# dictionary with all valid classes 
all_valid_classes = {} 

# walk directory and load modules dynamically 
this_path = os.path.dirname(__file__) 
modules = [] 
for root, dirnames, filenames in os.walk(this_path): 
    for filename in fnmatch.filter(filenames, '*.py'): 

     # avoid this file importing itself 
     full_path = os.path.join(root, filename) 
     if full_path == os.path.join(this_path, '__init__.py'): 
      continue 

     # convert the filename to the module name 
     trimmed_path = full_path[len(this_path) + 1:-3] 
     module_name = trimmed_path.replace('/', '.') 

     # import the module 
     module = import_module('%s.%s' % (__name__, module_name)) 

     # find valid classes (classes with a '_valid = True' attribute 
     for item_name in dir(module): 
      item = getattr(module, item_name) 
      if type(item) == TypeType: 
       try: 
        valid_attr = getattr(item, '_valid') 
        if valid_attr is True: 
         all_valid_classes[item_name] = item 
       except AttributeError: 
        pass 

my_moduleをインポートした後、all_valid_classesC1C2C4を(彼らは_valid = Trueでマークされている場合)が含まれます。

ps。しかし、あなたがすでにやっているように私は個人的に手作業で輸入していますが、それは私の意見ではもっと無色で清潔です。

+0

FYI、 '__init __。py'は重要なコードを含むことができます(' import foo'は、インポートディレクトリの最上位に 'foo.py'が含まれているか、' __init __。py'を含む 'foo'という名前のディレクトリです。 'foo.py'と' foo/__ init __。py'の内容が同じ場合、 'import foo'も同じように動作します)。 '__init __。py'も処理したいのですが、スキップしません。 – ShadowRanger

+0

@ShadowRangerディレクトリ内のモジュールをインポートすると '__init __。py'ファイルが自動的にインポートされるため、この場合はスキップしません。 – pacha

+1

あなたはそれらをインポートしていますが、クラスのためにそれらをスキャンしていないので、 '__init __。py'でのみ定義されたクラスは見つかりません。クラス定義を '__init__のみに格納する例については、py'、Pythonの 'collections'モジュールを参照してください。 'collections.abc'にないもののPythonの定義は' collections/__ init __。py'だけで見つけられます。 – ShadowRanger

関連する問題