1

我正在尝试实现一个工厂函数,该函数创建给定基类的子类(现在与其名称的字符串相比)。我有这个

class Base(object):
    ...

另一个文件中我有

class Sub(Base):
    ...

我将这些类分成文件,因为我将有许多子类,并且我不想将它们全部定义在一个大文件中(如果可能的话,我会满足于前向声明)。

现在在“基础”文件中,我想实现一个函数来用给定的名称创建一个实例,但是Base.__subclasses__()没有,所以我不能做这样的事情:

def factory(name):
    for Subclass in Base.__subclasses__()
        if name is ...
            return Subclass()

我的问题是实现这种模式的最佳方法是什么。将来我想将其更改为可能使用哈希表,但我无法让这个简单的“基于字符串”的示例正常工作。

4

2 回答 2

1

您应该意识到只有当解释器读取其定义时,您的类才开始存在。因此,必须首先导入具有该类的模块。

如果您的所有子类都位于一个文件中,则只需在执行其他操作之前导入它,以便读取定义。如果子类在多个文件中,您将需要某种动态导入

而且你不需要__subclassess__你所描述的,有一个名字就足够了。当然,如果您的最终目标实际上是实例化所有子类,那么您将需要它,但同样,子类__subclassess__只有在读取其定义时才会出现,即导入其模块。

于 2013-05-31T12:17:06.080 回答
0

如果您想要的是“最佳模式”,请考虑使用and的入口点功能。这可能需要您使用正确的方法来制作鸡蛋可分发包。在名为add 的文件中:setuptoolspkg_resourcessetup.pysetup.py

from setuptools import setup, find_packages
setup(
    name="HelloWorld",
    version="0.1",
    packages=find_packages(),
    entry_points={'my_subclasses': [
        "foo = package.module1:Foo",
        "bar = package.module2:Bar",
    ]}
)

当你黑客攻击时,安装你的包

# python setup.py develop

或者,如果您使用 virtualenv:

$ pip install -e . 

然后,您的工厂函数变得非常简单,实际上它只是调用 pkg_resources 来完成所有工作。

from pkg_resources import iter_entry_points

def factory(name):
    entry_point = iter_entry_points('my_subclasses', name)
    cls = entry_point.load()
    # create an instance?
    return cls()

这种方法有几个优点;最大的是,您库的其他用户可以通过在同一组中安装自己的带有入口点的鸡蛋来提供自己的实现('my_subclasses'在示例中)

另一个优点是不需要导入未使用的模块,只需要导入工厂返回的类。

如果您不想手动维护入口点列表,除了实际创建它们;这setup.py是一个普通的python脚本,可以通过全部导入或遍历文件系统来执行代码来查找所有类。

于 2013-05-31T12:40:49.950 回答