如何强制 python 导入模块依赖项的独立副本?



我遇到了pandas.DataFrame.to_html()依赖于全局状态的问题,正如其他问题中所引用的那样。 这些问题的解决方案有点笨拙,要么修改全局属性,然后还原它,要么将数据帧的内容存储在其他地方并在转换后将它们重新插入到 html 中。 此外,这些问题暗示了一个更普遍的问题:是否可以相互隔离地加载模块及其依赖项?

下面有一个 MWE。 当main.py运行时,它会导入mod1,这将设置 pandas 属性。 接下来导入mod2,识别pandas已加载。 然后,它使用该熊猫的实例化并重置属性。 因此,当main.py稍后调用mod1的函数时,mod1看到属性mod2离开它。 这意味着依赖pandas.to_html()mod1.bar()的行为符合mod2所禁止的。 我们可以签入该mod1.base.pd is mod2.base.pdmain.py(返回 True(。

我可以在mod1中指定我要导入base的干净副本(它是依赖项,pandas(以便mod1.base.pd is not mod2.base.pd吗? 我在importlib中看到的任何东西都不允许这样做。sys.modules暗示了某种神秘的诡计,但不确定这是否涵盖这种情况:

可以操纵此 [sys.modules] 来强制重新加载模块和其他技巧。

如果做不到,那么处理这种情况的风格正确方法是什么? 将全局赋值/set_option移动到每个函数(bar()baz()(中是可行的,但如果有多种函数依赖于to_html(),因此也依赖于全局状态,这似乎很乏味且容易出错。 我可以DataFrame.to_html(*args)包装到一个新的函数df_to_html(df, temporary_state, *args)中,该函数处理模块选项的设置和重置,只需调用此函数而不是to_html(),但如果有更多依赖于该选项的函数,那将同样很乏味。

base.py

import pandas as pd
def foo():
return pd.DataFrame([["Looooooooooooooooooooooooooooooooong","a"],
["b","Texxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxt"]], 
columns=['A','B'])

mod1.py

import base
base.pd.set_option('display.max_colwidth',8)
def bar():
return base.foo().loc[:,['A']].to_html()

mod2.py

import base
base.pd.set_option('display.max_colwidth',5)
def baz():
return base.foo().loc[:,['B']].to_html()

main.py

import mod1
import mod2
def qux():
while input():
print(mod1.bar())
print(mod2.baz())
if __name__=='__main__':
qux()

输出

<table border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
<th></th>
<th>A</th>
</tr>
</thead>
<tbody>
<tr>
<th>0</th>
<td>L...</td>
</tr>
<tr>
<th>1</th>
<td>b</td>
</tr>
</tbody>
</table>
<table border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
<th></th>
<th>B</th>
</tr>
</thead>
<tbody>
<tr>
<th>0</th>
<td>a</td>
</tr>
<tr>
<th>1</th>
<td>T...</td>
</tr>
</tbody>
</table>

从那以后,我学会了我在问题中提到的技巧,是的,这是可能的。 您需要mod1.pymod2.py清除 sys.modules 中任何可以缓存全局变量的内容。 在mod1.pymod2.py中,在import base之前添加以下文本:

[sys.modules.pop(key) for key in sys.modules.keys() if 'pandas' in key]
try:
sys.modules.pop('base')
except KeyError:
pass

然后,main.pymod1mod2具有不同版本的base.pandas,您可以通过添加到main.py中来验证:

print(mod1.base.pandas is mod2.base.pandas)

如果mod1mod2被运送给您时忘记了它们的全局状态更改可能会发生冲突,则可以在main.py中对sys.modules执行类似的操作。 但是,该全局状态缓存在每个导入pandas的模块或导入pandas的模块中,该模块现在是mod1mod2basepandas及其子包/模块。

相关内容

  • 没有找到相关文章

最新更新