繁体   English   中英

ImportError:尝试在没有已知父项的情况下进行相对导入 package [重复]

[英]ImportError : Attempted relative import with no known parent package [duplicate]

我正在学习使用 python 进行编程,并且在从 package 中的模块导入时遇到问题。我正在使用带有 Python 3.8.2 64 位的 visual studio 代码。

我的项目目录

.vscode
├── ecommerce
│   ├── __init__.py
│   ├── database.py
│   ├── products.py
│   └── payments
│       ├── __init__.py
│       ├── authorizenet.py
│       └── paypal.py
├── __init__.py
└── main.py

ecommerce/products.py文件中我有:

#products.py
from .database import Database
p = Database(3,2)

这样我就可以从 ecommerce ecommerce/database.py文件中导入Database class。 但我得到错误

ImportError : Attempted relative import with no known parent package

Python 文档和实验看来,相对导入(涉及., .. 等)只有在以下情况下才有效

  1. 导入模块有一个__name__而不是__main__ ,而且,
  2. 导入模块的__name__是 pkg.module_name,即它必须从目录层次结构的上方导入(要有一个父 pkg 作为它的一部分__name__ 。)

要么

导入模块通过包含父 pkg 的模块语法指定为python -m pkg.module ,在这种情况下,它的__name__仍然是__main__ ,因此它作为脚本运行,但相对导入将起作用。 这里__package__被设置并用于查找父 package 而__name____main__ ; 更多在这里

[毕竟,看来__package__sys.path是确定相对导入是否/如何工作的关键。 __name__表示脚本或模块(即__main__module_name )。 __package__指示相对导入发生在 package 中的位置,并且__package__的顶部需要在sys.path中。]

因此,继续@AmitTendulkar 的示例,如果您从项目根目录将其作为> python main.py> python -m main> python -m ecommerce.products ecommerce.products 运行,或者从该根目录输入交互式 python 并import mainimport ecommerce.products products.py 中的相关导入将起作用。

但是,如果您从电子商务目录中> python products.py> python -m products ,或从该电子商务目录中输入交互式 python 并import products ,它们将失败。

补充一下很有帮助

print("In module products __package__, __name__ ==", __package__, __name__)

等在每个文件中进行调试。

更新:

导入的工作方式取决于sys.path__package__ ,而不是__name__ /home/jj发出, > python sub/mod.py __package__一个sys.path/home/jj/sub的 __package__ , None - sys.path中模块的绝对导入工作,相对导入失败。

> python -m sub.mod __package__ sys.path/home/jj的 __package__ , sys.path中模块的sub绝对导入工作,相对导入工作相对于sys.path + __package__

补充一下更有帮助

import sys    
print("In module products sys.path[0], __package__ ==", sys.path[0], __package__)

等在每个文件中进行调试。

由于您使用的是 Python 3.8 版本,导入工作略有不同,但我认为这应该有效:

使用:

from database import Database
#Database is the class

或尝试:

import database.Database

最后,这个非常安全并且可能是最佳实践:

from . import Database  
# The '.' (dot) means from within the same directory as this __init__.py module grab the Database class.

我在 Windows 上遇到了类似的问题,对我有帮助的是(适应你的目录):

# local imports
import sys
sys.path.append(r"C:\path\to\your\project")

from ecommerce.database import Database

考虑以下基本文件结构

├── ecommerce
│   ├── __init__.py
│   ├── database.py
|   └── products.py
└── main.py

我假设您正在从项目根目录运行python main.py

这是从 Python 教程复制的文本,解释了相对导入的基本规则,

请注意,相对导入是基于当前模块的名称。 由于主模块的名称始终是__main__ ,因此用作 Python 应用程序的主模块的模块必须始终使用绝对导入。

所以下面的代码将起作用,

# main.py
import ecommerce.products 
# or to use it directly 
# from ecommerce.products import my_product

ecommerce.products.my_product()

你的 product.py 可能看起来像,

# ecommerce/products.py
from .database import Database

def my_product():
    p = Database(3, 2)

database.py 如下所示,

# ecommerce/database.py

class Database():
    def __init__(self, x, y):
        self._x = x
        self._y = y
        print('Inside DB init')

    # Rest of the methods...

你现在会得到,

> python main.py
Inside DB init

理想情况下,根目录下的__init__.py文件不是必需的,因为 package 名称是从电子商务开始的。

也可以运行python -m ecommerce.products命令直接调用products.py。 但这不会产生任何 output,因为我们没有调用 my_product() function(仅定义它)。

调用python ecommerce/products.py将不起作用,因为当前模块的名称将变为__main__而不是ecommerce 相对导入仅在当前 package 中使用时有效(因此在您的主脚本中您始终需要导入您的ecommerce包)。

要允许使用相对导入,您需要“将您的代码变成一个包”。 这意味着所有1) 将__init__.py放在代码的顶层目录中(在您的示例.vscode2) 将完整(绝对)路径添加到顶层目录的父目录(即您的目录) directory .vscode ) 到你的PYTHONPATH3) 将 Python 程序中的__package__变量设置为包含__init__.py的目录的名称,在你的例子中是“ .vscode ”。

然后您应该能够在ecommerce/products.py中使用:

from .ecommerce.database import Database

我不确定为什么点在名称中.vscode - 是目录名称的一部分,还是目录树中行的一部分? 如果是后者,请将.vscode替换为上面的vscode

试试这个...

from ecommerce.database import Database

这看起来像是 hack,但它确实有效,这是因为错误的 package 结构

在你的情况下尝试导入

from.vs_code.ecommerce import database

现在无论你想在哪里调用 class 构造函数,都可以这样做:

database.Database()

您可以将其分配给一个变量并使用它。

据推测,您使文件“products.py”可执行,这违反了包的概念,package 不再是 package 并且相对导入不起作用。 您必须在 package 之外调用它。

这里我也不确定根目录名是否可以像“.vscode”一样以点开头。

尝试以下

from ecommerce import database

我正在学习使用 python 编程,但在从包中的模块导入时遇到问题。 我正在使用带有 Python 3.8.2 64 位的视觉工作室代码。

我的项目目录

.vscode
├── ecommerce
│   ├── __init__.py
│   ├── database.py
│   ├── products.py
│   └── payments
│       ├── __init__.py
│       ├── authorizenet.py
│       └── paypal.py
├── __init__.py
└── main.py

ecommerce/products.py文件中,我有:

#products.py
from .database import Database
p = Database(3,2)

这样我就可以从ecommerce/database.py文件中导入Database类。 但我得到错误

ImportError : Attempted relative import with no known parent package

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM