Python模塊和包

来源:https://www.cnblogs.com/wangyueping/archive/2019/07/03/11112933.html
-Advertisement-
Play Games

Python模塊和包 一、模塊 1. 什麼是模塊 常見的場景:一個模塊就是一個包含了Python定義和聲明的文件,文件名就是模塊名字加上.py的尾碼。 但其實import載入的模塊分為四個通用類別: 1 使用Python編寫的代碼(.py文件) 2 已被編譯為共用庫或DLL的C或C++擴展 3 包好 ...


Python模塊和包

一、模塊

  1. 什麼是模塊

    常見的場景:一個模塊就是一個包含了Python定義和聲明的文件,文件名就是模塊名字加上.py的尾碼。

    但其實import載入的模塊分為四個通用類別: 

      1 使用Python編寫的代碼(.py文件)

      2 已被編譯為共用庫或DLL的C或C++擴展

      3 包好一組模塊的包

      4 使用C編寫並鏈接到Python解釋器的內置模塊

  2. 為什麼要使用模塊

    如果你退出python解釋器然後重新進入,那麼你之前定義的函數或者變數都將丟失,因此我們通常將程式寫到文件中以便永久保存下來,需要時就通過python test.py方式去執行,此時test.py被稱為腳本script。

    ​ 隨著程式的發展,功能越來越多,為了方便管理,我們通常將程式分成一個個的文件,這樣做程式的結構更清晰,方便管理。這時我們不僅僅可以把這些文件當做腳本去執行,還可以把他們當做模塊來導入到其他的模塊中,實現了功能的重覆利用。

  3. 如何使用模塊

    1. import ...

      # 自定義一個my_module.py文件(模塊)
      # 簡單的列印一句話
      print("來導入我啊,來啊來啊來啊...")
      
      
      # 在同一個目錄下的另一個py文件中導入該模塊
      import my_module
      print("小樣,看我把你弄過弄死你~")
      
      # 來導入我啊,來啊來啊來啊...
      # 小樣,看我把你弄過弄死你~

      執行完之後發現執行了模塊中的語句,列印了兩句話,由此可以推出,導入模塊時會執行該模塊中的內容,那如果重覆導入模塊是不是會多次執行模塊中的內容呢?我們接下來試試:

      # 自定義一個my_module.py文件(模塊)
      # 簡單的列印一句話
      print("來導入我啊,來啊來啊來啊...")
      
      
      # 在同一個目錄下的另一個py文件中導入該模塊
      import my_module
      print("小樣,看我把你弄過弄死你~")
      import my_module      # 再次導入模塊
      
      # 來導入我啊,來啊來啊來啊...
      # 小樣,看我把你弄過弄死你~
      # 再次導入模塊之後發現結果並沒有發現改變。

      模塊可以包含可執行的語句和函數的定義,這些語句的目的是初始化模塊,它們只在模塊名第一次遇到導入import語句時才執行(import語句是可以在程式中的任意位置使用的,且針對同一個模塊很import多次,為了防止你重覆導入,Python的優化手段是:第一次導入後就將模塊名載入到記憶體了,後續的import語句僅是對已經載入大記憶體中的模塊對象增加了一次引用,不會重新執行模塊內的語句)

      總結:首次導入模塊my_module時會做三件事:

      1. 為源文件(my_module模塊)創建新的名稱空間,在my_module中定義的函數和方法若是使用到了global時訪問的就是這個名稱空間。
      2. 在新創建的命名空間中執行模塊中包含的代碼
      3. 創建名字my_module來引用該命名空間
    2. from ... import ...

      對比import my_module,會將源文件的名稱空間'my_module'帶到當前名稱空間中,使用時必須是my_module.名字的方式

      而from 語句相當於import,也會創建新的名稱空間,但是將my_module中的名字直接導入到當前的名稱空間中,在當前名稱空間中,直接使用名字就可以了。

      # my_module
      a = 10
      print("來導入我啊,來啊來啊來啊...")
      
      # 執行文件
      from my_module import a
      print("小樣,看我把你弄過弄死你~")
      print(a)
      
      # 來導入我啊,來啊來啊來啊...
      # 小樣,看我把你弄過弄死你~
      # 10

      如果當前有重名a,那麼會有覆蓋效果。

      # my_module
      a = 10
      print("來導入我啊,來啊來啊來啊...")
      
      # 執行文件
      from my_module import a
      print("小樣,看我把你弄過弄死你~")
      a = 20
      print(a)
      
      # 來導入我啊,來啊來啊來啊...
      # 小樣,看我把你弄過弄死你~
      # 20
    3. from ... import *

      from my_module import * 把my_module中所有的不是以下劃線(_)開頭的名字都導入到當前位置,大部分情況下我們不應該使用這種導入方式,因為*你不知道你導入什麼名字,很有可能會覆蓋掉你之前已經定義的名字。而且可讀性極其的差,在互動式環境中導入時沒有問題。

      # my_module
      a = 10
      print("來導入我啊,來啊來啊來啊...")
      def func():
          print("哈哈哈哈")
      
      # 執行文件
      from my_module import *
      print(a)
      func()
      
      # 來導入我啊,來啊來啊來啊...
      # 10
      # 哈哈哈哈

      如果你想規定別人只能導入你模塊中指定的變數時,可以在模塊中使用__all__指定別人導入特定的變數

      # my_module
      __all__ = ["func"]
      a = 10
      print("來導入我啊,來啊來啊來啊...")
      def func():
          print("哈哈哈哈")
      
      # 執行文件
      from my_module import *
      func()        # 來導入我啊,來啊來啊來啊...
      print(a)  # NameError: name 'a' is not defined
  4. 模塊的別名

    import my_module as m
    from my_module import func as f
    
    # 當對模塊進行重命名之後,指向模塊記憶體空間中的指針將會發生改變重新指向新命名的變數,即使用模塊只能用重命名之後的變數名
    
    # 模塊也可以一行導入多個
    import os, sys (不推薦)
    from my_module import a, func
  5. 模塊的迴圈引用問題

    假如有兩個模塊a,b。我可不可以在a模塊中import b ,再在b模塊中import a?

    # a模塊
    import b
    def funca():
        print("我是A")
    b.funcb()
    
    # b模塊
    import a 
    def funcb():
        print("我是B")
    a.funca()
    
    # 1、當我在a模塊運行時
    # AttributeError: module 'b' has no attribute 'funcb'
    
    # 2、當我在b模塊運行時
    # AttributeError: module 'a' has no attribute 'funca'

    為什麼相互調用時無論執行哪一個模塊都提示模塊中沒有可執行的變數呢?

    分析:在上面第3步的時候,由於迴圈導入導致b.py並沒有載入完就接著回去執行了a.py,這個時候在a.py中執行b.funcb()就會告訴你沒有這個變數。同理如果限制性b.py,就找不到funca這個變數。

  6. 模塊的載入與修改

    考慮到性能的原因,每個模塊只被導入一次,放入字典sys.modules中,如果你改變了模塊的內容,你必須重啟程式,python不支持重新載入或卸載之前導入的模塊。

    如果只是你想交互測試的一個模塊,使用 importlib.reload(), e.g. import importlib; importlib.reload(modulename),這隻能用於測試環境。

  7. 把模塊當做腳本執行

    我們可以通過模塊的全局變數__name__來查看模塊名:
    當做腳本運行:
    __name__ 等於'__main__'

    當做模塊導入:
    __name__= 模塊名

    作用:用來控制.py文件在不同的應用場景下執行不同的邏輯
    if __name__ == '__main__':

    def fib(n):   
        a, b = 0, 1
        while b < n:
            print(b, end=' ')
            a, b = b, a+b
        print()
    
    if __name__ == "__main__":
        print(__name__)
        num = input('num :')
        fib(int(num))
  8. 模塊搜索路徑

    Python解釋器在啟動時會自動載入一些模塊,可以使用sys.modules查看

    在第一次導入某個模塊時(比如my_module),會先檢查該模塊是否已經被載入到記憶體中(當前執行文件的名稱空間對應的記憶體),如果有則直接引用

    如果沒有,解釋器則會查找同名的內建模塊,如果還沒有找到就從sys.path給出的目錄列表中依次尋找my_module.py文件。

    所以總結模塊的查找順序是:記憶體中已經載入的模塊->內置模塊->sys.path路徑中包含的模塊

