无法让Python从另一个文件夹导入模块

109

我似乎无法让Python导入一个子文件夹中的模块。当我尝试从已导入的模块创建一个类的实例时,出现了错误,但是导入本身成功了。这是我的目录结构:

Server
    -server.py
    -Models
        --user.py

以下是server.py的内容:

from sys import path
from os import getcwd
path.append(getcwd() + "\\models") #Yes, i'm on windows
print path
import user

u=user.User() #error on this line

还有 user.py:

class User(Entity):
    using_options(tablename='users')

    username = Field(String(15))
    password = Field(String(64))
    email    = Field(String(50))
    status   = Field(Integer)
    created  = Field(DateTime)
错误是: AttributeError: 'module'对象没有属性'User'

1
请粘贴错误信息? - Harley Holcombe
添加了2.x标签,因为这里的答案描述了通过添加__init__.py来解决问题,而在3.x中不是必需的。这里的问题在3.x中无法重现(当然,print语句必须更新为函数调用)。 - Karl Knechtel
10个回答

169

我认为你需要在Models目录下创建一个名为__init__.py的文件,这样python才会将其视为模块。

然后你可以执行以下操作:

from Models.user import User

你可以在__init__.py中包含代码(例如几个不同类需要的初始化代码),或者将其留空。但它必须存在。


2
谢谢,我以前从未听说过包。 - ryeguy
2
实际上,在导入时,Python 对待 blah.py 和 blah/init.py 是完全相同的。 - pi.
3
那很不明显...然后我对自己说:RTFM FMF。 - Alexander.Iljushkin
2
注意,如果你从另一个目录运行server.py文件,这将无法正常工作。 - kchoi
5
如果 server.py 在另一个文件夹中,该怎么办? - Mandroid
1
在Python 3.8.6中似乎不需要__init__.py文件了。只需要直接导入所需的内容即可(例如使用from folder.file import *)。 - carloswm85

29

你需要在Models子文件夹中创建一个名为__init__.py的文件,这个文件可以为空。它定义了一个包。

然后你可以执行:

from Models.user import User

你可以在Python教程中了解更多信息,点这里

此外,还有一篇关于Python项目文件组织的好文章,在这里


如果文件不为空呢? - Darkgaze

13

导入用户

u = user.User() #在这一行上发生错误

由于缺少上面提到的__init__,您会期望出现ImportError,这将使问题更加清晰。

您没有得到一个,因为'user'也是标准库中已存在的一个模块。您的导入语句抓取那个模块,并尝试在其中找到User类; 但是该类不存在,只有在此之后才会出错。

通常最好使用绝对导入:

import Server.Models.user

为了避免这种歧义。实际上从Python 2.7开始,'import user'根本不会相对于当前模块查找。

如果您真的想要相对导入,则可以在Python 2.5及更高版本中使用有点丑陋的语法显式地声明:

from .user import User

12

当你没有标准的包结构时,导入位于父文件夹中的模块的正确方法是:

import os, sys
CURRENT_DIR = os.path.dirname(os.path.abspath(__file__))
sys.path.append(os.path.dirname(CURRENT_DIR))

(你可以合并最后两行,但这种方式更容易理解)。

该解决方案跨平台,并且足够通用,不需要在其他情况下进行修改。


8
您缺少__init__.py文件。根据Python教程:
__init__.py文件是必需的,以便让Python将目录视为包含包;这样做是为了防止具有共同名称(例如string)的目录无意中隐藏了稍后在模块搜索路径上出现的有效模块。在最简单的情况下,__init__.py可以只是一个空文件,但它也可以执行包的初始化代码或设置稍后描述的__all__变量。
在Models目录中放置一个名为__init__.py的空文件,一切都应该没问题了。

1

你如何编写命令 os.path.dirname 的参数?

import os, sys
CURRENT_DIR = os.path.dirname(os.path.abspath(__file__))
sys.path.append(os.path.dirname(CURRENT_DIR))

0

我个人偏好的方式是在包含被其他模块使用的模块的每个目录中都有一个 __init__.py 文件,并在入口点中按照下面的方法覆盖 sys.path:

def get_path(ss):
  return os.path.join(os.path.dirname(__file__), ss)
sys.path += [
  get_path('Server'), 
  get_path('Models')
]

这使得指定目录中的文件可以被导入,我可以从 Server.py 中导入用户。

0
通过查看上述贡献者(Zorglub29,Tom,Mark,Aaron McMillin,lucasamaral,JoeyZhao,Kjeld Flarup,Procyclinsur,martin.zaenker,tooty44)给出的答案并调试我遇到的问题,我发现由于不同的用例导致了这个问题。 因此,在下面添加我的观察结果以供任何人参考。
在我的代码中,我有一个循环导入类。例如:
src
 |-- utilities.py (has Utilities class that uses Event class)  
 |-- consume_utilities.py (has Event class that uses Utilities class)
 |-- tests
      |-- test_consume_utilities.py (executes test cases that involves Event class)

当我尝试执行python -m pytest tests/test_utilities.py来执行test_utilities.py中编写的UT时,出现了以下错误。
ImportError while importing test module '/Users/.../src/tests/test_utilities.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
tests/test_utilities.py:1: in <module>
    from utilities import Utilities
...
...
E   ImportError: cannot import name 'Utilities'

我解决这个错误的方法是重构我的代码,将循环导入类中的功能移动,以便我可以删除类的循环导入。
请注意,我在我的“src”文件夹和“tests”文件夹中都有“__init__.py”文件,仍然能够通过重构代码摆脱“ImportError”。
以下stackoverflow链接提供了关于Python中循环依赖的更多细节:Circular dependency in Python

0

在根目录下创建start.py或任何名称的Python文件,并添加以下行

import os, sys
CURRENT_DIR = os.path.dirname(os.path.abspath(__file__))
sys.path.append(os.path.dirname(CURRENT_DIR))

它将在系统路径变量中添加您的项目根目录路径。添加后,Python 尝试搜索此路径和默认路径下的所有文件和库。

注意:我已在本地测试过。我认为,在云上不需要这样做。


-2
我遇到了同样的问题,并通过将项目添加到PYTHONPATH中解决了它。
尝试一下: export PYTHONPATH=path_to_your_project

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接