基于目录名使用importlib加载同名类:后果是啥?
Posted
技术标签:
【中文标题】基于目录名使用importlib加载同名类:后果是啥?【英文标题】:Loading same-named classes with importlib based on directory name: What are the consequences?基于目录名使用importlib加载同名类:后果是什么? 【发布时间】:2021-05-29 19:57:14 【问题描述】:当然,“除了明显的后果之外没有任何后果”是对我关于后果的问题的有效回答。
我帮助维护一个代码库,一些建议的代码结构大致如下:
# main.sh
export PYTHONPATH=$PYTHONPATH:$(pwd)
python main.py "brazil"
python main.py "france"
# main.py
from importlib.util import find_spec, module_from_spec
import sys
class BaseProcessor(object):
# abstract base class
pass
def run_for(country):
spec = find_spec(country + ".processor")
module = module_from_spec(spec)
spec.loader.exec_module(module)
processor = module.CountryProcessor()
processor.do_something()
if __name__ == "__main__":
run_for(sys.argv[1])
# brazil/processor.py
from main import BaseProcessor
class CountryProcessor(BaseProcessor):
def do_something(self):
print("This is the Brazil CountryProcessor")
# france/processor.py
from main import BaseProcessor
class CountryProcessor(BaseProcessor):
def do_something(self):
print("This is the France CountryProcessor")
run_for()
中的代码使用 importlib 根据传入的字符串 country
查找名为 processor 的模块。
输出如设计:
> ./main.sh
This is the Brazil CountryProcessor
This is the France CountryProcessor
我们有一些类似的代码(但使用sys.path.insert()
)已经运行了几个月;我不知道有什么情况是同名的类引起了问题。
如果有的话,这种设计可能会产生什么意想不到的后果?
【问题讨论】:
您的问题到底是什么?您显示一些代码并声明它按预期工作。那么不清楚的部分是什么? 好吧,一方面,您正在使用单独的进程进行迭代,因此类相互混淆的风险相当低。如果您同时运行多个国家/地区,我会考虑在一个函数中加载,然后将其分配给命名空间而不是全局范围。类似someCountry.processor = module.CountryProcessor()
a_guest:有什么后果?从长远来看,运行的代码通常会产生意想不到且可能不受欢迎的后果。我的问题是,这些后果是什么(如果有的话)?
虽然想起来了,但我忘记了软件工程堆栈交换。这是相当特定于 Python 的,所以我不知道它是否更适合那里或这里。
【参考方案1】:
在这里,我回答了我自己的问题,并为以下潜在的意外后果提出了理由。我渴望听到关于现实世界影响的其他意见。可能只是我在床底下看到了怪物。
重要的是要规定,这是我们预计会出现一段时间的代码,整个组件当然比我的玩具示例复杂很多倍。
-
这种方法在以后会产生调试困难。
-
直觉上,它似乎很容易出错:
-
它通常只会增加复杂性,从而增加维护成本。
在现实生活中,我认为这种方法反映了本可以部署到更持久解决方案的编程工作。现在,机会成本可能无关紧要 工作完成了。 (就上下文而言,建议使用此代码替换一些确实使用工厂和静态导入的代码,因此 IMO 的最终效果是引入反模式 一种工作机制。)
建议的替代方案
那么我该如何处理呢?如果导入的数量适中(例如,最多 40 或 50 ),我将使用简单的工厂类(甚至只是函数)对所有子类进行静态导入。 工厂可以维护一个查找表,或者(更好)它可以推断类名。将蛇案例转换为骆驼案例几乎是微不足道的。
如果数字更大,我仍然认为没有理由不加载所有类。只需遍历子目录列表一次,将它们转换为驼峰大小写,然后简单地导入它们 将类名转换为驼峰式。
Python 中额外导入的内存占用是如此微不足道,以至于我认为通常 Python 样式中的多余导入几乎没有缺点。如果由于某种原因 我们想要更明智地导入,我们可以将选择性导入保留在工厂类中,但仍然区分不同类的名称。又是一次 只要我们遵循模式,构造名称几乎是微不足道的。
【讨论】:
以上是关于基于目录名使用importlib加载同名类:后果是啥?的主要内容,如果未能解决你的问题,请参考以下文章
python importlib,如何使动态加载文件的缓存无效
编程艺术python importlib 动态调用 py 脚本方法