【问题标题】:import module with name same as built-in module in python 3导入与python 3中的内置模块名称相同的模块
【发布时间】:2019-07-03 06:18:45
【问题描述】:

我遇到了类似的问题,可以简化如下:

例如我的文件结构如下:

----folder
    ---- main.py
    ---- math.py

我在math.py 中定义了一个函数,我想在main.py 中导入这个math.py。

math.py中的代码如下

# math.py
def f(x) :
    return x**3

如果我在main.py 中编写代码如下

# main.py
import math

def main() :
    print(math.f(3))

if __name__ == "__main__":
    main()

然后它返回AttributeError: module 'math' has no attribute 'f'

如果我在main.py 中编写代码如下

# main.py
from . import math

def main() :
    print(math.f(3))

if __name__ == "__main__":
    main()

然后返回ImportError: cannot import name 'math' from '__main__' (main.py)

我的问题:

  1. 如果我只想在路径folder中导入与内置模块同名的模块math.py,该怎么办?

  2. 如果在main.py 中我想同时使用math.py 中定义的math.f(x) 和内置math.acos(x),我该怎么办?

PS:我遇到了类似的问题,因为我十年前有人写了很长的代码。当时并没有这样名字的内置模块(其实不是math模块。我只是通过上面的问题简化了问题)。并且这个模块的功能已经在很多地方使用。因此几乎不可能更改模块的名称,因为如果是这样,我需要仔细更改所有站点module.function()。

【问题讨论】:

    标签: python-3.x import python-import


    【解决方案1】:

    在内置模块之后命名模块是非常糟糕的做法。我建议您将 math.py 命名为其他名称。

    话虽如此,您可以使用带有 imp 的路径导入它:

    import imp
    math = imp.load_source('math', './math.py')
    

    【讨论】:

    • 这不是我当前的代码。其实同名的不是math.py。有人用python2写了很长的代码,当时还没有这个模块。
    【解决方案2】:

    进入一个兔子洞,但我们开始了。作为免责声明,就像 Jack 所说的在 builtins 之后命名模块是非常糟糕的做法,这可以更容易地按照他的建议使用 imp 完成。

    您遇到问题的原因来自一些事情的相互作用。当你输入

    import math
    

    你的 python 所做的是查看 sys.path。它将检查 sys.path 中名为 math 的模块的所有位置,并导入它找到的第一个模块。在您的情况下,它首先找到您的本地数学模块。导入完成后,它会将其添加到 sys.modules 中,但我们会回到那个。

    由于您想同时使用两者,首先您可以导入本地数学。我建议将其作为不同的名称导入以保持独立。

    from . import math as local_math
    

    在那之后,我们需要弄乱我们的 sys.path 来找到内置的数学

    sys.path = sys.path[::-1]
    

    这会颠倒 sys.path 的顺序,这意味着它将首先查找您的本地目录而不是最后一个。

    现在您可能认为这已经足够了,但是如果您尝试在此处导入数学,python 会在 sys.modules 中看到它,而不必费心再次尝试导入,所以首先

    del sys.modules['math']
    

    然后我们可以导入默认的数学模块

    import math
    

    最后清理我们的 sys.path

    sys.path = sys.path[::-1]
    

    现在我们可以访问我们需要的一切

    >>>math.cos(10)
    -0.8390715290764524
    >>>local_math.f(10)
    1000
    

    【讨论】:

    • 谢谢。我遇到了类似的问题,因为我十年前有人写了很长的代码。当时还没有这样名字的内置模块(其实不是math模块。我只是通过上面的问题简化了问题)。并且这个模块的功能已经在很多地方使用。因此几乎不可能更改模块的名称,因为如果这样我需要仔细更改所有站点module.function()。
    猜你喜欢
    • 2020-01-26
    • 1970-01-01
    • 1970-01-01
    • 2020-04-04
    • 2010-11-16
    • 1970-01-01
    • 2011-10-29
    • 2014-06-15
    • 1970-01-01
    相关资源
    最近更新 更多