我遇到了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.pd
main.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.py
并mod2.py
清除 sys.modules 中任何可以缓存全局变量的内容。 在mod1.py
和mod2.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.py
的mod1
和mod2
具有不同版本的base.pandas
,您可以通过添加到main.py
中来验证:
print(mod1.base.pandas is mod2.base.pandas)
如果mod1
和mod2
被运送给您时忘记了它们的全局状态更改可能会发生冲突,则可以在main.py
中对sys.modules
执行类似的操作。 但是,该全局状态缓存在每个导入pandas
的模块或导入pandas
的模块中,该模块现在是mod1
、mod2
、base
和pandas
及其子包/模块。