Python 3.x 如何强制python导入模块的独立副本';依赖关系?

Python 3.x 如何强制python导入模块的独立副本';依赖关系?,python-3.x,pandas,dataframe,global-variables,Python 3.x,Pandas,Dataframe,Global Variables,我遇到了一个问题,pandas.DataFrame.to_html()依赖于全局状态,如中所述。这些问题的解决方案有些老套,要么修改全局属性,然后将其还原,要么将数据帧的内容存储在其他地方,并在转换后重新插入html。此外,这些问题还暗示了一个更一般的问题:是否可以独立地加载模块及其依赖项 下面有一个MWE。当运行main.py时,它将导入设置pandas属性的mod1mod2,识别已加载的熊猫。然后,它使用熊猫的实例化并重置属性。因此,当main.py以后调用mod1的函数时,mod1将属性视

我遇到了一个问题,
pandas.DataFrame.to_html()
依赖于全局状态,如中所述。这些问题的解决方案有些老套,要么修改全局属性,然后将其还原,要么将数据帧的内容存储在其他地方,并在转换后重新插入html。此外,这些问题还暗示了一个更一般的问题:是否可以独立地加载模块及其依赖项

下面有一个MWE。当运行
main.py
时,它将导入设置pandas属性的
mod1
<接下来导入代码>mod2,识别已加载的
熊猫
。然后,它使用熊猫的实例化并重置属性。因此,当
main.py
以后调用
mod1
的函数时,
mod1
将属性视为
mod2
已离开它。这意味着依赖于
pandas.to_html()
mod1.bar()
,表现为
mod2
禁止。我们可以在
main.py
中检查
mod1.base.pd是否为mod2.base.pd
(返回True)

我是否可以在
mod1
中指定要导入
base
(及其依赖项
pandas
)的干净副本,以便
mod1.base.pd不是mod2.base.pd
?我在
importlib
中看到的任何内容都不允许这样做。暗指某种神秘的诡计,但不确定这是否涵盖本案:

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

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

base.py mod1.py mod2.py main.py 输出

A.
0
L
1.
B
B
0
A.
1.
T

我已经学会了问题中提到的技巧,是的,这是可能的。您需要使
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
执行类似的操作。但是,该全局状态缓存在导入熊猫的每个模块中,或者导入熊猫的模块中,现在是mod1、mod2、base和pandas及其子包/模块,这是可能的。您需要使
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
执行类似的操作。但是,该全局状态缓存在导入熊猫的每个模块中,或者导入熊猫的模块中,即现在的mod1、mod2、base和pandas及其子包/模块函数在调用
到_html()之前设置该选项。
?这肯定比加载一个单独的
pandas
(除了在内存和cpu方面很昂贵之外,要想完全正确地加载,这似乎是有问题的。)@cco我可以。但我的是一个精心设计的最小示例-可能有许多函数依赖于导入模块的全局状态,拦截每一个模块似乎都很容易出错,可能不是最好的方式。强制单独的模块实例的问题是,您需要从
sys.modules
中删除所有依赖项,直到模块没有全局状态的级别(如果存在这样的级别)。对我来说,这似乎比根据需要及时设置全局状态更容易出错(而且代价也更高)。全球国家之所以邪恶,正是因为它导致了这种丑陋的代码;不管怎样,你都会留下丑陋、脆弱的代码。为什么不让
bar()
baz()
函数在调用
到html()之前设置该选项呢?这肯定比加载一个单独的
pandas
(除了在内存和cpu方面很昂贵之外,要想完全正确地加载,这似乎是有问题的。)@cco我可以。但我的是一个做作的,最小的例子-可能有许多函数依赖于导入的mo
<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>
[sys.modules.pop(key) for key in sys.modules.keys() if 'pandas' in key]
try:
    sys.modules.pop('base')
except KeyError:
    pass
print(mod1.base.pandas is mod2.base.pandas)