向__ init__. py 添加代码

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

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

但是 django 添加了一些 from... import... 语句,并在 __init__.py中定义了一些类。为什么?这不是让事情看起来很混乱吗?为什么在 __init__.py中需要这个代码?

74238 次浏览

All imports in __init__.py are made available when you import the package (directory) that contains it.

Example:

./dir/__init__.py:

import something

./test.py:

import dir
# can now use dir.something

EDIT: forgot to mention, the code in __init__.py runs the first time you import any module from that directory. So it's normally a good place to put any package-level initialisation code.

EDIT2: dgrant pointed out to a possible confusion in my example. In __init__.py import something can import any module, not necessary from the package. For example, we can replace it with import datetime, then in our top level test.py both of these snippets will work:

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

and

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

The bottom line is: all names assigned in __init__.py, be it imported modules, functions or classes, are automatically available in the package namespace whenever you import the package or a module in the package.

It's just personal preference really, and has to do with the layout of your python modules.

Let's say you have a module called erikutils. There are two ways that it can be a module, either you have a file called erikutils.py on your sys.path or you have a directory called erikutils on your sys.path with an empty sys.path0 file inside it. Then let's say you have a bunch of modules called fileutils, procutils, parseutils and you want those to be sub-modules under erikutils. So you make some .py files called sys.path1, sys.path2, and sys.path3:

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

Maybe you have a few functions that just don't belong in the fileutils, procutils, or parseutils modules. And let's say you don't feel like creating a new module called miscutils. AND, you'd like to be able to call the function like so:

erikutils.foo()
erikutils.bar()

rather than doing

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

So because the erikutils module is a directory, not a file, we have to define it's functions inside the __init__.py file.

In django, the best example I can think of is django.db.models.fields. ALL the django *Field classes are defined in the __init__.py file in the django/db/models/fields directory. I guess they did this because they didn't want to cram everything into a hypothetical django/db/models/fields.py model, so they split it out into a few submodules (related.py, files.py, for example) and they stuck the made *Field definitions in the fields module itself (hence, __init__.py).

Using the __init__.py file allows you to make the internal package structure invisible from the outside. If the internal structure changes (e.g. because you split one fat module into two) you only have to adjust the __init__.py file, but not the code that depends on the package. You can also make parts of your package invisible, e.g. if they are not ready for general usage.

Note that you can use the del command, so a typical __init__.py may look like this:

from somemodule import some_function1, some_function2, SomeObject


del somemodule

Now if you decide to split somemodule the new __init__.py might be:

from somemodule1 import some_function1, some_function2
from somemodule2 import SomeObject


del somemodule1
del somemodule2

From the outside the package still looks exactly as before.

"We recommend not putting much code in an __init__.py file, though. Programmers do not expect actual logic to happen in this file, and much like with from x import *, it can trip them up if they are looking for the declaration of a particular piece of code and can't find it until they check __init__.py. "

-- Python Object-Oriented Programming Fourth Edition Steven F. Lott Dusty Phillips