2008-09-23 77 views
75

我正在看看django中的模型系統是如何工作的,並且我注意到了一些我不明白的東西。將代碼添加到__init__.py

我知道你創建一個空的__init__.py文件來指定當前目錄是一個包。並且您可以在__init__.py中設置一些變量,以便導入*正常工作。

但是django增加了一大堆from ... import ...語句並在__init__.py中定義了一堆類。爲什麼?這不就是讓事情看起來凌亂嗎?是否有一個原因需要__init__.py中的代碼?

+13

這不是真的關於Django嗎?是的,你首先在Django中看到了它,但這看起來更像是一個純Python的東西 - 也許Django標籤並不合適。 – 2008-09-23 12:46:20

+0

我在`__init __。py` django 1.8中看不到任何import語句。這是舊版本嗎?如果是的話哪個版本? – 2017-01-03 06:51:08

回答

67

當導入包含它的包(目錄)時,__init__.py中的所有導入都可用。

例子:

./dir/__init__.py

import something 

./test.py

import dir 
# can now use dir.something 

編輯:忘了提,在__init__.py代碼運行你第一次從目錄中導入任何模塊。所以它通常是放置任何包級初始化代碼的好地方。編輯2:dgrant在我的例子中指出了可能的混淆。在__init__.pyimport something可以導入任何模塊,從包中不需要。例如,我們可以用import datetime替換它,然後在我們的頂級test.py這兩個片斷都可以工作:

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

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

的底線是:在__init__.py分配的所有名稱,是它導入的模塊,函數或類,只要在包中導入包或模塊,就會自動在包名稱空間中使用。

+0

好的,謝謝。但我仍然不確定爲什麼將類添加到`__init __。py`中是一個好主意。我並沒有真正考慮這些類的初始化代碼(但也許我錯了)。 – Erik 2008-09-23 04:57:23

+0

這些可能是每次使用包時都很有用的類。但我不想推測,可能有很多原因,爲什麼他們在那裏,客觀或沒有:) – 2008-09-23 05:08:11

32

這真的只是個人喜好,並且與你的python模塊的佈局有關。

假設您有一個名爲erikutils的模塊。有兩種方法,它可以是一個模塊,要麼你有一個文件名爲erikutils.pysys.path或者你有一個叫做上的目錄sys.path erikutils,內帶一個空__init__.py文件。那麼假設您有一堆名爲fileutilsprocutils,parseutils的模塊,並且您希望這些模塊是erikutils下的子模塊。所以,你做一些.py文件名爲fileutils.pyprocutils.pyparseutils.py

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

也許你有,只是沒有在fileutils屬於少數的功能, procutilsparseutils模塊。假設您不想創建名爲miscutils的新模塊。而且,你希望能夠調用的函數,像這樣:

erikutils.foo() 
erikutils.bar() 

,而不是做

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

所以因爲erikutils模塊是一個目錄,而不是一個文件,我們必須定義它的功能在__init__.py文件中。

在django中,我能想到的最好例子是django.db.models.fields。所有的django *字段類都是在__init__.py文件中定義的django/db/models /字段目錄中。我猜他們這樣做是因爲他們不希望所有東西都塞進一個假設的Django/DB /模型/ fields.py模式,所以他們分裂出來成幾個子模塊(related.pyfiles.py例如),他們將製作的*字段定義粘貼在字段模塊本身中(因此,__init__.py)。

26

使用__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 

從包裝的外觀仍然與以前完全一樣。