2010-07-05 58 views
3

我正在開發一個Python 2.6包,其中我想獲取某個目錄(包內)中的所有類的列表,以便隨後對類對象執行內省。目錄中的列表類(Python)

具體來說,如果包含當前正在執行模塊的目錄中有一個子目錄名爲「foobar的」和「foobar的」包含.py文件指定class Foo(MyBase)class Bar(MyBase)class Bar2,我想獲得的類引用列表從MyBase繼承的對象,即FooBar,但不是Bar2

我不確定這個任務實際上是否需要涉及任何文件系統的處理,或者子目錄中的模塊是否自動加載,並且只是需要通過內省以某種方式列出。這裏有什麼想法嗎?示例代碼非常感謝,因爲我對Python很陌生,特別是自省。

回答

4

模塊是不會自動加載,但它應該很容易遍歷目錄中的模塊,並與__import__內置函數加載它們:

import os 
import glob 
for file in glob(os.path.join(os.path.dirname(os.path.abspath(__file__))), "*.py"): 
    name = os.path.splitext(os.path.basename(file))[0] 
    # add package prefix to name, if required 
    module = __import__(name) 
    for member in dir(module): 
     # do something with the member named ``member`` 
+0

啊,'__import__'函數看起來非常有用,謝謝你。 – Noldorin 2010-07-05 09:25:11

+1

不是所有的成員都必須是類。 – mtnpaul 2011-11-10 21:01:35

2

選項1:grep的爲 「^類(\一個\ W +)\(MYCLASS」 正則表達式與-r參數

選項2:使目錄包(創建一個空__init__.py文件),導入並對其成員遞歸迭代:

import mymodule 
def itermodule(mod): 
    for member in dir(mymod): 
     ... 

itermodule(mymodule) 
+0

不知道怎麼的grep-ING幫助的實現,雖然我相信這只是我的無知。我如何在Python中做到這一點,然後獲取類對象?第二種方案看起來不錯 – Noldorin 2010-07-05 09:24:45

+0

我認爲grep是爲了找到所有包含'class'的文件(包含class的文件)​​,例如'egrep -ir --include = * .py「class」.'給出了這些文件的列表,你可以將它們轉換成Python導入 – Mark 2013-07-20 22:09:24

-1

在有egrep的平臺:

from subprocess import Popen, PIPE 
from re import search 

def get_classes(directory): 
    job = Popen(['egrep', '-ir', '--include=*.py', 'class ', str(directory), ], stdout=PIPE) 
    fileout, fileerr = job.communicate() 
    if fileerr: 
     raise Exception(fileerr) 
    while directory[-1] == '/': 
     directory = directory[:-1] 
    found = [] 
    for line in fileout.split('\n'): 
     match = search('^([^:]+).py:\s*class\s*(\S+)\s*\((\S+)\):', line) 
     if match: 
      pypath = match.group(1).replace(directory, '').replace('/', '.')[1:] 
      cls = match.group(2) 
      parents = filter(lambda x: x.strip, match.group(3).split()) 
      found.append((pypath, cls, parents,)) 
    return found 

get_classes('.'),egrep的返回是這樣的:

./helpers/action.py:class Action(object): 
./helpers/get_classes.py: job = Popen(['egrep', '-ir', '--include=*.py', 'class ', str(directory), ], stdout=PIPE) # this is the get_classes script; not a valid result 
./helpers/options.py:class Option(object): 

被轉換成路徑,類名的元組和直系祖先:

[('helpers.action', 'Action', ['object']), ('helpers.options', 'Option', ['object'])] 

如果你只是想要的路徑,這是[item[0] for item in get_classes('.')]

+0

-1表示平臺依賴性和子流程 – 2014-11-09 16:34:14

1

我想做同樣的事情,這是我結束了:

import glob 
import importlib 
import inspect 
import os 

current_dir = os.path.join(os.path.dirname(os.path.abspath(__file__))) 
current_module_name = os.path.splitext(os.path.basename(current_dir))[0] 
for file in glob.glob(current_dir + "/*.py"): 
    name = os.path.splitext(os.path.basename(file))[0] 

    # Ignore __ files 
    if name.startswith("__"): 
     continue 
    module = importlib.import_module("." + name,package=current_module_name) 

    for member in dir(module): 
     handler_class = getattr(module, member) 

     if handler_class and inspect.isclass(handler_class): 
      print member 

希望它可以幫助..

0

用它處理我自己,這是我的版本(分叉@krakover片段):

  • 迭代目錄,並導入每個腳本放在那裏
    • 過濾掉抽象類
    • 濾除類,不繼承基類
    • 每個迭代類的新實例(如果您覺得沒有用,請更改它)

import importlib 
import inspect 
import os 
import glob 


def import_plugins(plugins_package_directory_path, base_class=None, create_instance=True, filter_abstract=True): 

    plugins_package_name = os.path.basename(plugins_package_directory_path) 

    # ----------------------------- 
    # Iterate all python files within that directory 
    plugin_file_paths = glob.glob(os.path.join(plugins_package_directory_path, "*.py")) 
    for plugin_file_path in plugin_file_paths: 
     plugin_file_name = os.path.basename(plugin_file_path) 

     module_name = os.path.splitext(plugin_file_name)[0] 

     if module_name.startswith("__"): 
      continue 

     # ----------------------------- 
     # Import python file 

     module = importlib.import_module("." + module_name, package=plugins_package_name) 

     # ----------------------------- 
     # Iterate items inside imported python file 

     for item in dir(module): 
      value = getattr(module, item) 
      if not value: 
       continue 

      if not inspect.isclass(value): 
       continue 

      if filter_abstract and inspect.isabstract(value): 
       continue 

      if base_class is not None: 
       if type(value) != type(base_class): 
        continue 

      # ----------------------------- 
      # Instantiate/return type (depends on create_instance) 

      yield value() if create_instance else value 

用法:

SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) 
plugins_directory_path = os.path.join(SCRIPT_DIR, 'plugins') 
plugins = import_plugins(plugins_directory_path, base_class=BasePlugin) 

for plugin in plugins: 
    plugin.foo() 
  • 想象有一個名爲plugins子目錄包含BasePlugin