Python基礎(十八)

  • 2019 年 10 月 7 日
  • 筆記

今日主要內容

  • 包

一、包

(一)什麼是包

  • 只要是含有__init__.py文件的文件夾就是一個包
  • 包的本質其實就是一個文件夾,利用包將不同功能的模組組織起來,以此來提高程式的結構性和可維護性
  • 包是用來導入的,不是用來執行的,所以它和軟體開發規範分文件管理還是有區別的,一個是項目,一個是用來導入的包
  • 正因為包是用來導入的,所以運行文件一定要放在包的外面

(二)創建一個包

  • 利用程式碼創建一個包

    import os  os.makedirs('glance/api')  os.makedirs('glance/cmd')  os.makedirs('glance/db')  l = []  l.append(open('glance/__init__.py','w'))  l.append(open('glance/test.py','w'))  l.append(open('glance/api/__init__.py','w'))  l.append(open('glance/api/policy.py','w'))  l.append(open('glance/api/versions.py','w'))  l.append(open('glance/cmd/__init__.py','w'))  l.append(open('glance/cmd/manage.py','w'))  l.append(open('glance/db/models.py','w'))  map(lambda f:f.close() ,l)
    • 下述所有內容,均以此圖結構為基礎

(三)__init__.py文件

  • 在我們導入包的時候,其實本質上導入的就是__init__.py文件,解釋器會自動執行__init__.py文件中的內容

    # glance/__init__.py  print("這裡是glance下的__init__.py文件")    # run.py  import glance    運行結果:  這裡是glance下的__init__.py文件

(四)包的導入

  • 包的導入,須注意兩點內容:
    • 導入時無論是使用import還是使用from xxx import xxx導入,點的前面必須是一個包
    • 使用from xxx import xxx導入時,import前可以出現點,import後不能出現點
  1. 常規導入

    • import導入
    # policy.py  def policy_func():   print("這是policy文件中的函數")    # run.py  import glance.api.policy    glance.api.policy.policy_func()    運行結果:  這是policy文件中的函數  # 成功導入
    • from import導入
    # policy.py  def policy_func():   print("這是policy文件中的函數")    # run.py  from glance.api.policy import policy_func    policy_func()    運行結果:  這是policy文件中的函數  # 成功導入
  2. 包內部之間的導入:

    • 包內部之間的相互引用,只能用絕對導入和相對導入,不能直接導入,比如policy.py文件需要導入versions.py文件中的函數,如果直接import導入會報找不到該模組的錯誤

      • 包內部互相引用的時候不能直接導入
      # versions.py  def versions_func():      print("這是versions文件中的函數")    # policy.py  import versions  # 直接導入versions模組,在外面的run文件中運行,就無法找到versions模組    def policy_func():      versions.versions_func()      print("這是policy文件中的函數")    # run.py  from glance.api import policy    policy.policy_func()    運行結果:  ModuleNotFoundError: No module named 'versions'
      • 原因分析:如果直接在policy文件中運行程式,完全沒有問題,因為此時policy文件的模組查找路徑中包含versions模組,但是**包是用來導入的,如果在包外的run文件中導入policy模組,此時模組查找路徑就變為了run文件所在的路徑,所以當policy文件導入versions模組時,路徑下並沒有versions模組,所以找不到該模組
    • 絕對導入:

    # versions.py  def versions_func():      print("這是versions文件中的函數")    # policy.py  from glance.api import versions    def policy_func():      versions.versions_func()      print("這是policy文件中的函數")    # run.py  from glance.api import policy    policy.policy_func()    運行結果:  這是versions文件中的函數  這是policy文件中的函數
    • 相對導入:
    # versions.py  def versions_func():      print("這是versions文件中的函數")    # policy.py  from . import versions    def policy_func():      versions.versions_func()      print("這是policy文件中的函數")    # run.py  from glance.api import policy    policy.policy_func()    運行結果:  這是versions文件中的函數  這是policy文件中的函數
    • 只要使用了相對導入的模組,只能作為模組使用,不能作為腳本(終端中直接運行的文件成為腳本)使用,說白了就是不能直接運行
    # versions.py  def versions_func():      print("這是versions文件中的函數")    # policy.py  from . import versions    def policy_func():      versions.versions_func()      print("這是policy文件中的函數")    運行結果:  ImportError: cannot import name 'versions'
  3. 單獨導入包,並使用包內的包或模組

    • 單獨導入一個包,其本質上導入的只是__init__.py文件,包中其他的文件並沒有被導入
    # policy.py  def policy_func():      print("這是policy文件中的函數")    # run.py  import glance  # 只導入了__init__.py文件    glance.api.policy.policy_func()  # 並不能使用    運行結果:  AttributeError: module 'glance' has no attribute 'policy'  
    • 此時就要利用到__init__.py文件了,__init__.py文件在包中起到了交接管理的作用,可以在__init__.py文件中導入每個子文件,也可以控制其是否能被導入,所以每一個包中必須要有__init__.py文件
    # policy.py  def policy_func():      print("這是policy文件中的函數")    # glance/__init__.py  from . import api    # glance/api/__init__.py  from . import policy    # run.py  import glance    glance.api.policy.policy_func()    運行結果:  這是policy文件中的函數  
    • 直接調用模組中的方法
    # policy.py  def policy_func():      print("這是policy文件中的函數")    # glance/__init__.py  from .api import *    # glance/api/__init__.py  from .policy import *    # run.py  import glance    glance.policy_func()    運行結果:  這是policy文件中的函數  
    • 還可以通過__all__來控制模組和模組中函數的導入

      • 控制模組導入
      # glance/__init__.py  from .api import *    # glance/api/__init__.py  __all__ = ["versions"]  # 只能導入versions,其餘api下模組都不能被導入    # run.py  import glance    glance.policy    運行結果:  AttributeError: module 'glance' has no attribute 'policy'  
      • 控制方法導入
      # policy.py  def policy_func():      print("這是policy文件中的func")    def policy_foo():     print("這是policy文件中的foo")    # glance/__init__.py  from .api import *    # glance/api/__init__.py  from .policy import *  __all__ = ["policy_foo"]  # 控制只能導入foo函數,其餘函數都不能被導入    # run.py  import glance    glance.policy_func()    運行結果:  AttributeError: module 'glance' has no attribute 'policy_func'  

Tags: