Python是非常优雅的语言。好吧,除了......除了进口。我仍然无法以我看来自然的方式工作。
我的文件MyObjectA
中有一个班级mypackage/myobjecta.py
。该对象使用mypackage/utils.py
中的一些实用程序函数。所以我在myobjecta.py
的第一行写道:
from mypackage.utils import util_func1, util_func2
但是一些实用程序函数创建并返回MyObjectA
的新实例。所以我需要写utils.py
:
from mypackage.myobjecta import MyObjectA
嗯,不,我不能。这是一个循环导入,Python将拒绝这样做。
关于这个问题,这里有很多问题,但似乎没有人给出满意的答案。从我在所有答案中可以阅读的内容:
import ...
而不是from ... import ...
(我个人不喜欢写作并可能完全重构
姓名限定词;我喜欢看到我正在进口的内容
来自外界的模块)。那会有帮助吗?我不确定,
还有循环进口。 我仍然希望有解决方案4)这将是Pythonic在功能和优雅,简单和工作的意义上。或者没有?
注意:我主要是一个C ++程序员,通过包含相应的标题可以很容易地解决上面的例子,我不相信它在Python中是不可能的。
答案 0 :(得分:1)
Pythonistas不赞成从函数中导入。 Pythonista通常不喜欢全局变量。但是,我看到了两者,并且认为使用它们的项目不会比某些严格的Pythhonistas所做的其他项目差。该功能确实存在,对其功能没有过多争论。
从函数导入问题还有另一种选择:从文件的顶部(或者实际上是从底部)导入时,此导入将花费一些时间(虽然很短,但是有些时间),但是Python将缓存整个文件,如果另一个文件需要相同的导入,Python可以快速检索模块而无需导入。而如果从函数中导入,则情况会变得很复杂:每次调用该函数时,Python都必须处理import
行,这可能会以很小的方式减慢程序速度。
对此的一种解决方案是独立缓存模块。好的,这使用函数体内的导入和全局变量。哇!
_MODULEA = None
def util1():
if _MODULEA is None:
from mymodule import modulea as _MODULEA
obj = _MODULEA.ClassYouWant
return obj
我看到在使用平面API的项目中采用了这种策略。不管您是否喜欢(我不确定自己),它都可以运行且非常快捷,因为导入行仅执行一次(函数首次执行时)。不过,我还是建议进行重组:循环导入问题通常显示出结构问题,而这始终值得解决。不过,我确实同意,如果在这种情况下Python提供了更多有用的错误,那就太好了。
答案 1 :(得分:0)
在函数体中导入某些内容并不是什么骇人听闻,这是一种绝对有效的模式:
def some_function():
import logging
do_some_logging()
通常只会引发ImportError
,因为import()
在调用时会评估整个文件的顶级语句。
如果您没有逻辑循环依赖... ,在python中没有什么是不可能的......
如果您确实希望将导入放在最上面:
,可以采取一种方法来自David Beazleys的优秀演讲Modules and Packages: Live and Let Die! - PyCon 2015,1:54:00
,这是一种处理python循环导入的方法:
try:
from images.serializers import SimplifiedImageSerializer
except ImportError:
import sys
SimplifiedImageSerializer = sys.modules[__package__ + '.SimplifiedImageSerializer']
这会尝试导入SimplifiedImageSerializer
,如果引发ImportError
,因为它已经导入,它会从导入缓存中提取它。
PS:你必须以David Beazley的声音阅读整篇文章。
答案 2 :(得分:0)
不要将mypackage.utils
导入您的主模块,它已存在于mypackage.myobjecta
中。导入mypackage.myobjecta
后,正在执行该模块中的代码,并且您不需要将任何内容导入当前模块,因为mypackage.myobjecta
已经完成。
答案 3 :(得分:0)
无法实现您想要的。 Python无法知道要执行顶层代码才能执行您要执行的操作的顺序。
假设您首先导入utils
。 Python将首先评估第一条语句from mypackage.myobjecta import MyObjectA
,该语句需要执行myobjecta
模块的顶层。然后,Python必须执行from mypackage.utils import util_func1, util_func2
,但是直到解析myobjecta
导入后,它才能执行该操作。
Python不会无限递归,而是通过允许最内部的导入完成而无需完成来解决这种情况。因此,utils
导入完成而没有执行文件的其余部分,并且您的import语句失败,因为util_func1
还不存在。
import myobjecta
起作用的原因是,它允许在执行了每个模块的主体之后稍后再解析符号。就个人而言,即使是这种循环导入,也让我感到困惑,因此,我不建议您完全使用它们。
如果您还是想使用循环导入,并且希望它们是“从”导入,那么我认为它可以可靠地工作的唯一方法是:在从另一个模块导入之前,定义另一个模块使用的所有符号。在这种情况下,您对util_func1
和util_func2
的定义必须在from mypackage.myobjecta import MyObjectA
中的utils
语句之前,而MyObjectA
的定义必须在{{1 }}在from mypackage.utils import util_func1, util_func2
中。
像C#这样的编译语言可以处理这种情况,因为顶层是定义的集合,而不是指令。他们不必按给定的顺序创建每个类和每个函数。他们可以按照需要的顺序解决问题,从而避免出现任何周期。 (C ++通过在原型中复制信息来做到这一点,我个人认为这是一个非常棘手的解决方案,但那也不是Python的工作方式。)
像Python这样的系统的优点是它是高度动态的。是的,您可以基于仅在运行时才知道的内容来不同地定义类或函数。或在创建类后修改它。或者尝试导入依赖项,如果不可用,则不使用它们。如果您不觉得坚持严格的依赖关系树不便带来这些麻烦,那是完全合理的,也许编译语言可以更好地为您服务。