将代码添加到__init__.py

时间:2020-03-06 14:34:50  来源:igfitidea点击:

我正在研究django中的模型系统如何工作,我注意到了一些我不理解的东西。

我知道我们创建了一个空的__init__.py文件来指定当前目录是一个包。并且我们可以在__init __。py中设置一些变量,以便import *正常工作。

但是django添加了一堆from ... import ...语句,并在__init__.py中定义了一堆类。为什么?这不仅会使事情看起来凌乱吗?是否有理由需要在__init__.py中使用此代码?

解决方案

导入包含__init__.py的软件包(目录)时,所有导入都可用。

例子:

./dir / __ init __。py

import something

。/ test.py

import dir
# can now use dir.something

编辑:忘了提一下,init.py中的代码在我们首次从该目录导入任何模块时运行。因此,通常是放置任何程序包级初始化代码的好地方。

EDIT2:dgrant指出了我的示例中可能存在的混乱。在__init __。py中,import something`可以导入任何模块,而不必从包中导入。例如,我们可以将其替换为"导入日期时间",然后在顶层" test.py"中,这两个代码片段都将起作用:

import dir
print dir.datetime.datetime.now()

import dir.some_module_in_dir
print dir.datetime.datetime.now()

底线是:在__init__.py中分配的所有名称(无论是导入的模块,函数还是类),无论何时导入软件包或者软件包中的模块,都将自动在软件包名称空间中提供。

实际上,这只是个人喜好,并且与python模块的布局有关。

假设我们有一个名为erikutils的模块。它可以通过两种方式成为模块,或者在sys.path上有一个名为erikutils.py的文件,或者在sys.path上有一个名为erikutils的目录,其中有一个空的__init__.py文件在里面。然后假设我们有一堆名为fileutilsprocutilsparseutils的模块,并且我们希望这些模块成为erikutils下的子模块。因此,我们制作了一些名为fileutils.py,procutils.py和parseutils.py的.py文件:

erikutils
  __init__.py
  fileutils.py
  procutils.py
  parseutils.py

也许我们有一些不属于fileutilsprocutils或者parseutils模块的功能。假设我们不想创建一个名为miscutils的新模块。 AND,我们希望能够像这样调用该函数:

erikutils.foo()
erikutils.bar()

而不是做

erikutils.miscutils.foo()
erikutils.miscutils.bar()

因此,因为erikutils模块是目录,而不是文件,所以我们必须在__init __。py文件中定义它的功能。

在django中,我能想到的最好的例子是django.db.models.fields。所有django * Field类都在django / db / models / fields目录的__init__.py文件中定义。我猜他们这样做是因为他们不想将所有内容都塞进假设的django / db / models / fields.py模型中,因此他们将其拆分为几个子模块(例如,related.py,files.py)和他们将制成的* Field定义粘贴在fields模块本身中(因此,是__init__.py)。

使用__init __。py文件可以使内部包结构从外部不可见。如果内部结构发生变化(例如,因为将一个胖模块分成两个),则只需调整__init__.py文件,而无需调整依赖于软件包的代码。我们还可以使包裹的某些部分不可见,例如如果尚未准备好一般使用。

请注意,我们可以使用del命令,因此典型的__init __。py可能看起来像这样:

from somemodule import some_function1, some_function2, SomeObject

del somemodule

现在,如果我们决定拆分" somemodule",则新的" init.py"可能是:

from somemodule1 import some_function1, some_function2
from somemodule2 import SomeObject

del somemodule1
del somemodule2

从外部看,包装看上去仍然和以前一样。