Python中的魔法导入
编辑:我应该指定我正在使用Python2,但我很想看看如何在2或3中解决这个问题 场景: 我有一个名为Python中的魔法导入,python,class,dynamic,Python,Class,Dynamic,编辑:我应该指定我正在使用Python2,但我很想看看如何在2或3中解决这个问题 场景: 我有一个名为shapes的软件包 我在shapes中有一个名为factory的模块,它有一个ShapeClassFactory类。 该类可以被传递一个字符串,它将在远程数据库中查找数据,并使用该数据动态定义一个类,然后返回该类 shapes.py: from .factory import ShapeClassFactory __all__ = ['ShapeClassFactory'] from .fa
shapes
的软件包
我在shapes
中有一个名为factory
的模块,它有一个ShapeClassFactory
类。
该类可以被传递一个字符串,它将在远程数据库中查找数据,并使用该数据动态定义一个类,然后返回该类
shapes.py:
from .factory import ShapeClassFactory
__all__ = ['ShapeClassFactory']
from .factory import ShapeClassFactory
__all__ = ['ShapeClassFactory']
def get_shape_names():
"""Returns all valid shapes that can be passed in to ShapeClassFactory"""
return ['Circle', 'Rect'] # your own code should query the database
for name in get_shape_names():
globals()[name] = ShapeClassFactory(name)
__all__.append(name)
实际上,该软件包可用于各种其他软件包和脚本中,例如:
from shapes import ShapeClassFactory
Circle = ShapeClassFactory("Circle")
Rect = ShapeClassFactory("Rect")
myCircle = Circle(r=5, fill='red')
mySquare = Rect(x=5, y=5, fill=None)
问题:
以上都很好。但是,我希望能够以这样的方式编写shapes
包:
from shapes import Circle, Rect
myCircle = Circle(r=5, fill='red')
mySquare = Rect(x=5, y=5, fill=None)
…其思想是,如果在形状
中找不到该成员,它将使用形状关联工厂
尝试生成该成员
困难在于,在被请求之前,可用类基本上是未知的,因此预定义的类名列表没有帮助
如果
ShapeClassFactory
无法构建类,我不介意抛出一个ImportError
,但这样做可能吗?您可以在初始化时自动在shapes
命名空间中构建所有可能的对象,只要没有太多可能的类,并且预先初始化类的成本不会太高。您可以在shapes.py中使用如下代码:
from .factory import ShapeClassFactory
__all__ = ['ShapeClassFactory']
from .factory import ShapeClassFactory
__all__ = ['ShapeClassFactory']
def get_shape_names():
"""Returns all valid shapes that can be passed in to ShapeClassFactory"""
return ['Circle', 'Rect'] # your own code should query the database
for name in get_shape_names():
globals()[name] = ShapeClassFactory(name)
__all__.append(name)
import语句将运行正在导入的模块,然后提取请求的名称。没有办法事先知道会要求什么名字。基本上,如果不做修补
\uuuuuu导入\uuuuuuu
(可能是使用元钩子?)之类的事情,您就无法做到这一点,而且您真的不应该这么做。例如,dir(shapes)做什么?正确的方法是您已经完成的操作。如果可能生成的类数量相当少,您可以在形状的命名空间中生成它们中的每一个。这也是一种标准且合理的方法。我使用生成类的主要原因之一是,如果在远程数据库中定义了新形状,我希望避免必须更新包,因此定义接受类的列表并不是这种情况的真正解决方案。实际上,您可以让这些类自动更新。假设你有一个查询数据库的函数get\u shape\u names
,我会写一个答案。这是一个有趣的问题。我最初的反应是,你们已经拥有的工厂设置还不错。当然,对于Python来说,这感觉有点冗长,但是再一次,它仍然只是每个“动态导入”增加一行,所以在实际操作中,这并不可怕。它的好处是实现简单易懂。这些东西总是有价值的,不应该轻易扔掉!这样做的问题是,可能有几十个类可用,但通常在单个模块或脚本中只使用2到4个类。因为数据库查询和类构造本身都有很大的成本,所以我只需要生成已请求的类。您可以将类构造的成本转移到实例化上。换句话说,使用中定义的实例变量而不是类变量。这意味着您只需要一个数据库查询就可以获得可能的形状列表,所有其他查询都会在实例化过程中发生。我对在实例级别定义所有属性的想法感觉不太好——除此之外,这并不实用(即,我想要一些类方法),感觉这段代码在可读性和可维护性方面都是一个倒退。在处理大量实例时,它也感觉到了潜在的内存过剩。