【发布时间】:2018-03-10 16:24:21
【问题描述】:
编辑:我应该指定我(卡住)使用 Python 2 工作,但有兴趣看看如何在 2 或 3 中解决这个问题
场景:
我有一个名为shapes 的包。
我在shapes 中有一个名为factory 的模块,它有一个ShapeClassFactory 类。
这个类可以传递一个字符串,它会在远程数据库中查找数据并使用它来动态定义一个类,然后返回。
shapes.py:
from .factory import ShapeClassFactory
__all__ = ['ShapeClassFactory']
实际上,这个包可以用在各种其他包和脚本中,如下所示:
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)
...这个想法是,如果在shapes 中找不到该成员,它会使用ShapeClassFactory 来尝试生成它。
困难在于可用类在请求之前基本上是未知的,因此预定义的类名列表将无济于事。
如果 ShapeClassFactory 无法构建类,我不介意抛出 ImportError —— 但这样的事情是否可能?
【问题讨论】:
-
import 语句将运行正在导入的模块,然后拉出请求的名称。没有办法事先知道将请求哪些名称。基本上,如果不进行修补
__import__之类的操作(可能使用元挂钩?),您就无法做到这一点,而且您真的不应该这样做。例如, dir(shapes) 做什么?正确的方法是你已经做过的。 -
如果可能生成的类的数量相当少,您可以在
shapes的命名空间中生成每一个。这也是一种标准且合理的方式。 -
我使用生成的类的主要原因之一是如果在远程数据库中定义了新的形状,我想避免更新包,因此定义接受的类列表不是确实是这种情况的解决方案。
-
您实际上可以让这些类自动更新。假设您有一个查询数据库的函数
get_shape_names,我会写一个答案。 -
这是一个有趣的问题。我最初的反应是您已经拥有的工厂设置还不错。当然,对于 Python 来说,这有点冗长,但话又说回来,每个“动态导入”仍然只是多一行,所以实际上,这并不可怕。它的好处是实现简单易懂。那总是值得的,不应该掉以轻心!