【问题标题】:'import' operation behaves differently if I name script 'string.py' or 'math.py'. Why it so?如果我将脚本命名为“string.py”或“math.py”,“导入”操作的行为会有所不同。为什么会这样?
【发布时间】:2021-03-27 20:03:20
【问题描述】:

更新:

案例 1:

同一文件夹中的文件:

ma​​in.py

string.py

ma​​in.py中的代码:

import string

string.py中的代码:

print('Hello!')

运行 ma​​in.py 输出是:Hello!

案例 2:

同一文件夹中的文件:

ma​​in.py

ma​​th.py

ma​​in.py中的代码:

import math

ma​​th.py 中的代码:

print('Hello!')

运行 ma​​in.py 输出什么都没有...

老问题:

如果我将我的脚本命名为“string.py”并将其导入另一个脚本,它会与内置的“string”模块重叠

如果我将我的脚本命名为“math.py”并将其导入另一个脚本,则内置的“数学”会与我自己的重叠

使用内置模块等名称的脚本导入行为取决于我如何命名它们。

一些受影响的模块名称:hashlib、字符串、日历

不影响的模块名称:math、cmath、os

来自realpython.com

Python 要做的第一件事是在 sys.modules 中查找名称 abc。 这是之前导入的所有模块的缓存。如果 在模块缓存中找不到该名称,Python 将继续 搜索内置模块列表。这些是来的模块 预装 Python,可在 Python 标准中找到 图书馆。如果在内置模块中仍未找到该名称,则 Python 然后在 sys.path 定义的目录列表中搜索它。

来自 Michael Lutz 的“Learning Python”:

大致来说,Python 的模块搜索路径是由串联组成的 在这些主要组件中,有些是为您预设的,有些是为您预先设置的 你可以定制其中的一个来告诉 Python 去哪里看:

  1. 程序的主目录

  2. PYTHONPATH 目录(如果已设置)

  3. 标准库目录

  4. 任何 .pth 文件的内容(如果存在)

  5. 第三方扩展的站点包主页

那么现在哪一个是正确的?

【问题讨论】:

  • 您能否提供重现您所询问行为的示例代码?无论模块的名称如何,您都应该看到相同的行为,这表明这里还有更多的东西在起作用。
  • @larsks 感谢您的回答。我更新了问题。现在应该清楚了
  • @larsks 感谢您的回答。我更新了问题。现在应该清楚了

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


【解决方案1】:

math 和 string 的区别在于 math 是用 C 编写的,目的是提高速度,而 string 模块是用 Python 编写的,可以在 python lib 目录下找到。

因此,当您尝试导入字符串时,本地文件将覆盖全局字符串文件,但当您尝试导入数学时,Python 不会搜索文件,因为它是内置在 Python 解释器中的。

您可以使用以下代码找到所有内置模块的列表:

import sys
print(sys.builtin_module_names)

如果您真的想覆盖数学模块,可以通过更改 sys.modules 字典中的值来实现。

【讨论】:

  • 这似乎不正确,至少在 Python 3 中是这样。如果我在本地目录和 import math 中创建 math.py,我会得到本地 math.py 文件。
  • @larsks 你能分享你的完整代码吗?带有“import math”的简单“main.py”;带有空“math.py”的 print(math)”按预期工作(内置导入)。
【解决方案2】:

我不相信@ZacharyaHaitin 的回答是正确的,而且我很确定如果凯伦真的看到了问题中描述的行为,那么肯定还有其他事情发生。

让我们来看看一些例子......

覆盖string 模块

我们有一个包含两个文件的空目录:

$ ls
main.py string.py

文件main.py 包含:

$ cat main.py
import string

文件string.py 包含:

$ cat math.py
print('hello')

当我们运行main.py 时,我们看到:

$ python main.py
hello

覆盖math 模块

如果我们对math 执行相同的实验,我们会看到相同的行为。这里是main.py

$ cat main.py
import math

这里是math.py

$ cat math.py
print('hello')

当我们运行main.py 时,我们看到的行为与我们在上一个示例中看到的相同:

$ python main.py
hello

以上示例与 Python2 和 Python3 的行为相同。在这两种情况下都没有必要与sys.modules 混在一起。


这是一个重现上述示例的脚本:

#!/bin/sh

echo "Overriding string module"

cat > main.py << EOF
import string
EOF

cat > string.py <<EOF
print('hello')
EOF

echo "main.py"
echo "-------"
cat main.py
echo

echo "string.py"
echo "---------"
echo
cat string.py
echo

echo "Running main.py..."
python main.py

cat <<EOF

======================================================================

EOF

echo "Overriding math module"

cat > main.py << EOF
import math
EOF

cat > math.py <<EOF
print('hello')
EOF

echo "main.py"
echo "-------"
cat main.py
echo

echo "math.py"
echo "---------"
echo
cat math.py
echo

echo "Running main.py..."
python main.py

【讨论】:

  • 我已经在 Ubuntu 和 Windows 10 以及两个版本的 Python(2 和 3)中进行了检查,无论文件夹是否为空。在“数学”的情况下,我没有得到任何输出。如 realpython.com 中所述:“ ...如果在模块缓存中找不到该名称,Python 将继续搜索内置模块列表。这些是 Python 预装的模块,可以在 Python 标准库中找到..." 所以如果我打印出 sys.builtin_module_names,我会看到 'math' 但看不到 'string'。我在解释器的文件夹中也没有看到模块'math.py'('string.py' 存在)
  • 如果您运行我在此处包含的测试脚本,它对您产生的结果与对我产生的结果不同,请告诉我。
  • 还是一样。在第一种情况下 - 第二个是“你好” - 什么都没有
  • 但是sys.builtin_module_names 中有'math' 吗?因为我,与其他答案所说的不同,而且我的行为与您所观察到的一样。相反,如果我将名称更改为 time.py(并且 'time' 在我的内置模块中!),我会看到 Karen 观察到的行为。所以我认为 Zacharya 的回答可能是正确的。
  • @KonradRudolph 也许我们运行不同版本的 Python 解释器?在我的解释器中,模块“数学”包含在 sys.builtin_module_names
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-03
  • 1970-01-01
  • 2019-12-25
  • 2012-05-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多