我是 Python 新手,之前我一直在使用 Swift 之类的语言,其中导入并不是什么大问题:你只是定义了一个新类,并且可以从程序的另一部分访问它。
我不能在 Python 中使用这种方式,因为这里的 import 以另一种方式工作:你不能进行循环导入,两个文件相互导入。我知道我正面临这个问题,因为以错误的方式使用语言,但我不明白如何避免它。
我的意思是,在大多数情况下,您可以通过将两个类组合到一个文件中来解决这个问题,但感觉不对。此外,我还找到了诸如“将导入语句移动到文件末尾”之类的建议,但这也不是一个好主意。
如果您愿意,我想了解 Python 的哲学。在决定在单独的文件中创建类(class)时,我应该如何组织我的项目以及我应该遵循什么指导?
最佳答案
你当然可以导入child
来自 parent
和 parent
来自 child
.完成这项工作的关键是 child
不要深入探究parent
从它的模块级代码,因为parent
在 Python 运行 child
中的模块级代码时,模块仅部分加载.
以下是导入 child
时发生的情况来自 parent
和 parent
来自 child
(假设 parent
首先加载):
parent
模块级别的代码运行直到它到达加载 child
的语句(import child
或 from child import something
)。 “模块级别”是指不在类或函数定义中的语句。在模块级别定义的类和函数也将被创建为模块内的对象。但是,函数和类方法本身还不会运行。 import child
parent
中的声明(或等价物)的模块级代码,它将停止运行 parent
代码并开始运行 child
中的模块级代码.如果 child
进口 parent
通过 import parent
或 from parent import something
,它将得到 parent
模块处于当前的部分构建状态。所以 child
中的模块级代码无法访问下面定义的对象 import child
在 parent.py
. child
的模块级代码运行完毕,控制权将返回parent
低于import child
语句,Python 将完成运行 parent
中的所有模块级代码. 如果
child
,这个过程会给你带来麻烦。的模块级代码尝试访问 parent
中定义的对象。在 import child
之后语句(因为 parent
仅在 child
加载时部分完成)。解决方法是导入 parent
在模块级别 child
但推迟访问 parent
内的对象来自 child
直到 child
之后和 parent
已完成加载。特别是,不要使用 from parent import something
在 child
的模块级代码,您可能需要使用 import parent
,然后访问 parent.something
从 child
中的函数或方法代码内部.这样做是安全的,因为这些函数和方法要到 child
之后才会运行。和 parent
完成运行,此时 parent
的所有元素模块定义正确。这是我的意思的一个例子,使用你在评论中描述的设置。如果您提供有关给您带来问题的代码的更多信息,我可以更紧密地调整它。
版本 1(不起作用)
__main__.py:
from user import User
u = User()
用户.py:
from data_manager import DataManager
...
class User:
def __init__(self, data_manager=None):
if data_manager is None:
data_manager = DataManager(user=self)
self.data_manager = data_manager
数据管理器.py:
# next line will fail because user.py has been partly loaded
# and user.User doesn't exist yet
from user import User
...
class DataManager:
def __init__(self, user=None):
...
if user is None:
user = User(data_manager=self)
self.user = user
版本 2(将工作)
__main__.py:
from user import User
u = User()
用户.py:
import data_manager as dm
...
class User:
def __init__(self, data_manager=None):
if data_manager is None:
data_manager = dm.DataManager(user=self)
self.data_manager = data_manager
数据管理器.py:
import user as user_module
...
# this defines a class which will eventually create an instance
# of user.User, but it won't try to do that until control returns
# to __main__.py, by which point the `user` and `data_manager`
# modules are fully defined
class DataManager:
def __init__(self, user=None):
...
if user is None:
user = user_module.User(data_manager=self)
self.user = user
请注意,您的类(class)中的引用
__init__
在实际实例化类之前,方法不会得到解决。即 user = user_module.User(data_manager=self)
行执行如下操作:“在当前模块中查找名为 user_module
的对象;在该对象中查找 User
属性;构造该类的对象”。重要的是 data_manager
可以安全导入user
早期的模块(模块已经存在,即使它只是部分构建),但上面的代码实际上不会在 user
中查找任何内容模块直到 DataManager
对象被实例化,此时 user.User
将被正确定义。
关于python - 如何避免循环导入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43973509/