1. 程式人生 > >Python基礎(十八)

Python基礎(十八)

今日主要內容

一、包

(一)什麼是包

  • 只要是含有__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'