从python中的文件返回类的实例

时间:2010-01-28 00:40:55

标签: python

在我的程序中,我有一个包含各种.py文件的包,每个包含一个类定义。我想列出一个列表,其中每个条目都是其中一个类的实例。另外,我的程序不知道包中有多少文件或者调用了什么文件或类,所以我不能只导入每个文件。理想情况下,我应该能够修改包的内容(取出文件,放入新文件等),而不必重写程序的其他部分。有没有办法做到这一点?

最初,我有一个'if __name__ =='__ main__':在每个文件中返回foo()'行并尝试使用execfile()附加到列表中,但显然这不起作用。有什么想法吗?

对不起,如果这有点模糊。如果需要,我会尽力澄清。我正在使用Python 2.5.4。

编辑:

我的程序是“龙与地下城”的随机字符生成器。我为程序需要的每个主要数据类型创建了一个包。我有一个Classes,Races,Items等的包。在创建一个角色时,我的程序会列出每个数据类型,它可以在制作角色时进行排序。例如,在装备角色时,程序可以查看武器列表并过滤掉不适合该角色的所有武器,然后从剩余的武器中随机选择。

我不想指定文件名,因为我希望以后能够轻松添加到此程序中。如果以后我想在程序中添加更多的武器类型,我可以写一些新的类描述并将它们放入Weapons包中,程序可以使用它们,而无需我编辑任何其他代码。 / p>

4 个答案:

答案 0 :(得分:2)

这听起来有点糟糕。如果您详细说明问题可能会更好,我们可以帮助您以其他方式解决问题。但是,你想要的并不难:

import types
import my_package

my_package_members = [getattr(my_package, i) for i in dir(my_package)]
my_modules = [i for i in my_package_members if type(i) == types.ModuleType]

instances = []

for my_module in my_modules:
    my_module_members = [getattr(my_module, i) for i in dir(my_module)]
    my_classes = [i for i in my_module_members
                  if type(i) in (types.TypeType, types.ClassType)]
    for my_class in my_classes:
        instances.append(my_class())

编辑:稍微简化了代码。

答案 1 :(得分:0)

要实现这一点,您需要做以下事情:

  • 让您的代码枚举包含您代码的源文件。
  • 对于每个源文件,将文件中指定的代码导入新模块。
  • 对于每个模块,找到包含的所有类,实例化每个类并将其添加到最终列表中。

轮流拍摄每个部分:

  • 要枚举源文件,请使用os.walkos.path查找文件并构建源的完整路径。
  • 要动态导入给定源文件中的代码,您可以执行execfile(my_file) in my_dict,其中my_file是源文件的完整路径,my_dict是一个字典,用于返回结果代码(例如,在源文件中声明的任何类都将成为此dict的成员)。请注意,如果要导入的文件不是有效的python模块/包层次结构(包中包含 init .py文件),则只需要使用此方法 - 如果它们可以使用而是import()
  • 要枚举在给定模块中声明的类,您可以使用inspect.getmembers()

答案 2 :(得分:0)

如果您愿意做更多工作,可以使用pkg_resource's entry points来宣传和发现相关课程。 Fedora帐户系统uses this提供plugin functionality

答案 3 :(得分:0)

首先,假设所有模块都作为.py文件存在于软件包的目录中:

import inspect, glob, os, sys

def thelistyouwant(pathtothepackage):
  sys.path.insert(0, pathtothepackage)
  result = []
  for fn in glob.glob(os.path.join(pathtothepackage, '*.py')):
    if fn.startswith('_'): continue   # no __init__ or other private modules
    m = __import__(fn[:-3])
    classes = inspect.getmembers(m, inspect.isclass)
    if len(classes) != 1:
      print>>sys.stderr, "Skipping %s (%d != 1 classes!)" % (fn, len(classes))
      continue
    n, c = classes[0]
    try:
      result.append(c())
    except TypeError:
      print>>sys.stderr, "Skipping %s, can't build a %s()" % (fn, n)

  del sys.path[0]           
  return result

进一步的假设:每个模块应该只有1个类(否则它会被警告跳过),可以在没有参数的情况下进行实例化(ditto ditto);你不想看{​​{1}}(如果有的话;实际上这段代码不要求路径是实际的包,任何目录都可以,所以__init__.py可能存在也可能不存在)也不任何名称以下划线开头的模块(包的“私有”模块)。