<p>主要目标:自动注册工厂中的类(通过字符串),以便在运行时使用该字符串动态创建,类可以在自己的文件中,而不是分组在一个文件中。在</p>
<p>我有几个类都继承自同一个基类,它们定义了一个字符串作为它们的类型。在</p>
<p>用户希望获得这些类之一的实例,但在运行时只知道类型。在</p>
<p>因此,我有一个工厂来创建一个给定类型的实例。
我不想硬编码“if-then语句”,所以我有一个元类来注册基类的所有子类:</p>
<pre><code>class MetaRegister(type):
# we use __init__ rather than __new__ here because we want
# to modify attributes of the class *after* they have been
# created
def __init__(cls, name, bases, dct):
if not hasattr(cls, 'registry'):
# this is the base class. Create an empty registry
cls.registry = {}
else:
# this is a derived class. Add cls to the registry
interface_id = cls().get_model_type()
cls.registry[interface_id] = cls
super(MetaRegister, cls).__init__(name, bases, dct)
</code></pre>
<p>问题是,要使其工作,工厂必须导入所有的子类(因此元类运行)。
要修复此问题,可以使用<code>from X import *</code>
但要实现这一点,您需要在包的<code>__init__.py</code>文件中定义一个<code>__all__</code>var来包含所有的子类。在</p>
<p>我不想对子类进行硬编码,因为它违背了使用元类的目的。在</p>
<p>我可以使用以下方法查看包中的文件:</p>
^{pr2}$
<p>这很好,<strong>但是</strong>项目需要编译成一个.so文件,这就取消了文件系统的使用。在</p>
<p>那么,如何才能实现在运行时创建实例而不必对类型进行硬编码的主要目标呢?在</p>
<p>有没有一种方法可以在运行时填充一个<code>__all__</code>var而不接触文件系统?在</p>
<p>在Java中,我可能会用一个注释来修饰类,然后在运行时得到所有带有该注释的类,python上有类似的东西吗?在</p>
<p>我知道python中有decorator,但我不确定是否可以用这种方式使用它们。在</p>
<p>编辑1:
每个子类必须在一个文件中:</p>
<pre><code>- Models
-- __init__.py
-- ModelFactory.py
-- Regression
--- __init__.py
--- Base.py
--- Subclass1.py
--- Subclass2ExtendsSubclass1.py
</code></pre>
<p>编辑2:一些代码来说明问题:</p>
<pre><code>+ main.py
|__ Models
|__ __init__.py
|__ ModelFactory.py
|__ Regression
|__ init__.py
|__ Base.py
|__ SubClass.py
|__ ModelRegister.py
main.py
from models.ModelFactory import ModelFactory
if __name__ == '__main__':
ModelFactory()
ModelFactory.py
from models.regression.Base import registry
import models.regression
class ModelFactory(object):
def get(self, some_type):
return registry[some_type]
ModelRegister.py
class ModelRegister(type):
# we use __init__ rather than __new__ here because we want
# to modify attributes of the class *after* they have been
# created
def __init__(cls, name, bases, dct):
print cls.__name__
if not hasattr(cls, 'registry'):
# this is the base class. Create an empty registry
cls.registry = {}
else:
# this is a derived class. Add cls to the registry
interface_id = cls().get_model_type()
cls.registry[interface_id] = cls
super(ModelRegister, cls).__init__(name, bases, dct)
Base.py
from models.regression.ModelRegister import ModelRegister
class Base(object):
__metaclass__ = ModelRegister
def get_type(self):
return "BASE"
SubClass.py
from models.regression.Base import Base
class SubClass(Base):
def get_type(self):
return "SUB_CLASS"
</code></pre>
<p>运行它你只能看到“基地”它打印。
使用decorator可以得到相同的结果。在</p>