我是 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将被正确定义。
