Python:__init__.py文件和、__all__、import、__name__、__doc__


有時候,很容易忽略一些看上去不起眼的小細節,可能人總是有那么點理所當然的想法。

就像init.py文件,是不是感覺像個熟悉的陌生人?~~~

這里來淺析一下一些基礎概念(都是左右各雙下划線)。

1. __init__.py 文件:這個文件,就像一個標識符一樣,用來表明一個文件夾是python包還是一般文件夾,如果文件夾中存在該文件,就是python包;可以試試pycharm直接建立package,就會發現剛建完就已經存在__init__.py文件了。

這個文件用處:

用處一:當用於import對象時,可以識別出哪些是可以導入的包,哪些只是一般文件夾;

用處二:可以在其中導入需要的對象,然后通過在執行程序中import package來引用這些包,所以簡化了執行程序,因為每次導入package的時候會自動執行__init__.py;但最好不要在這里寫自己的模塊,該文件越簡單越好;

用處三:__all__參數,只用於指定 from package import * 時,導入的包是哪些,不需要的包可以先不導入;並不影響from package import module/package、import package.module等形式的導入。

注意:該文件可以為空,即不做操作,但是package必須要有這個文件。

2. import:用於導入包、函數、變量、類等;那么import干了些啥?(sys.path是可以修改的,且從package包導入模塊需要用 from package import ... 形式

3. __name__:用於判斷當前模塊是不是主程序文件(主執行),也就是查看 __name__ 的值是否為 '__main__' ,如果則該程序屬於主程序文件,如果不是則顯示該文件的文件名;

4. __doc__:模塊的注釋文本,例如函數或者類的說明,用 '''...''' 三引號形式包圍;

5. 示例說明

(1)首先文件夾和文件如下:可見my_init是一個python包,package_test也是一個包,my_init_2是一個普通文件夾。

(2)首先兩個 __init__.py都為空,此時import模塊的操作如下:

## import_test.py 內容

class BBB():
    def __init__(self, kk):
        self.kk = kk
        print(self.kk)
    
    def gogogo(self):
        print('---test class with import---')
        
def ss_B():
    print('---------------- this is the imported *.py file --------------')

def tt_B():
    print('this is also from imported file')

print('it is very bad')
print(__name__)

if __name__ == "__main__":
    print(__name__)
    ss_B()
  • main_test.py導入import_test模塊 —— 兩個py文件在同一目錄下
# 直接導入,main_test.py

import import_test as it
it.ss_B()
print(__name__)

很明顯,前兩個結果來自導入import_test時,自動執行了該模塊 import_test中的內容(輸出的結果1和結果2);而為啥沒繼續執行下面的 if __name__='__main__' 里面的內容,那是因為此時__name__的值為:import_test(輸出的結果2),並不是__main__,所以不會執行。

然后,結果3調用了import_test模塊內的函數,結果4返回__main__,表明當前模塊(main_test.py)屬於主程序。

  • main_test.py導入import_test模塊,同一目錄,也可以如下
# main_test.py

from
import_test import ss_B #可以直接通過py文件導入函數,模塊可以通過 from module_name import func 或者直接 import module_name;但是package要通過from package_name import module_name 或者 import package_name.module_name def ss(): print('---------------- this is the main *.py file --------------') if __name__ == "__main__": print(__name__) #用於判斷主程序是當前程序還是其他程序 ss() ss_B()

此時不能用:from my_init import import_test,為什么呢?因為my_init這個文件不在搜索路徑下,但是它的子目錄在搜索路徑(D:\\Python_workspace\\Felix_test\\test_init\\my_init)下,可以使用sys.path查看:

如果要是用,需要先將該目錄加入搜索路徑(它本身的目錄為 —— D:\Python_workspace\Felix_test\test_init\my_init),通過絕對地址加入

# main_test.py

import
sys,os sys.path.append(os.path.abspath(r'D:\Python_workspace\Felix_test\test_init')) #只有test_init目錄下才包含my_init目錄 from my_init import import_test

 

  • main_test.py導入package_test包中的模塊,main_test和package_test包同一目錄
# sub_test.py 內容

def sub_packege_test():
    '''testing on the sub_packege_test doc ---'''
    print('it is a sub-package!')

則,調用時,__doc__表示說明文本(每個對象,例如函數、類、模塊都有這個屬性):

# main_test.py

from package_test import sub_test     #導入包中的文件
sub_test.sub_packege_test()
print(sub_test.sub_packege_test.__doc__)  #該函數說明

也可:

from package_test.sub_test import sub_packege_test  #導入包內*.py文件中的函數
sub_packege_test()
  • my_init_2文件夾中的test_1.py可以直接調用test_2.py,同一目錄,雖然這個文件夾不是package
# test_2.py 內容
def xx():
    print('-----what happended here-----')
print(xx())  

# ---------------------------------------------------------------------------
# test_1.py 內容 import test_2 as t2 t2.xx() print('it is test_1.py')
  • my_init_2文件夾中的test_2,無法直接import my_init包中的import_test.py模塊,需要先添加搜索路徑;反之,也可以在my_init包中的模塊,import另一個文件夾(my_init_2)中的模塊 —— 注意:這可能會失敗,因為你import的模塊有可能會導入import其他的包,但是這些其他包又不在搜索路徑中時,就會報錯。
# test_2.py 內容

import os
import sys
sys.path.append(os.path.abspath(r'D:\Python_workspace\Felix_test\test_init'))  #絕對路徑導入包,先將文件夾加入搜索路徑,然后導入;相對路徑個人感覺不太好用
from my_init import import_test

import_test.ss_B()

def xx():
    print('-----what happended here-----')
print(xx())  

所以,最好不要嵌套太多層來進行import。。。

(3)使用__init__.py方法

  • main_test.py中import package_test中的模塊

首先,修改my_init包的package_test中的__init__.py文件如下(使用__all__變量):

__all__ = ['sub_test']   #可以只選部分,不用導入過多包,只會影響 from package_test import * 中的導入結果

print('this is from __init__ file, sub-package')

然后,import使用:

# sub_test.py 內容
def sub_packege_test():
    '''testing on the sub_packege_test doc ---'''
    print('it is a sub-package!')

#-------------------------------------------------
# main_test.py
from package_test import *
sub_test.sub_packege_test()
print(__name__)
sub_test_2.sub_packege_test_2()

可見:當使用 from package_test import * 時,讀取到的包均屬於package_test的 __init__.py中 __all__變量的值,不在該變量值中的包不會讀取。

  • 此時,如果__init__.py中沒有某個模塊,而你又要使用時,可以在執行文件中自己導入
# main_test.py

from
package_test import sub_test_2 # 這種形式的導入與__init.py中的__all__參數無關 sub_test_2.sub_packege_test_2()

  • 如果,不使用__all__變量,直接在__init__.py中import需要的包
# package_test中的__init__.py文件內容:

from package_test import sub_test
print('this is from __init__ file, sub-package')

這種情況與直接在需要的地方通過from package import module,來導入模塊差不多;只不過如果使用了__init__.py文件,那么就會執行一次__init__.py文件,將所有需要的包一次性導入,在執行文件中就不需要寫很多import語句,而只需要導入包package即可,然后通過包來引用模塊;同時此時如果該文件里面還有其他代碼也會執行。

# main_test.py

from package_test import sub_test    #這種形式,如果有很多包則會比較麻煩
#import sub_test   #直接導入該模塊不行
sub_test.sub_packege_test()


# 所以可以這樣,通過package包來引用,如果在__init__.py中寫了很多個from package import module,則都可以這樣使用;也就是簡化了很多import語句
# main_test.py
import package_test package_test.sub_test.sub_packege_test()

 

注意:

1. from module/package import func/module:只是將某模塊或者package的一部分導入當前命名空間;

2. import語句中,如果導入的是模塊則會執行該模塊代碼;如果是package,則會執行package包的__init__.py文件;

3. sys.modules 和 sys.path的官方鏈接、解釋:

4. __init__.py文件越簡單越好,也可以為空。

5. __init__.py的import操作,主要是可以簡化執行程序中的import語句;而__all__只用於控制from package import * 中導入的包。

6. 以上都是用的絕對導入import;其中相對導入和絕對導入

 

#

參考:

https://blog.csdn.net/fitzzhang/article/details/78988155

https://www.jianshu.com/p/dacbed54d063

https://www.runoob.com/python/python-modules.html

https://blog.csdn.net/weixin_38256474/article/details/81228492

https://www.cnblogs.com/byronsh/p/10745292.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM