繁体   English   中英

在Python中使用元类填充Factory

[英]Populating Factory using Metaclasses in Python

显然,在Python中注册类是元类的主要用例。 在这种情况下,我有一个序列化模块,该模块当前使用动态导入来创建类,我更喜欢将其替换为工厂模式。

因此,基本上,它是这样做的:

data = #(Generic class based on serial data)
moduleName = data.getModule()
className = data.getClass()
aModule = __import__(moduleName)
aClass = getattr(aModule, className)

但我希望它这样做:

data = #(Generic class based on serial data)
classKey = data.getFactoryKey()
aClass = factory.getClass(classKey)

但是,有一个障碍:如果我让工厂依赖元类,则工厂仅在导入模块后才知道类的存在(例如,它们是在模块导入时注册的)。 因此,要填充工厂,我必须:

  1. 手动导入所有相关模块(这实际上会破坏让元类自动注册事物的目的……)或
  2. 自动导入整个项目中的所有内容(这让我感到难以置信且笨拙)。

在这些选项中,将类直接注册到工厂似乎是最好的选择。 有没有人找到我没有看到的更好的解决方案? 一种选择可能是通过遍历项目文件来自动生成工厂模块中所需的导入,但是除非您使用提交钩子来执行此操作,否则可能会导致工厂过时的风险。

更新:

我发布了一个自我解答,以结束此问题。 如果有人知道一种很好的方式来遍历嵌套子包中的所有Python模块,而且这种方式永远不会发生循环,那么我将很乐意接受该答案,而不是这个答案。 我看到发生的主要问题是:

\A.py (import Sub.S2)
\Sub\S1.py (import A)
\Sub\S2.py
\Sub\S3.py (import Sub.S2)

当您尝试导入S3时,它首先需要导入Main(否则将不知道Sub是什么)。 此时,它尝试导入A。在那里,将调用__init__.py ,并尝试注册A。这时,A尝试导入S1。 由于Sub中的__init__.py被命中,因此它将尝试导入S1,S2和S3。 但是,S1想要导入A(它尚不存在,因为它正在导入中)! 因此导入失败。 您可以切换遍历的方式(即深度优先而不是广度优先),但是遇到相同的问题。 对此有很好的遍历方法的任何见解都将非常有帮助。 两阶段方法可能可以解决该问题(即遍历以获取所有模块引用,然后作为统一批处理导入)。 但是,我不太确定处理最后阶段的最佳方法(即知道何时完成遍历然后再导入所有内容)。 我的最大限制是我不想拥有一个超级包来处理(即Sub和A下的一个额外目录)。 如果我这样做了,它可能会开始遍历,但是所有的导入都没有充分的理由(例如,所有的导入都需要一个额外的目录)。 到目前为止,向sitecustomize.py添加一个特殊的函数调用似乎是我唯一的选择(无论如何,我还是在该文件中为软件包开发设置了根目录)。

我发现的解决方案是基于特定的基本目录对软件包进行所有导入,并对所有可能具有要注册的类的模块具有特殊的__init__.py函数。 因此,基本上,如果您导入任何模块,则它首先必须导入基本目录,然后继续遍历每个具有类似__init__.py文件的软件包(即文件夹)。

这种方法的缺点是有时会多次导入相同的模块,如果有人在模块导入中留下带有副作用的代码,这将很烦人。 但是,这两种方法都不好。 不幸的是,如果您这样做,某些主要软件包(咳嗽,咳嗽:烧瓶)会对IDLE造成严重的投诉(IDLE只是重新启动,而不是做任何事情)。 另一个缺点是,由于模块彼此导入,因此有时它会尝试导入已经在导入过程中的模块(一个容易捕获的错误,但我仍在尝试淘汰)。 这并不理想,但是确实可以完成工作。 附件中附有有关更具体问题的其他详细信息,如果有人可以提供更好的答案,我将很乐意接受。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM