我有一个名为
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: partially initialized module 'requests' has no attribute 'get' (most likely due to a circular 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: cannot import name 'get' from partially initialized module 'requests' (most likely due to a circular import) (/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
使用 star-import 然后使用该功能会引发
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 在哪里寻找模块?)
发生这种情况是因为您名为
requests.py
的本地模块隐藏了您尝试使用的已安装 requests
模块。当前目录被添加到 sys.path
之前,因此本地名称优先于安装名称。
出现这种情况时,一个额外的调试提示是仔细查看回溯,并意识到您的问题脚本的名称与您尝试导入的模块相匹配:
注意您在脚本中使用的名称:
File "/Users/me/dev/rough/requests.py", line 1, in <module>
您要导入的模块:
requests
将您的模块重命名为其他名称以避免名称冲突。
Python 可能会在您的
requests.pyc
文件旁边生成一个 requests.py
文件(在 Python 3 中的 __pycache__
目录中)。重命名后也将其删除,因为解释器仍将引用该文件,从而重新产生错误。但是,pyc
中的__pycache__
文件如果py
文件已被删除,应该不会影响您的代码。
例子中,将文件重命名为
my_requests.py
,去掉requests.pyc
,再次运行成功打印出<Response [200]>
.
注意: 这不仅发生在将文件命名为您尝试导入的模块时。如果您将文件命名为与您直接导入的模块导入的模块相同的名称,也会发生这种情况。例如,有一个名为
copy.py
的文件并尝试从那里import pandas
,将给出
ImportError: cannot import name 'copy' from 'copy'
那是因为
pandas
进口copy
。这里没有神奇的解决方案,因为您无法知道世界上所有模块的名称,但经验法则是尝试使模块名称尽可能唯一,并在出现此类错误时尝试更改名称。
错误发生是因为用户创建的脚本与库文件名有名称冲突。但是请注意,问题可能是间接引起的。可能需要一些侦探工作才能找出导致问题的文件。
例如:假设你有一个包含
mydecimal.py
的脚本import decimal
,打算使用标准库decimal
库进行带十进制数的精确浮点计算。这不会造成问题,因为没有标准库mydecimal
。然而,碰巧 decimal
导入 numbers
(另一个标准库模块)供内部使用,因此项目中名为 numbers.py
的脚本会导致问题。
在一个特别有害的案例中,在项目中有一个名为
token.py
的文件(或当前工作目录,当以交互模式启动Python时)导致交互帮助中断:
$ touch token.py
$ python
Python 3.8.10 (default, Nov 14 2022, 12:59:47)
[GCC 9.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> help
Type help() for interactive help, or help(object) for help about object.
>>> help()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.8/_sitebuiltins.py", line 102, in __call__
import pydoc
File "/usr/lib/python3.8/pydoc.py", line 66, in <module>
import inspect
File "/usr/lib/python3.8/inspect.py", line 40, in <module>
import linecache
File "/usr/lib/python3.8/linecache.py", line 11, in <module>
import tokenize
File "/usr/lib/python3.8/tokenize.py", line 35, in <module>
from token import EXACT_TOKEN_TYPES
ImportError: cannot import name 'EXACT_TOKEN_TYPES' from 'token' (/current/working/directory/token.py)
回溯告诉我们所有我们需要知道的:调用
help
触发延迟导入标准库pydoc
,它间接尝试导入标准库token
,但发现我们的token.py
不包含适当的名称。在旧版本的 Python 中,情况更糟:tokenize
会从 token
进行星号导入,然后它的顶级代码会尝试使用那里定义的名称,导致 NameError
- 和堆栈跟踪不提文件名token.py
.
如果在跟踪自己并重命名或删除项目中适当的
.py
文件后仍然遇到这样的问题,还要检查 .pyc
文件 Python 在导入模块时用于缓存字节码编译。在 3.x 中,这些将存储在具有特殊名称__pycache__
的文件夹中; 删除这样的文件夹和文件是安全的,并且可能压制它们(但您通常不想这样做)。