为什么某些文件名不允许用于本地Python源代码文件?

7 浏览
0 Comments

为什么某些文件名不允许用于本地Python源代码文件?

似乎有一些文件名不能与我运行Python源代码的同一目录中的文件同名,因为它们可能与我导入的模块中的同名文件冲突。\n有没有办法保持名称不变但避免异常?\n考虑到Python已经存在了这么久,这个问题似乎很奇怪,而且默认安装的Python也没有避免这个问题,无论导入了哪些模块(例如在copy.py场景中导入了openpyxl,在email.py场景中导入了smtplib)。\n下面是两个示例异常。我的源代码在testing.py文件中。copy.py和email.py文件与testing.py文件在同一目录中。目前,我将它们重命名为copy2.py和email2.py,但这似乎是一个不好的解决方法。\ncopy.py\n

Traceback (most recent call last):
  File "C:\Python\Python37_64\lib\runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "C:\Python\Python37_64\lib\runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "C:\Python\Python37_64\lib\cProfile.py", line 185, in 
    main()
  File "C:\Python\Python37_64\lib\cProfile.py", line 178, in main
    runctx(code, globs, None, options.outfile, options.sort)
  File "C:\Python\Python37_64\lib\cProfile.py", line 20, in runctx
    filename, sort)
  File "C:\Python\Python37_64\lib\profile.py", line 62, in runctx
    prof.runctx(statement, globals, locals)
  File "C:\Python\Python37_64\lib\cProfile.py", line 100, in runctx
    exec(cmd, globals, locals)
  File "C:\GitLab\redcap-p01-etl\testing.py", line 7, in 
    import openpyxl # openpyxl 3.0.7
  File "C:\Python\venv\Python37_64\lib\site-packages\openpyxl\__init__.py", line 6, in 
    from openpyxl.workbook import Workbook
  File "C:\Python\venv\Python37_64\lib\site-packages\openpyxl\workbook\__init__.py", line 4, in 
    from .workbook import Workbook
  File "C:\Python\venv\Python37_64\lib\site-packages\openpyxl\workbook\workbook.py", line 4, in 
    from copy import copy
  File "C:\GitLab\p01\copy.py", line 2
    def parse_slash_copy(const char *args):
    ^
IndentationError: unexpected indent

\nemail.py\n

Traceback (most recent call last):
  File "C:\Python\Python37_64\lib\runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "C:\Python\Python37_64\lib\runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "C:\Python\Python37_64\lib\cProfile.py", line 185, in 
    main()
  File "C:\Python\Python37_64\lib\cProfile.py", line 178, in main
    runctx(code, globs, None, options.outfile, options.sort)
  File "C:\Python\Python37_64\lib\cProfile.py", line 20, in runctx
    filename, sort)
  File "C:\Python\Python37_64\lib\profile.py", line 62, in runctx
    prof.runctx(statement, globals, locals)
  File "C:\Python\Python37_64\lib\cProfile.py", line 100, in runctx
    exec(cmd, globals, locals)
  File "C:\GitLab\p01\testing.py", line 13, in 
    import requests
  File "C:\Python\venv\Python37_64\lib\site-packages\requests\__init__.py", line 43, in 
    import urllib3
  File "C:\Python\venv\Python37_64\lib\site-packages\urllib3\__init__.py", line 11, in 
    from . import exceptions
  File "C:\Python\venv\Python37_64\lib\site-packages\urllib3\exceptions.py", line 3, in 
    from .packages.six.moves.http_client import IncompleteRead as httplib_IncompleteRead
  File "C:\Python\venv\Python37_64\lib\site-packages\urllib3\packages\six.py", line 199, in load_module
    mod = mod._resolve()
  File "C:\Python\venv\Python37_64\lib\site-packages\urllib3\packages\six.py", line 113, in _resolve
    return _import_module(self.mod)
  File "C:\Python\venv\Python37_64\lib\site-packages\urllib3\packages\six.py", line 82, in _import_module
    __import__(name)
  File "C:\Python\Python37_64\lib\http\client.py", line 71, in 
    import email.parser
  File "C:\GitLab\p01\email.py", line 1, in 
    import smtplib
  File "C:\Python\Python37_64\lib\smtplib.py", line 47, in 
    import email.utils
ModuleNotFoundError: No module named 'email.utils'; 'email' is not a package

0
0 Comments

为什么某些文件名不允许用于本地Python源代码文件?

Python内置了许多模块,例如json、collections、copy和email。可以在官方文档中找到一个完整的列表。

由于模块/包名称在每个解释器会话中是全局唯一的,因此使用与内置模块相同名称的自定义模块/包将使后者无法通过给定名称访问。这意味着任何试图访问内置模块的代码(无论是你自己的代码还是第三方代码)都很可能失败。

对此没有解决方法。除非你有意要替换它们,否则不要重复使用内置模块/包的名称。这包括删除带有此类命名冲突的残留代码。要么重命名冲突的文件,要么将它们移到搜索路径之外。

这是不完整的。了解Python的导入机制对于解决这类问题非常重要;特别是它是如何搜索模块的。此外,在“删除残留代码”时,您还可能需要清理本地__pycache__文件夹中的缓存.pyc文件。

你知道一个好的参考资料吗?我认为当主要信息是“不要”的时候,不需要了解导入系统的所有细节。

0
0 Comments

为什么一些文件名在本地Python源代码文件中是不允许的?

在Python的默认配置中,当Python加载模块时,它会在一系列路径中寻找模块,这些路径定义在一个列表中,可以通过`sys.path`访问。

根据文档:

“在程序启动时初始化时,列表中的第一项`path[0]`是包含用于调用Python解释器的脚本的目录。如果脚本目录不可用(例如,如果解释器是以交互方式调用的,或者脚本是从标准输入中读取的),`path[0]`是空字符串,这将指导Python首先在当前目录中搜索模块。请注意,脚本目录插入在由`PYTHONPATH`导致的条目之前。”

在你的情况下,`path[0]`是`C:\GitLab\p01`,这绝对不是搜索标准库模块的地方。

个人而言,我对这个设计决策并不是很满意(我更喜欢,特别是新程序员被迫尽快理解相对导入),但这是一个有意识的设计决策,它为我们提供了很多方便。

你可以简单地修改`sys.path`来避免这个异常:

import sys
local = sys.path.pop(0)
import requests
sys.path.insert(0, local)

这可能与程序中的其他任何对`sys.path`的修改不兼容(但至少你可以确保在问题导致的导入之后立即恢复更改)。对于每个与你想要的名称冲突的导入(乐观地说,是一系列导入),你都将被困在这样的情况中。当然,如果你想使用名称`sys`,那就没有办法了。

你可以以多种方式封装这个方法,并以多种方式插入到导入系统中。这是一个广泛的研究课题,超出了Stack Overflow答案的范围。

我同意这种设计是糟糕的,但却是被设计成这样的方式。我会给你们两个人点赞,但我会将你的答案标记为正确的。我的问题本来就有点特殊。

0