python編譯相關

来源:https://www.cnblogs.com/aster-ist/p/18014685
-Advertisement-
Play Games

python編譯相關 具體編譯步驟 Python代碼的編譯和執行過程可以更詳細地描述如下: 詞法分析(Lexical Analysis)和語法分析(Syntax Analysis): Python解釋器首先會對源代碼進行詞法分析和語法分析。詞法分析器會將源代碼分解成詞法單元(tokens),這些單元 ...


python編譯相關

具體編譯步驟

Python代碼的編譯和執行過程可以更詳細地描述如下:

  1. 詞法分析(Lexical Analysis)和語法分析(Syntax Analysis)
    Python解釋器首先會對源代碼進行詞法分析和語法分析。詞法分析器會將源代碼分解成詞法單元(tokens),這些單元是語言的基本構建塊,例如關鍵字、標識符、運算符等。語法分析器會根據語言的語法規則將這些詞法單元組織成抽象語法樹(Abstract Syntax Tree,AST),這是源代碼的一種中間表示形式。

    • 抽象語法樹是什麼樣的:(舉例)

      抽象語法樹(Abstract Syntax Tree,AST)是在編譯過程中常用的一種數據結構,用於表示源代碼的語法結構。讓我們以一個簡單的Python代碼示例來說明:

      def greet(name):
          return f"Hello, {name}!"
      print(greet("Alice"))
      

      這段代碼的抽象語法樹可以如下所示(簡化表示):

      Module(
          body=[
              FunctionDef(
                  name='greet',
                  args=arguments(
      //arg 表示函數的一個參數,arguments 則表示函數定義中的參數集合。
                      args=[
                          arg(arg='name', annotation=None)
                      ],
                      defaults=[],
      //defaults:這表示位置參數的預設值。它也是一個列表,但在這個例子中是空的。如果函數的某些參數有預設值,那麼這裡會指定這些預設值。
                      kw_defaults=[],
      //kw_defaults:這表示關鍵字參數的預設值。與 defaults 類似,它也是一個列表。然而,在這個例子中也是空的,表示函數的關鍵字參數沒有預設值。
                      kwarg=None,
      //kwarg:這表示用於收集未明確定義的額外關鍵字參數的關鍵字參數的名稱。在這個例子中,它設置為 None,表示函數不接受超出明確定義的關鍵字參數之外的其他關鍵字參數。
                      kwonlyargs=[],
      //kwonlyargs:這表示僅關鍵字參數。關鍵字參數是一種只能通過關鍵字傳遞並且在參數列表中在 * 之後指定的參數。在這個例子中也是一個空列表。
                      kwargannotation=None
      //kwargannotation:這表示 kwarg 的註釋,如果有的話。註釋是可選的元數據,可以附加到函數參數上,指示參數的預期類型或用途。在這個例子中,它設置為 None,表示未為 kwarg 指定註釋。
                  ),
                  body=[
                      Return(
      //Return 表示函數的返回語句,用於從函數中返回一個值。在這裡,Return 節點表示函數的返回部分。
                          value=JoinedStr(
      //value 屬性指定了要返回的值。在這裡,value 是一個 JoinedStr 對象,它表示一個由多個字元串拼接而成的複合字元串。JoinedStr 表示一個由多個字元串組成的複合字元串。
                              values=[
      //values 屬性是一個列表,包含了組成複合字元串的各個部分。在這裡,複合字元串由 'Hello, '、Name 對象和 '!' 三部分組成。
                                  Str(s='Hello, '),
                                  FormattedValue(
      //FormattedValue 表示格式化值,用於在字元串中插入變數。value 屬性是一個 Name 對象,表示要插入的變數名。在這裡,Name(id='name', ctx=Load()) 表示要插入的變數是函數參數 name。
                                      value=Name(id='name', ctx=Load()),
                                      conversion=-1,
                                      format_spec=None
                                  ),
                                  Str(s='!')
                              ]
                          )
                      )
                  ],
                  decorator_list=[]
              ),
              Expr(
      //Expr 表示一個表達式語句,用於執行函數調用或其他表達式。
                  value=Call(
      //Call 表示函數調用表達式。func 屬性是一個 Name 對象,表示要調用的函數名。在這裡,Name(id='print', ctx=Load()) 表示要調用的函數是內置函數 print()。
                      func=Name(id='print', ctx=Load()),
                      args=[
                          Call(
                              func=Name(id='greet', ctx=Load()),
      //id 和 ctx 分別是 Name 對象的兩個屬性:id 屬性:表示標識符的名稱。在這裡,id='print' 表示標識符的名稱是 'print',即函數名或變數名為 print。ctx 屬性:表示標識符的上下文(Context)。ctx 可以指定標識符在代碼中的使用方式,例如載入(load)、存儲(store)等。在這裡,ctx=Load() 表示該標識符在這個上下文中是一個載入(load)的標識符,即在代碼中引用了名為 'print' 的函數或變數。
                              args=[
                                  Str(s='Alice')
                              ],
                              keywords=[]
                          )
                      ],
                      keywords=[]
                  )
              )
          ]
      )
      

      在這個抽象語法樹中,我們可以看到代碼中的函數定義、函數調用以及其他表達式的結構。每個節點都表示源代碼中的一個語法結構,例如函數定義、表達式等。這種抽象語法樹的表示形式使得編譯器可以更輕鬆地分析和處理源代碼,進而進行編譯和執行。

      1. 位置參數(Positional Arguments):
         位置參數是函數定義中的普通參數,它們按照在函數參數列表中的順序進行傳遞,不需要指定參數名稱。例如,在函數定義中,`def my_function(a, b):` 中的 `a` 和 `b` 就是位置參數。在調用函數時,傳遞的參數值會按照位置與位置參數一一對應。
      
      2. 預設值(Default Values):
         預設值是在函數定義中為參數提供的初始值。如果在函數調用時沒有提供對應參數的值,那麼參數將使用預設值。預設值允許函數在某些情況下以可選方式接受參數。例如,在函數定義中,`def greet(name="Guest"):`, 這裡的 `name` 參數有一個預設值 `"Guest"`。如果調用 `greet()` 時沒有傳遞參數,它將使用預設值 `"Guest"`。
      
      3. 僅關鍵字參數(Keyword-Only Arguments):
         僅關鍵字參數是只能通過關鍵字傳遞的參數,這些參數出現在函數定義中的 `*` 符號之後。這意味著在函數調用時必須使用參數名稱來傳遞這些參數值。這種類型的參數可以增加函數的靈活性和可讀性。例如,在函數定義中,`def greet(name, *, prefix="Hello"):` 中的 `prefix` 參數就是一個僅關鍵字參數。這意味著在調用 `greet()` 時必須通過關鍵字指定 `prefix` 參數的值,例如 `greet("Alice", prefix="Hi")`。
      
      4. 註釋(Annotations):
         註釋是Python中的一種元數據,用於為函數參數或變數提供類型信息或其他說明。註釋不會影響代碼的運行,但可以提供更多的信息,幫助理解代碼的含義和用法。例如,在函數定義中,`def greet(name: str):`, 這裡的 `str` 就是參數 `name` 的註釋,指示其應該是一個字元串類型。註釋可以在函數定義時使用冒號(`:`)後面的形式指定。在實際運行中,這些註釋並不會被Python解釋器使用,但可以被其他工具或IDE用來進行類型檢查或提供代碼提示。
      
      
  2. 編譯成位元組碼
    接下來,AST會被編譯成位元組碼。這個階段由Python解釋器的編譯器組件完成。位元組碼是一種中間表示形式,類似於彙編語言,它包含一系列的指令,用於執行相應的操作。位元組碼與具體的硬體和操作系統無關,也就是說生成的位元組碼可以在任何支持Python解釋器的平臺上執行,而不需要重新編譯。

  3. 執行位元組碼
    Python虛擬機(Python Virtual Machine,簡稱為VM)會負責執行位元組碼。虛擬機是一個解釋器,它按照位元組碼中的指令逐條執行。在執行過程中,虛擬機會將位元組碼轉換為機器代碼,併在底層硬體上執行。這個過程是動態的,允許Python代碼在運行時進行一些優化和動態調整。

  4. 優化和動態調整
    在執行過程中,Python解釋器還會進行一些優化和動態調整。例如,解釋器可能會對頻繁執行的代碼塊進行編譯優化,將其編譯成本地機器碼以提高執行效率。此外,解釋器還會動態地調整記憶體分配和管理策略,以最大限度地減少記憶體占用和提高性能。

  5. pyc是怎麼產生的:

    在首次運行Python程式時,解釋器會將源代碼編譯成位元組碼,並且會將這些位元組碼緩存到磁碟上的 .pyc 文件中(如果存在對應的 .py 文件)。這樣,在下次運行相同的程式時,解釋器可以直接載入 .pyc 文件,而無需重新編譯源代碼。這種緩存的機制可以加快程式的啟動速度,特別是對於大型項目或經常被重覆執行的腳本來說。需要註意的是,.pyc 文件並不是與特定機器或平臺相關的二進位文件。它們是跨平臺的中間位元組碼表示形式,因此可以在不同的平臺上被載入和執行。

