我有一个名为 requests.py
的脚本,需要使用第三方 requests
包。该脚本要么无法导入包,要么无法访问其功能。
为什么这不起作用,如何修复它?
尝试简单导入然后使用该功能会导致 AttributeError
:
import requests
res = requests.get('http://www.google.ca')
print(res)
Traceback (most recent call last):
File "/Users/me/dev/rough/requests.py", line 1, in <module>
import requests
File "/Users/me/dev/rough/requests.py", line 3, in <module>
requests.get('http://www.google.ca')
AttributeError: module 'requests' has no attribute 'get'
在较新版本的 Python 中,错误消息改为 AttributeError:部分初始化的模块“requests”没有属性“get”(很可能是由于循环导入)
。
使用特定名称的 from-import 会导致 ImportError
:
from requests import get
res = get('http://www.google.ca')
print(res)
Traceback (most recent call last):
File "requests.py", line 1, in <module>
from requests import get
File "/Users/me/dev/rough/requests.py", line 1, in <module>
from requests import get
ImportError: cannot import name 'get'
在较新版本的 Python 中,错误消息改为 ImportError:无法从部分初始化的模块“requests”导入名称“get” (很可能是由于循环导入)(/Users/me/dev/rough/requests.py)
。
对包内的模块使用 from-import 会导致不同的 ImportError
:
from requests.auth import AuthBase
Traceback (most recent call last):
File "requests.py", line 1, in <module>
from requests.auth import AuthBase
File "/Users/me/dev/rough/requests.py", line 1, in <module>
from requests.auth import AuthBase
ImportError: No module named 'requests.auth'; 'requests' is not a package
使用星型导入然后使用该功能会引发 NameError
:
from requests import *
res = get('http://www.google.ca')
print(res)
Traceback (most recent call last):
File "requests.py", line 1, in <module>
from requests import *
File "/Users/me/dev/rough/requests.py", line 3, in <module>
res = get('http://www.google.ca')
NameError: name 'get' is not defined
从 Python 3.13 开始,错误从 文档 中,消息变得非常清晰:
一个常见的错误是编写与标准同名的脚本
库模块。当这导致错误时,我们现在显示更多
有用的错误消息:
$ python random.py Traceback(最近一次调用最后一次):文件
“/home/me/random.py”,第 1 行,在 中
导入随机文件“/home/me/random.py”,第 3 行,在 中
打印(随机.randint(5))
^^^^^^^^^^^^^^^ AttributeError:模块“random”没有属性“randint”(考虑重命名“/home/me/random.py”,因为它
与名为“random”的标准库模块同名并且
防止导入该标准库模块)
类似地,如果
脚本与它尝试的第三方模块具有相同的名称
导入并导致错误,我们还显示了更有用的
错误消息:
$ python numpy.py Traceback(最近一次调用最后一次):文件
“/home/me/numpy.py”,第 1 行,在 中
import numpy as np File "/home/me/numpy.py", line 3, in ;
np.array([1,2,3])
^^^^^^^^ AttributeError:模块“numpy”没有属性“array”(如果“/home/me/numpy.py”与
您打算导入的库)
如果您故意将模块命名为与现有模块相同,并且想要处理这种情况,请参阅当我的项目有同名模块时,如何从标准库导入? (如何控制 Python 查找模块的位置?)
I have a script named requests.py
that needs to use the third-party requests
package. The script either can't import the package, or can't access its functionality.
Why isn't this working, and how do I fix it?
Trying a plain import and then using the functionality results in an AttributeError
:
import requests
res = requests.get('http://www.google.ca')
print(res)
Traceback (most recent call last):
File "/Users/me/dev/rough/requests.py", line 1, in <module>
import requests
File "/Users/me/dev/rough/requests.py", line 3, in <module>
requests.get('http://www.google.ca')
AttributeError: module 'requests' has no attribute 'get'
In more recent versions of Python, the error message instead reads AttributeError: partially initialized module 'requests' has no attribute 'get' (most likely due to a circular import)
.
Using from-import of a specific name results in an ImportError
:
from requests import get
res = get('http://www.google.ca')
print(res)
Traceback (most recent call last):
File "requests.py", line 1, in <module>
from requests import get
File "/Users/me/dev/rough/requests.py", line 1, in <module>
from requests import get
ImportError: cannot import name 'get'
In more recent versions of Python, the error message instead reads ImportError: cannot import name 'get' from partially initialized module 'requests' (most likely due to a circular import) (/Users/me/dev/rough/requests.py)
.
Using from-import for a module inside the package results in a different ImportError
:
from requests.auth import AuthBase
Traceback (most recent call last):
File "requests.py", line 1, in <module>
from requests.auth import AuthBase
File "/Users/me/dev/rough/requests.py", line 1, in <module>
from requests.auth import AuthBase
ImportError: No module named 'requests.auth'; 'requests' is not a package
Using a star-import and then using the functionality raises a NameError
:
from requests import *
res = get('http://www.google.ca')
print(res)
Traceback (most recent call last):
File "requests.py", line 1, in <module>
from requests import *
File "/Users/me/dev/rough/requests.py", line 3, in <module>
res = get('http://www.google.ca')
NameError: name 'get' is not defined
From Python 3.13 onwards the error message becomes very clear, from the documentation:
A common mistake is to write a script with the same name as a standard
library module. When this results in errors, we now display a more
helpful error message:
$ python random.py Traceback (most recent call last): File
"/home/me/random.py", line 1, in <module>
import random File "/home/me/random.py", line 3, in <module>
print(random.randint(5))
^^^^^^^^^^^^^^ AttributeError: module 'random' has no attribute 'randint' (consider renaming '/home/me/random.py' since it
has the same name as the standard library module named 'random' and
prevents importing that standard library module)
Similarly, if a
script has the same name as a third-party module that it attempts to
import and this results in errors, we also display a more helpful
error message:
$ python numpy.py Traceback (most recent call last): File
"/home/me/numpy.py", line 1, in <module>
import numpy as np File "/home/me/numpy.py", line 3, in <module>
np.array([1, 2, 3])
^^^^^^^^ AttributeError: module 'numpy' has no attribute 'array' (consider renaming '/home/me/numpy.py' if it has the same name as a
library you intended to import)
For cases where you name your module the same as an existing one on purpose and want to handle that situation, see How can I import from the standard library, when my project has a module with the same name? (How can I control where Python looks for modules?)
发布评论
评论(6)
之所以发生这种情况,是因为您的本地模块名为
requests.py
阴影已安装的请求
您要尝试使用的模块。当前目录被添加到sys.path
,因此本地名称优先于已安装的名称。当出现此内容时,一个额外的调试提示是仔细查看回溯,并意识到所讨论的脚本的名称与您要导入的模块匹配:
注意您在脚本中使用的名称:
您正在尝试的模块导入:
请求
将您的模块重命名为其他东西,以避免名称碰撞。
Python可能会在您的
requests.pyss.pyss.pyc
requests.pys.py
file(在__ pycache __ pycache __
in python 3中)。重命名后也将其删除,因为解释器仍将引用该文件,从而重新产生错误。但是,pyc
__ pycache __
应该如果py> py
文件已删除,则不会影响您的代码。在示例中,将文件重命名为
my_requests.py
,删除requests.pyc
,然后再次成功打印&lt; wenspys [200]&gt;
。注意: 这不仅发生在将文件命名为要导入的模块时。如果您将文件命名与直接导入的模块导入的模块相同,则可能会发生这种情况。例如,拥有一个名为
copy.py
的文件,然后尝试从那里导入pandas因为
pandas
导入复制
。这里没有魔术解决方案,因为您不知道世界上所有模块的名称,但是经验法则是尝试使模块的名称尽可能独特,并在遇到此类错误时尝试更改名称。This happens because your local module named
requests.py
shadows the installedrequests
module you are trying to use. The current directory is prepended tosys.path
, so the local name takes precedence over the installed name.An extra debugging tip when this comes up is to look at the Traceback carefully, and realize that the name of your script in question is matching the module you are trying to import:
Notice the name you used in your script:
The module you are trying to import:
requests
Rename your module to something else to avoid the name collision.
Python may generate a
requests.pyc
file next to yourrequests.py
file (in the__pycache__
directory in Python 3). Remove that as well after your rename, as the interpreter will still reference that file, re-producing the error. However, thepyc
file in__pycache__
should not affect your code if thepy
file has been removed.In the example, renaming the file to
my_requests.py
, removingrequests.pyc
, and running again successfully prints<Response [200]>
.Note: This doesn't only happen when naming your file as the module you are trying to import. This can also happen if you name your file the same as a module imported by a module you import directly. For example, having a file called
copy.py
and trying toimport pandas
from there, will giveThat is because
pandas
importscopy
. There is no magic solution here as you can't know all the modules' names in the world, but a rule of thumb is to try to make names of modules as unique as possible and try to change the name whenever you get such error.发生错误是因为用户创建的脚本具有带有库文件名的名称扣。但是请注意,问题可能是间接引起的。可能需要一些侦探工作才能确定哪个文件引起了问题。
例如:假设您有一个脚本
myDecimal.py
,其中包括导入小数
,打算使用标准库十进制
库,以进行准确的浮动 - 点数的点数十进制数字。这不会引起问题,因为没有标准库myDecimal
。但是,碰巧的是,十进制
imports数字
(另一个标准库模块)用于内部使用会导致问题。如果在项目中跟踪和重命名或删除适当的
.py
文件后仍然遇到这样的问题,请检查.py> .pyc
files 导入模块时使用Python用于缓存字节码编译。在3.x中,这些将存储在带有特殊名称__ pycache __
的文件夹中。 delete 这样的文件夹和文件,以及可能抑制它们(但通常您不想)。The error occurs because a user-created script has a name-clash with a library filename. Note, however, that the problem can be caused indirectly. It might take a little detective work to figure out which file is causing the problem.
For example: suppose that you have a script
mydecimal.py
that includesimport decimal
, intending to use the standard librarydecimal
library for accurate floating-point calculations with decimal numbers. That doesn't cause a problem, because there is no standard librarymydecimal
. However, it so happens thatdecimal
importsnumbers
(another standard library module) for internal use, so a script callednumbers.py
in your project would cause the problem.If you still encounter problems like this after tracking own and renaming or removing the appropriate
.py
files in your project, also check for.pyc
files that Python uses to cache bytecode compilation when importing modules. In 3.x, these will be stored in folders with the special name__pycache__
; it is safe to delete such folders and files, and possible to suppress them (but you normally won't want to).摘要
当项目中的 Python 源文件与某些外部库模块(在标准库中或已安装的第三方包中)同名时,就会出现此类问题。当尝试从外部库
导入
(需要使用绝对导入)时,会找到项目自己的模块,从而导致各种错误,具体取决于关于确切的细节。在一般情况下,解决问题的最简单方法是重命名受影响的文件。可能还需要找到并删除任何相应的
.pyc
文件。 (这是完全安全的;这些文件只是之前将 Python 源代码转换为字节码的工作的缓存 Python 虚拟机,类似于 Java 中的.class
文件。)当首选项目自己的模块时,这是因为 Python 如何搜索绝对导入的模块源代码。根据 Python 的具体启动方式,
sys.path
中定义的模块搜索路径通常以当前项目内的路径开头。在查找任何标准库或第三方库文件夹之前,Python 将首先查找那里。这个搜索过程不关心导入模块所在的文件夹;任何相对路径都是相对于进程的当前工作目录,而不是导入模块。 (但是,标准库路径通常是绝对路径,并且靠近sys.path
的末尾。)AttributeError
An
AttributeError
发生是因为项目自己的模块根本没有定义调用代码想要从外部库模块使用的函数、类等。因此,表示项目模块的
,因此这正是错误消息所声明的内容。'module'对象
没有具有指定名称的属性在极少数不幸的情况下,项目自己的模块可能会碰巧定义具有相同名称的内容,从而执行不同的操作。 这可能会导致任何类型的异常或其他逻辑错误。例如,如果问题中的第一个示例被修改:
现在将引发
TypeError
,因为代码将尝试使用以下命令调用本地定义的get
函数:参数数量错误。ImportError
使用特定的来源导入会导致以不同的方式报告错误,因为现在在导入过程本身中检测到问题。在问题的示例中,
from requests import get
意味着,不应创建一个新的全局名称requests
来命名模块,而应该有一个新的全局名称get
命名该模块中的函数(在普通导入后将被称为requests.get
)。这需要从该模块查找get
属性;但由于加载了错误的模块,该属性查找失败。较新版本的 Python 将此报告为可能的循环导入。其他导入尝试可能会导致不同的
ImportError
错误,抱怨导入的模块“不是包”。这是不言自明的:在问题的示例中,requests
是一个普通模块(因为它是由源代码文件requests.py
定义的),但是requiredrequests
- 由第三方库定义 - 是一个包(由其他地方的requests
文件夹内的多个文件定义,包括__init__.py
它定义了一些顶级包内容不是模块,如get
函数)。NameError
使用星型导入(例如
from requests import *
)不会直接失败 - 它会为所有模块内容创建全局名称。但是,由于问题示例中的模块不包含任何名为get
的内容,因此其尝试星号导入本身也不会定义该名称。因此,会出现NameError
- 这是尝试使用不存在的全局名称时出现的正常错误。加重因素
Python 的默认
导入
系统基于名称,而不是文件路径,并且 Python 不区分“(驱动程序)脚本”文件”和“库(模块)文件”。任何 Python 源代码都可以导入
。尽管 Python 缓存了模块导入,但主脚本通常不会在此缓存中,这意味着它完全能够尝试导入自身。这就是问题中的示例中发生的情况:由于requests
尚未import
ed,缓存中没有任何内容,因此驱动程序脚本中的尝试(名为 < code>requests.py) 到import requests
将搜索要导入的内容,并找到驱动程序脚本(即它自己的源文件)。如果模块尝试在其自己的初始化中使用该导入(例如,通过执行 from-import),这只会在导入时导致问题。 否则,问题将被推迟,从而在尝试使用该功能时(通常)导致
AttributeError
或NameError
。另请参阅:每当加载模块时(即从其源导入,而不是使用缓存) ),有自己的顶层
import
语句运行,导致更多的递归导入。任何这些间接导入都可能找到本地代码。 Python 标准库不是一个包,并且大多使用绝对导入来引用其其他组件。例如,正如戴夫·罗夫(Dave Rove)的回答中所指出的,当从名为numbers.py
的源文件或在项目中尝试导入标准库decimal
模块时,可能会失败有这样一个源文件。在一个特别有害的情况中,项目中有一个名为
token.py
的文件(或以交互模式启动 Python 时的当前工作目录)导致交互式帮助中断:回溯告诉我们需要知道的一切:调用
help
会触发标准库pydoc
的延迟导入,从而间接尝试导入标准库token
,但发现我们的token.py
不包含适当的名称。在旧版本的 Python 中,情况更糟:tokenize
将从token
进行星型导入,然后其顶级代码将尝试使用其中定义的名称,导致NameError
- 以及堆栈跟踪未提及文件名token.py
。即使相应的源文件被重命名或删除,Python 也可以从缓存的字节码文件 (
.pyc
) 中导入。这是为了加快导入速度,但它会创建保持代码目录“干净”的额外步骤。重命名任何.py
文件以解决此类问题后,请务必检查字节码缓存。解决问题
当然,标准建议简单明了:只需重命名错误导入的
.py
文件,并删除这些模块的所有缓存字节码.pyc
文件。默认情况下,在 Python 3.x 中,文件夹中任何.py
文件的.pyc
文件都将放入具有特殊名称__pycache__< 的子文件夹中/代码>;在 2.x 中,它们只是与相应的
.py
文件一起出现。然而,虽然这种方法可以快速解决大多数遇到这种问题的人的紧迫问题,但该建议的扩展性却不是很好。有很多可能有问题的名字;虽然大多数项目对包含名为
os.py
的源文件不感兴趣,但其他一些名称可能更理想,或更难解决。因此,这里还有一些其他有用的技术:控制
sys.path
当然,由于问题是由
sys.path
指定绝对导入应该首先在当前项目中查找引起的,只需更改 sys.path 即可避免这种情况。有问题的路径在文档中描述为“不安全的道路”。当使用交互式 Python 提示符时,这将是一个空字符串(相当于
'.'
的相对路径) - 即 Python 进程的当前工作目录,反映任何更改 使用例如os.chdir
创建。对于正常启动的驱动程序脚本(python driver.py
),它将是脚本所在的目录,作为绝对路径(不一定当前工作目录,因为可以在命令行上指定路径,例如 python path/to/driver.py)。对于使用-m
命令行标志运行的模块,它将是初始当前工作目录(不一定是模块所在的位置,而且也是不受 os.chdir 影响的绝对路径)。要避免在
sys.path
中出现此路径,请执行以下操作之一:在 Python 3.11 及更高版本中,设置
PYTHONSAFEPATH
环境变量,或使用-P
命令行选项 Python。在 Python 3.4 及更高版本中,使用
-I
命令行选项 以隔离模式启动。然而,这还有其他几个影响:它将忽略 PYTHONPATH 和 PYTHONHOME 等环境变量,并且还会跳过将用户特定的站点包目录添加到路径中(因此,代码将无法访问使用 Pip 的--user
选项安装的第三方库)。如果所有其他方法都失败,请考虑手动操作
sys.path
。这很混乱并且容易出错,但是sys.path
只是一个带有文件路径的普通字符串列表,修改其内容将影响将来的导入
。 (不要尝试替换列表对象;这不会起作用,因为 Python 不会通过名称sys.path
查找它,而是使用硬编码的内部无法从 Python 中销毁或替换该对象;sys.path
只是一个初始化为引用它的名称。)请记住,删除“不安全”路径将防止故意绝对导入在包内工作。这对于一些小型项目来说很不方便,但也是学习正确的包组织的一个很好的理由。说到这里:
在包内使用相对导入
一个组织良好的 Python 项目通常包含一个或多个(通常只有一个)包(存储在主项目文件夹的子文件夹中),以及放置在包子文件夹外部的一个或多个驱动程序脚本。 驱动程序脚本通常会使用单个绝对导入来访问包功能,同时实现一些简单的包装器逻辑(例如,解析命令行参数、格式化和报告未捕获的异常等)。 同时,该包将始终对其自身内容使用相对导入,并且仅在需要访问其他包(标准库和第三方依赖项)时才使用绝对导入。
例如,项目的组织方式可能如下:
driver.py 中的代码将使用绝对导入到包中,例如:(
如果需要逻辑来解析命令行参数,它通常应该放在驱动程序中而不是程序包的代码中。)
然后,程序包内的代码将使用相对导入 - 因此
x.py
可能包含类似的内容:这得到了两全其美:最初的绝对值import 设置顶级包,以便相对导入起作用,并且相对导入将避免依赖于 sys.path 配置。即使不采取步骤配置 sys.path,它通常也会包含包含驱动程序脚本的文件夹,但不包含任何包文件夹;因此,这也自动避免了导入路径冲突。 (绝对导入不会找到包内容,除非它指定了相应的包路径;但通常当它这样做时,从当前包导入是有意的。)
这也避免了为下一个项目设置陷阱其中这个作为依赖项。举例来说,我们实现并发布了一个
API
包,而其他人编写了Client
,其中包含API
作为依赖项。由于API
代码将为其他API
功能(例如,from .import 功能
)使用相对导入,因此Client
项目自己的功能性.py 不会引起问题。当然,为了使初始绝对导入起作用,需要在 sys.path 中提及顶级包文件夹。不过,这通常是通过安装软件包来完成的,因此不会引起问题。
禁用字节码缓存
如果需要重命名文件,那么如果
.pyc
文件一开始就不存在,那么避免这些文件出现问题会更容易。毕竟,它们没有必要;同样,它们只是为了加快程序后续运行时的导入速度。要抑制
.pyc
文件生成,请使用-B
命令行选项或设置PYTHONDONTWRITEBYTECODE
环境变量。 (没有内置的解决方案可以删除所有现有的 .pyc 文件,但这很容易使用shutil
标准库模块手动实现。)避免有问题的名称
考虑使用第三方工具(例如 IDE 插件)来警告标准库或项目中第三方库使用的文件名。在 Python 3.10 及更高版本中,标准库模块名称的完整列表也是 可用为 sys.stdlib_module_names 。这包括当前 Python 安装中可能不存在的名称(例如特定于操作系统的组件或有时被禁用或省略的内容,例如 Tkinter)。
Summary
Problems such as this occur when a Python source file in the project has the same name as some external library module (either in the standard library or an installed third-party package). When attempting to
import
from the external library (which requires using an absolute import), the project's own module is found instead, causing various errors depending on the exact details.The easiest way to fix the problem, in ordinary cases, is to rename the affected file. It may also be necessary to locate and delete any corresponding
.pyc
files. (This is perfectly safe; the files are just a cache of the work that was previously done to translate Python source code into bytecode for the Python virtual machine, analogous to.class
files in Java.)When the project's own module is preferred, this is because of how Python searches for module source code for absolute imports. Depending on exactly how Python is started, the module search path defined in
sys.path
will usually start with a path that is within the current project. Python will look there first, before looking in any standard library or third-party library folders. This search process does not care about the folder where the importing module is located; any relative paths are relative to the process' current working directory, not the importing module. (However, the standard library paths will normally be absolute paths, and near the end ofsys.path
, anyway.)AttributeError
An
AttributeError
occurs because the project's own module simply doesn't define the function, class etc. that the calling code wants to use from the external library module. As a result, the'module' object
that represents the project's modulehas no attribute
with the specified name, so that's exactly what the error message claims.In rare, unfortunate cases, the project's own module might happen to define something with the same name such that it does something different. This can cause any kind of exception or other logical error. For example, if the first example from the question is modified:
now a
TypeError
will be raised instead, because the code will attempt to call the locally-definedget
function with the wrong number of arguments.ImportError
Using a specific from-import causes the error to be reported differently because the problem is now detected during the importing process itself. In the example in the question,
from requests import get
means, instead of creating a new global namerequests
which names the module, there should be a new global nameget
which names the function from that module (the one which would be referred to asrequests.get
after a plain import). This requires looking up theget
attribute from that module; but since the wrong module was loaded, that attribute lookup fails. More recent versions of Python report this as a probable circular import.Other import attempts can cause different
ImportError
s which complain that the imported module "is not a package". This is self-explanatory: in the example in the question,requests
is an ordinary module (because it is defined by a source code file,requests.py
), but the desiredrequests
- defined by the third-party library - is a package (defined by several files inside arequests
folder elsewhere, including an__init__.py
which defines some top-level package contents that are not modules, like theget
function).NameError
Using a star-import, like
from requests import *
, will not fail directly - it creates global names for all the module contents. However, since the module in the question example doesn't contain anything namedget
, its attempt to star-import itself will not define that name either. Thus, aNameError
occurs - the normal error for trying to use a global name that doesn't exist.Aggravating factors
Python's default
import
system is based on names, not file paths, and Python does not distinguish between "(driver) script files" and "library (module) files". Any Python source code can beimport
ed. Although Python caches module imports, the main script will not generally be in this cache, which means it is perfectly capable of attempting toimport
itself. This is what happens in the example in the question: sincerequests
was not alreadyimport
ed, there is nothing in the cache, so the attempt in the driver script (namedrequests.py
) toimport requests
will search for something to import, and find the driver script (i.e., its own source file).This only causes a problem at import time, if the module tries to use that import in its own initialization, e.g. by doing a from-import. Otherwise, the problem will be deferred, resulting in (typically)
AttributeError
orNameError
when trying to use the functionality. See also:Whenever a module is loaded (i.e., imported from its source, rather than using the cache), its own top-level
import
statements run, causing more imports, recursively. Any of these indirect imports could potentially find the local code. The Python standard library is not a package, and mostly uses absolute import to refer to its other components. For example, as pointed out in Dave Rove's answer, attempting to import the standard librarydecimal
module could fail when tried from a source file namednumbers.py
, or within a project that has such a source file.In one especially pernicious case, having a file named
token.py
in a project (or the current working directory, when starting up Python in interactive mode) causes the interactive help to break:The traceback tells us all we need to know: calling
help
triggers a deferred import of the standard librarypydoc
, which indirectly attempts to import the standard librarytoken
, but finds ourtoken.py
which doesn't contain the appropriate name. In older versions of Python, it was even worse:tokenize
would do a star-import fromtoken
, and then its top-level code would try to use a name defined there, resulting inNameError
- and a stack trace not mentioning the file nametoken.py
.Python can import from cached bytecode files (
.pyc
) even if the corresponding source file is renamed or deleted. This is intended to speed up imports, but it creates an extra step to keep code directories "clean". After renaming any.py
file to resolve a problem like this, make sure to check the bytecode cache as well.Solving the problem
Of course, the standard advice is simple and straightforward: just rename the
.py
files that were mistakenly imported, and delete any cached bytecode.pyc
files for those modules. By default, in Python 3.x, the.pyc
files for any.py
files within a folder will be put into a subfolder with the special name__pycache__
; in 2.x, they simply appeared alongside the corresponding.py
files.However, while this approach quickly solves the immediate problem for most people encountering it, the advice does not scale very well. There are a lot of potentially problematic names; while most projects will not be interested in including a source file named e.g.
os.py
, some other names might be more desirable, or harder to work around. So, here are some other useful techniques:Controlling
sys.path
Of course, since the problem is caused by
sys.path
specifying that absolute imports should look in the current project first, it can be avoided by just changing thesys.path
.The problematic path is described in the documentation as a "potentially unsafe path". When using the interactive Python prompt, this will be an empty string (a relative path equivalent to
'.'
) - i.e., the current working directory for the Python process, reflecting any changes made by using e.g.os.chdir
. For driver scripts started normally (python driver.py
), it will be the directory where the script is located, as an absolute path (not necessarily the current working directory, since a path could be specified on the command line, likepython path/to/driver.py
). For modules run using the-m
command-line flag, it will be the initial current working directory (not necessarily where the module is located, but also an absolute path that will not be affected byos.chdir
).To avoid having this path in
sys.path
, do one of the following:In Python 3.11 and up, set the
PYTHONSAFEPATH
environment variable, or use the-P
command-line option to Python.In Python 3.4 and up, use the
-I
command-line option to start in isolated mode. This, however, has several other effects: it will ignore environment variables likePYTHONPATH
andPYTHONHOME
, and it will also skip adding the user-specific site-packages directory to the path (therefore the code will not have access to third-party libraries that were installed using the--user
option for Pip).If all else fails, consider manually manipulating
sys.path
. This is messy and error-prone, butsys.path
is just an ordinary list of strings with file paths, and modifying its contents will affect futureimport
s. (Do not try to replace the list object; this will not work, because Python does not look for it by the namesys.path
, but uses a hard-coded internal reference. It is not possible to destroy or replace that object from Python;sys.path
is just a name that is initialized to refer to it.)Keep in mind that removing the "unsafe" path will prevent intentional absolute imports from working within the package. This is inconvenient for some small projects, but also a good reason to learn proper package organization. Speaking of which:
Using relative imports within packages
A well-organized Python project will typically consist of one or more (usually just one) packages, stored in subfolders of the main project folder, plus one or more driver scripts placed outside of the package subfolders. The driver scripts will typically use a single absolute import to access the package functionality, while implementing some simple wrapper logic (e.g. to parse command-line arguments, format and report otherwise-uncaught exceptions, etc.). The package, meanwhile, will use relative imports throughout for its own content, and absolute import only where necessary to access other packages (the standard library and third-party dependencies).
For example, a project might be organized like:
Code in
driver.py
will use absolute import into the package, like:(If logic is needed to parse the command-line arguments, it should normally go in the driver rather than in the package's code.)
Then, code inside the package will use relative imports - so
x.py
might contain something like:This gets the best of both worlds: the initial absolute import sets up the top-level package so that relative imports will work, and the relative imports will avoid depending on the
sys.path
configuration. Even without taking steps to configuresys.path
, it will typically include the folder with the driver scripts, but not any package folders; thus, this also automatically avoids import path conflicts. (An absolute import won't find the package contents unless it specifies the corresponding package path; but typically when it does, importing from the current package was intentional.)This also avoids setting traps for the next project which has this one as a dependency. Say for example that we implement and publish an
API
package, and someone else writesClient
which hasAPI
as a dependency. SinceAPI
code will use relative import for otherAPI
functionality (say,from . import functionality
), theClient
project's ownfunctionality.py
won't cause a problem.For the initial absolute import to work, of course, the top-level package folder needs to be mentioned in
sys.path
. However, this is normally accomplished by installing the package, so it does not cause a problem.Disabling bytecode caching
If a file needs to be renamed, avoiding problems with
.pyc
files will be easier if they simply don't exist in the first place. They are not necessary, after all; they are, again, simply intended to speed up imports on subsequent runs of the program.To suppress
.pyc
file generation, use the-B
command-line option or set thePYTHONDONTWRITEBYTECODE
environment variable. (There is no built-in solution to delete all existing.pyc
files, but this is easy enough to implement by hand using e.g. theshutil
standard library module.)Linting to avoid problematic names
Consider using third-party tools (such as IDE plugins) to warn about filenames used by the standard library or by third-party libraries in the project. In Python 3.10 and up, the full list of standard library module names is also available as
sys.stdlib_module_names
. This includes names that might not be present in the current Python installation (e.g. OS-specific components or things that are sometimes disabled or omitted, such as Tkinter).只需将导致错误的导入放在最后,然后将其移至导入的底部
如果
importflask
导致错误,just put down the import which causing error to the last
if
import flask
is causing error then move that to bottom of the imports循环依赖性:当两个或多个模块相互依赖时,就会发生。这是由于每个模块都是按照另一个模块定义的事实。
如果您获得循环导入与请求模块错误类似的错误。
请尝试重命名文件。
此错误的错误通常是由于您试图导入requests
模块的文件名冲突。我也遇到了同样的问题,我的文件名是
email.py
,而我正试图导入请求模块。因此,它与email.parser
有一些冲突。因此,我将文件名从email.py
更改为email1.py
,并且有效。有关循环依赖性的更多信息: https://stackabuse.com/python-circular-imports/
Circular dependency : It occurs when two or more modules depend on each other. This is due to the fact that each module is defined in terms of the other.
If you are getting circular import error similar to below request module error.
Please try to rename the file.
The error for this error is usually due to conflict with the file name where you are trying to import therequests
module.I was also having same problem, where my file name was
email.py
and I was trying to import the requests module. So, it was having some conflict withemail.parser
. So, I changed the file name fromemail.py
toemail1.py
and it worked.For more info on circular dependency: https://stackabuse.com/python-circular-imports/
问题中提到的循环依赖错误的原因在接受的答案中进行了解释:
就我而言,我在模块中遇到了循环依赖错误,但没有具有该名称的文件或目录。
我的猜测是该模块以某种方式损坏,因为在我卸载它并重新安装相同版本后,它起作用了:
您可以在错误日志堆栈跟踪中识别导致错误的模块。
当错误与文件名无关时,这对于收到此错误的人可能会有所帮助。
The reason for the circular dependency error mentioned in the question is explained in the accepted answer:
In my case, I encountered a circular dependency error in a module but had no file or directory with that name.
My guess is that the module became corrupted somehow because after I uninstalled it and reinstalled the same version, it worked:
You can identify the module causing the error in the error log stack trace.
This might be helpful for those receiving this error when it is not related to the file name.