从具有相同名称的脚本导入已安装的包引发“AttributeError:模块没有属性”或 ImportError 或 NameError

问题描述 投票:0回答:2

我有一个名为

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 在哪里寻找模块?)

python python-import python-module shadowing
2个回答
83
投票

发生这种情况是因为您名为

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
。这里没有神奇的解决方案,因为您无法知道世界上所有模块的名称,但经验法则是尝试使模块名称尽可能唯一,并在出现此类错误时尝试更改名称。


28
投票

错误发生是因为用户创建的脚本与库文件名有名称冲突。但是请注意,问题可能是间接引起的。可能需要一些侦探工作才能找出导致问题的文件。

例如:假设你有一个包含

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__
的文件夹中; 删除这样的文件夹和文件是安全的,并且可能压制它们(但您通常不想这样做)。

© www.soinside.com 2019 - 2024. All rights reserved.