整個過程中,Python代碼並不會直接編譯成機器代碼,而是先被解釋器解析為位元組碼,然後由解釋器執行位元組碼。這種解釋型的方式使得Python具有跨平臺性,因為位元組碼是與硬體無關的,只要有對應的解釋器,Python代碼就可以在不同平臺上執行。。

如何生成pyc文件

  1. 在py程式內部

    使用 Python 自帶的 py_compile 模塊來將 .py 文件編譯成 .pyc 文件。這個模塊提供了一個名為 compile 的函數,你可以使用它來編譯 Python 源文件。

    import py_compile
    
    # 指定要編譯的 Python 源文件路徑
    source_file = 'example.py'
    
    # 編譯 Python 源文件,並生成對應的 .pyc 文件
    py_compile.compile(source_file)
    

    運行這段代碼將會在源文件所在的目錄下生成一個與源文件同名的 .pyc 文件。

    compileall 模塊也是用於將 Python 源文件編譯成位元組碼文件的工具,它比 py_compile 模塊更加靈活,可以批量編譯目錄下的所有 .py 文件。

    import compileall
    
    # 指定要編譯的目錄路徑
    directory = '/path/to/directory'
    
    # 編譯目錄下的所有 Python 源文件,並生成對應的 .pyc 文件
    compileall.compile_dir(directory)
    
    

    這將會編譯指定目錄下的所有 Python 源文件,併在相同目錄下生成對應的 .pyc 文件。

  2. 使用命令行工具來編譯 Python 源文件,

    例如在命令行中執行以下命令:

    python -m py_compile example.py
    

    這將在同一目錄下生成一個名為 example.pyc 的文件。

