Python/Django: 为什么在使用前导入模块会阻止循环导入?
Python/Django: Why does importing a module right before using it prevent a circular import?
我已经 运行 在不同的情况下多次遇到这个问题,但我的设置如下:
我有两个 Django 模型文件。一个包含用户模型和优惠券代码,用户可以使用它们来注册课程。这些都在 account/models.py 文件中。 Course 和相关的多对多字段位于不同的模型文件 course/models.py 中。我通常在我的代码中将它们分别称为 amod 和 cmod。
在 course/models.py 中我有一个导入语句:
from account import models as amod
class Course(ExtendedModel):
stuff = stuff
我需要为此处未显示的课程和用户之间的多对多 model/table 导入 account/models.py 文件。到目前为止,还不错。
在 account/models.py 文件中我有 CouponCode 模型。每个实例都被创建,然后可以在创建后分配给特定的课程对象,以允许学生使用它来注册系统中的课程。
class CouponCode(ExtendedModel):
assigned_course = UniqueIDForeignKey("course.Course", blank=True, null=True, related_name='assigned_coupon_code_set')
...
...
@staticmethod
def assign_batch(c, upper_limit):
import course.models as cmod # Why is this allowed here?
assert isinstance(c, cmod.Course)
# Do other stuff here
那个静态方法允许我传入一个课程对象和一些我想分配给它的 CouponCodes,然后它将下一个 N 个未分配的代码分配给该课程。我的问题来自 assert 语句。
我需要从 course/models.py 导入 Course 对象,以确保传入的对象实际上是 Course 的一个实例,但如果我在文件顶部这样做,我遇到问题,因为这个文件已经被导入 course/models.py。 (amod 正在导入到 cmod 中,然后在 amod 中我需要导入 cmod)。
如果我在需要它之前在方法中导入它而不是在文件顶部导入它,为什么允许我这样做?
当一个模块被导入时(好吧,它是在给定进程中第一次导入),所有的顶级语句都会被执行(记住import
是 一个可执行语句)。所以你不能让 module1 在顶层有一个 import module2
语句,而 module2 在顶层有一个 import module1
- 它显然不能工作。
现在,如果在模块 2 中将 import module1
语句移动到函数中,则该语句不会在函数实际调用之前执行,因此不会阻止模块 1 导入模块 2。
请注意,这仍然被认为是不好的做法,大多数时候循环依赖意味着你应该重构你的代码来避免这个问题(将两个模块依赖的部分提取到第三个模块中,该模块依赖于两个但是 none 的其他依赖,或简单地合并模块) - 但有些情况由于其他限制而变得复杂,因此将其作为最后的解决方案是可以的。
此外,您 不需要 导入模型以在 ForeignKey
或 Many2Many
字段中引用它 - 您可以传递 "appname.ModelName"
字符串,cf https://docs.djangoproject.com/en/1.8/ref/models/fields/#foreignkey
To refer to models defined in another application, you can explicitly
specify a model with the full application label. For example, if the
Manufacturer model above is defined in another application called
production, you’d need to use:
class Car(models.Model):
manufacturer = models.ForeignKey('production.Manufacturer')
This sort of reference can be useful when resolving circular import
dependencies between two applications.
我已经 运行 在不同的情况下多次遇到这个问题,但我的设置如下:
我有两个 Django 模型文件。一个包含用户模型和优惠券代码,用户可以使用它们来注册课程。这些都在 account/models.py 文件中。 Course 和相关的多对多字段位于不同的模型文件 course/models.py 中。我通常在我的代码中将它们分别称为 amod 和 cmod。
在 course/models.py 中我有一个导入语句:
from account import models as amod
class Course(ExtendedModel):
stuff = stuff
我需要为此处未显示的课程和用户之间的多对多 model/table 导入 account/models.py 文件。到目前为止,还不错。
在 account/models.py 文件中我有 CouponCode 模型。每个实例都被创建,然后可以在创建后分配给特定的课程对象,以允许学生使用它来注册系统中的课程。
class CouponCode(ExtendedModel):
assigned_course = UniqueIDForeignKey("course.Course", blank=True, null=True, related_name='assigned_coupon_code_set')
...
...
@staticmethod
def assign_batch(c, upper_limit):
import course.models as cmod # Why is this allowed here?
assert isinstance(c, cmod.Course)
# Do other stuff here
那个静态方法允许我传入一个课程对象和一些我想分配给它的 CouponCodes,然后它将下一个 N 个未分配的代码分配给该课程。我的问题来自 assert 语句。
我需要从 course/models.py 导入 Course 对象,以确保传入的对象实际上是 Course 的一个实例,但如果我在文件顶部这样做,我遇到问题,因为这个文件已经被导入 course/models.py。 (amod 正在导入到 cmod 中,然后在 amod 中我需要导入 cmod)。
如果我在需要它之前在方法中导入它而不是在文件顶部导入它,为什么允许我这样做?
当一个模块被导入时(好吧,它是在给定进程中第一次导入),所有的顶级语句都会被执行(记住import
是 一个可执行语句)。所以你不能让 module1 在顶层有一个 import module2
语句,而 module2 在顶层有一个 import module1
- 它显然不能工作。
现在,如果在模块 2 中将 import module1
语句移动到函数中,则该语句不会在函数实际调用之前执行,因此不会阻止模块 1 导入模块 2。
请注意,这仍然被认为是不好的做法,大多数时候循环依赖意味着你应该重构你的代码来避免这个问题(将两个模块依赖的部分提取到第三个模块中,该模块依赖于两个但是 none 的其他依赖,或简单地合并模块) - 但有些情况由于其他限制而变得复杂,因此将其作为最后的解决方案是可以的。
此外,您 不需要 导入模型以在 ForeignKey
或 Many2Many
字段中引用它 - 您可以传递 "appname.ModelName"
字符串,cf https://docs.djangoproject.com/en/1.8/ref/models/fields/#foreignkey
To refer to models defined in another application, you can explicitly specify a model with the full application label. For example, if the Manufacturer model above is defined in another application called production, you’d need to use:
class Car(models.Model): manufacturer = models.ForeignKey('production.Manufacturer')
This sort of reference can be useful when resolving circular import dependencies between two applications.