二、包

  1. 什麼是包

    包是一種通過使用‘.模塊名’來組織Python模塊名稱空間的方式。

    1. 無論是import形式還是from...import形式,凡是在導入語句中(而不是在使用時)遇到帶點的,都要第一時間提高警覺:這是關於包才有的導入語法
    2. 包是目錄級的(文件夾級),文件夾是用來組成py文件(包的本質就是一個包含__init__.py文件的目錄)
    3. import導入文件時,產生名稱空間中的名字來源於文件,import 包,產生的名稱空間的名字同樣來源於文件,即包下的__init__.py,導入包本質就是在導入該文件

    強調

    1. 在python3中,即使包下沒有__init__.py文件,import 包仍然不會報錯,而在python2中,包下一定要有該文件,否則import 包報錯
    2. 創建包的目的不是為了運行,而是被導入使用,記住,包只是模塊的一種形式而已,包即模塊
  2. import

    1. 創建目錄代碼

      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/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)
    2. 目錄結構

      glance/                   #Top-level package
      
      ├── __init__.py      #Initialize the glance package
      
      ├── api                  #Subpackage for api
      
      │   ├── __init__.py
      
      │   ├── policy.py
      
      │   └── versions.py
      
      ├── cmd                #Subpackage for cmd
      
      │   ├── __init__.py
      
      │   └── manage.py
      
      └── db                  #Subpackage for db
      
          ├── __init__.py
      
          └── models.py
    3. 文件內容

      #文件內容
      
      #policy.py
      def get():
          print('from policy.py')
      
      #versions.py
      def create_resource(conf):
          print('from version.py: ',conf)
      
      #manage.py
      def main():
          print('from manage.py')
      
      #models.py
      def register_models(engine):
          print('from models.py: ',engine)

    我們在與包glance同級別的文件中測試

    import glance.db.models
    glance.db.models.register_models("mysql")
    # from models.py:  mysql
  3. from ... import ...

    需要註意的是from後import導入的模塊,必須是明確的一個不能帶點,否則會有語法錯誤,如:from a import b.c是錯誤語法

    我們在與包glance同級別的文件中測試

    from glance.db import models
    from glance.api import policy
    
    models.register_models("mysql")  # from models.py:  mysql
    policy.get()               # from policy.py
  4. __init__.py文件

    不管是哪種方式,只要是第一次導入包或者是包的任何其他部分,都會依次執行包下的__init__.py文件(我們可以在每個包的文件內都列印一行內容來驗證一下),這個文件可以為空,但是也可以存放一些初始化包的代碼。

  5. from glance.api import *

    此處是想從包api中導入所有,實際上該語句只會導入包api下__init__.py文件中定義的名字,我們可以在這個文件中定義__all___:

    #在__init__.py中定義
    x=10
    
    def func():
        print('from api.__init.py')
    
    __all__=['x','func','policy']
  6. 絕對導入和相對導入

    我們的最頂級包glance是寫給別人用的,然後在glance包內部也會有彼此之間互相導入的需求,這時候就有絕對導入和相對導入兩種方式:

    絕對導入:以glance作為起始

    相對導入:用.或者..的方式最為起始(只能在一個包中使用,不能用於不同目錄內)

    例如:我們在glance/api/version.py中想要導入glance/cmd/manage.py

    # 在glance/api/version.py
    
    #絕對導入
    from glance.cmd import manage
    manage.main()
    
    #相對導入
    from ..cmd import manage
    manage.main()

    特別需要註意的是:可以用import導入內置或者第三方模塊(已經在sys.path中),但是要絕對避免使用import來導入自定義包的子模塊(沒有在sys.path中),應該使用from... import ...的絕對或者相對導入,且包的相對導入只能用from的形式。

  7. 單獨導入包

    單獨導入包名稱時不會導入包中所有包含的所有子模塊,如

    # 在glace同級文件test下
    import glance
    glance.api.policy.get()
    # AttributeError: module 'glance' has no attribute 'api'

    解決辦法:

    # 在glace包下的__init__文件中
    from . import api
    
    # 在api包下的__init__文件中
    from . import policy
    
    # 再次在glace同級文件test下執行
    import glance
    glance.api.policy.get()
    # from policy.py

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • ↵ 【編者的話】微服務的概念源於 2014 年 3 月 Martin Fowler 所寫的一篇文章“Microservices”。文中內容提到:微服務架構是一種架構模式,它提倡將單一應用程式劃分成一組小的服務,服務之間互相協調、互相配合,為用戶提供最終價值。 背景 應用系統的架構歷史 什麼是微服務? ...
  • 我們旅程的最後階段的三個主要目標是使系統對故障更具彈性,提高UI的響應能力,並確保我們的設計是可伸縮的。加強系統的工作主要集中在訂單和註冊限界上下文中的RegistrationProcessManager類。性能改進工作的重點是當訂單創建時UI與領域域模型的交互方式。 ...
  • 一年前,當我和小伙伴小龍一起做一個外包項目的時候,受到了嚴重的鄙視。我那時候還不知道 Maven,所以搭建項目用的還是最原始的方式,小龍不得已在導入項目的時候花了很長時間去下載項目依賴的開源類庫。 出於對我的尊重,小龍沒有破口大罵,而是非常委婉地說了一句:“二哥,你好歹也有一定的知名度了,竟然沒用 ...
  • Go程式是怎樣跑起來的?本文從編碼、編譯、彙編、鏈接、運行、退出這些環節一一探索。 ...
  • ![](https://img2018.cnblogs.com/blog/1728961/201907/1728961-20190703082545108-1217931464.png) ...
  • 本人在 .NET 轉JAVA 的路上 ,也在學習SpringBoot相關知識,這裡記錄一下在Springboot中實現文件上傳下載的核心代碼 源碼下載地址: https://github.com/struggle0903/SpringBootfiledemo.git ...
  • 點擊屏幕拍打你的翅膀。當你飛過屏幕時,註意黑烏鴉。 下載地址 ...
  • 看一個數組的子集有多少,其實就是排列組合, 比如:[0,1] 對應的子集有:[] [0] [1] [1,1] 這四種。 一般對應有兩種方法: 位運算 和 回溯 。 這裡先使用位運算來做。 位運算 一個長度為n的數組,對其做排列組合,可以理解為:這n個數字中,有哪些是存在的,哪些是不存在的。 例如,數 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...