pyo

.pyo 文件與 .pyc 文件相似,只是在優化模式下生成,並且可能會刪除一些調試信息和註釋。

在 Python 3.x 中,預設情況下,當你使用優化標誌(-O-OO)運行 Python 解釋器時,生成的位元組碼文件將使用 .pyo 擴展名而不是 .pyc。這些優化標誌會啟用優化編譯器標誌,從而在生成的位元組碼中刪除一些調試信息或註釋,以減小位元組碼文件的大小並提高執行效率。

  • O:啟用優化編譯,將會刪除 assert 語句。
  • OO:啟用更嚴格的優化,將會刪除 assert 語句以及文檔字元串(docstrings)。

生成的 .pyo 文件可以被 Python 解釋器載入和執行,與 .pyc 文件的使用方式相同。不過需要註意的是,.pyo 文件並不會自動替換 .pyc 文件,而是作為 .pyc 文件的一個替代品。因此,如果你在優化模式下運行了一個 Python 腳本,它會生成一個 .pyo 文件,但如果以普通模式再次運行同一個腳本,它還是會生成 .pyc 文件。

拿到pyc文件後反編譯回py文件

利用uncompyle6 這個Python 反編譯工具它用於將 Python 位元組碼文件(.pyc.pyo 文件)反編譯回等效的 Python 源代碼。

直接在命令行中安裝 uncompyle6 就可以用了

pip install uncompyle6

安裝完成後,就可以使用以下命令將位元組碼文件反編譯為 Python 源代碼:

uncompyle6 sample.pyc > sample.py

或者,如果是一個 .pyo 文件,也可以用相同的方式進行反編譯:

uncompyle6 sample.pyo > sample.py

解釋和編譯

編譯器:先整體編譯再執行

解釋器:邊解釋邊執行

優缺點:

編譯方式:運行速度快,但是任何的改動都要整體重新編譯。可以脫離編譯環境運行。C語言

解釋方式:運行速度慢,但是部分的改動不需要整體重新編譯。不可以脫離解釋器環境運行。python

說是python慢,但是也有優化速度的方式,也就是生成pyc文件的方式。參考了JAVA的位元組碼做法,但並不完全相同。其作用就是減少重覆的解釋工作。

Python 有幾種不同的解釋器

最常見的包括:

  1. CPython:CPython 是 Python 的官方解釋器,它是使用 C 語言實現的。CPython 是最常用的 Python 解釋器,它執行 Python 代碼,並提供了許多標準庫和擴展模塊。
  2. Jython:Jython 是一個在 Java 平臺上運行的 Python 解釋器。它將 Python 代碼編譯成 Java 位元組碼,然後在 Java 虛擬機(JVM)上執行。Jython 可以直接調用 Java 類庫,並且與 Java 代碼可以無縫集成。
  3. IronPython:IronPython 是一個在 .NET 平臺上運行的 Python 解釋器。它將 Python 代碼編譯成 .NET 中間語言(CIL),然後在 .NET 運行時上執行。IronPython 可以與 .NET 框架和庫進行交互,並且可以通過使用 .NET 語言擴展 Python。
  4. PyPy:PyPy 是一個用 Python 實現的解釋器,它旨在提供更高的性能。PyPy 使用即時(JIT)編譯技術來動態優化 Python 代碼,並且通常比 CPython 提供更好的性能。

除了這些常見的解釋器之外,還有一些其他的 Python 解釋器,例如 MicroPython(針對嵌入式系統)、Stackless Python(用於併發編程)、Pyston(用於性能優化)、Nuitka(將 Python 代碼編譯成 C 或 C++)、Shed Skin(將 Python 代碼轉換成 C++)等。


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

-Advertisement-
Play Games
更多相關文章
  • 由於兩個月的奮戰,導致很久沒更新了。就是上回老周說的那個產線和機械手搬貨的項目,好不容易等到工廠放假了,我就偷偷樂了。當然也過年了,老周先給大伙伴們拜年了,P話不多講,就祝大家身體健康、生活愉快。其實生活和健康是密不可分的,想活得好,就得健康。包括身體健康、思想健康、心理健康、精神健康。不能以為我無 ...
  • MiniExcel簡介 簡單、高效避免OOM的.NET處理Excel查、寫、填充數據工具。 目前主流框架大多需要將數據全載入到記憶體方便操作,但這會導致記憶體消耗問題,MiniExcel 嘗試以 Stream 角度寫底層演算法邏輯,能讓原本1000多MB占用降低到幾MB,避免記憶體不夠情況。 特點: 低記憶體 ...
  • 什麼是值轉換器 在WPF(Windows Presentation Foundation)中,值轉換器(Value Converter)是一種機制,允許你在綁定時轉換綁定源和綁定目標之間的值。值轉換器實現了 IValueConverter 介面,該介面包含兩個方法:Convert 和 Convert ...
  • 最近在折騰微信相關的開發,包括公眾號、企業微信內部應用、企業微信第三方開發。基於Razor方式寫了: 企業微信內部應用的類庫 企業微信第三方應用的類庫 公眾號的類庫 一個統一管理公眾號、企業微信內部應用和第三方應用有關授權、Token之類的應用。 然後準備寫一個開源的簡單的酒店管理系統,名字的想好了 ...
  • 我在給雲伺服器配置本地電腦免密登錄的過程中,學習了一下SSH免密登錄的實現原理。 對SSH中輸入密碼登錄和免密登錄的原理根據自己的理解做瞭如下筆記,分享給大家希望能有所幫助。 1. 對稱加密 對稱加密是加密過程中只有一個密鑰,加密解密都只用這個密鑰。 加密通訊至少要有一對通訊對象,對稱加密的問題主要 ...
  • 概述 隨著互聯網的發展,軟體系統由原來的單體應用轉變為分散式應用。分散式系統把一個單體應用拆分為可獨立部署的多個服務,因此需要服務與服務之間遠程協作才能完成事務操作。這種分散式系統下不同服務之間通過遠程協作完成的事務稱之為分散式事務,例如用戶註冊送積分事務、創建訂單減庫存事務,銀行轉賬事務等都是分佈 ...
  • 在Mysql資料庫中,模糊搜索通常使用LIKE關鍵字。然而,隨著數據量的不斷增加,Mysql在處理模糊搜索時可能面臨性能瓶頸。因此,引入Elasticsearch作為搜索引擎,以提高搜索性能和用戶體驗成為一種合理的選擇。 1、客戶的訴求 在ES中,影響搜索結果的因素多種多樣,包括分詞器、Match搜 ...
  • pandas的DataFrame功能強大自不必說,它可以幫助我們極大的提高統計分析的效率。 不過,使用DataFrame開發我們的分析程式的時候,經常需要列印出DataFrame的內容,以驗證和調試數據的處理是否正確。 在命令行中雖然可以直接列印出DataFrame的內容,但是閱讀比較困難。正好前段 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...