Python 快速指南



Python - 概述

Python 是一種高階多正規化程式語言。由於 Python 是一種基於直譯器的語言,因此與其他一些主流語言相比,它更容易學習。Python 是一種動態型別語言,具有非常直觀的資料型別。

Python 是一種開源的跨平臺程式語言。它可在所有主要的 Linux、Windows 和 Mac OS 作業系統平臺上根據Python 軟體基金會許可證(與 GNU 通用公共許可證相容)使用。

Python 的設計理念強調簡潔、可讀性和明確性。Python 以其“包含電池”的方法而聞名,因為 Python 軟體附帶了全面的標準函式和模組庫。

Python 的設計理念記錄在Python 之禪中。它包含 19 條格言,例如:

  • 優美勝於醜陋
  • 明瞭勝於晦澀
  • 簡潔勝於複雜
  • 複雜勝於凌亂

要獲取完整的 Python 之禪文件,請在 Python shell 中輸入import this

>>> import this
The Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

Python 支援命令式、結構化以及面向物件的程式設計方法。它也提供函數語言程式設計的功能。

Python - 歷史

荷蘭程式設計師Guido Van Rossum 建立了 Python 程式語言。在 80 年代後期,他曾在荷蘭名為Centrum Wiskunde & Informatica (CWI) 的計算機科學研究所從事 ABC 語言的開發工作。1991 年,Van Rossum 構思併發布了 Python 作為 ABC 語言的繼任者。

對於許多不瞭解 Python 的人來說,“Python”這個詞與一種蛇有關。然而,Rossum 將選擇“Python”這個名字歸功於 BBC 的熱門喜劇系列“蒙提·派森的飛行馬戲團”。

作為 Python 的首席架構師,開發者社群授予他“終身仁慈獨裁者”(BDFL)的稱號。然而,在 2018 年,Rossum 放棄了這個稱號。此後,Python 參考實現的開發和分發由非營利組織Python 軟體基金會負責。

Python 歷史上重要的階段:

Python 0.9.0

Python 的第一個公開版本是 0.9。它於 1991 年 2 月釋出。它包含對核心面向物件程式設計原則的支援。

Python 1.0

1994 年 1 月釋出了 1.0 版本,其中包含函數語言程式設計工具,以及對複數等的支援。

Python 2.0

下一個主要版本——Python 2.0 於 2000 年 10 月釋出。它包含許多新特性,如列表推導式、垃圾收集和 Unicode 支援。

Python 3.0

Python 3.0是Python的一個完全改版版本,於2008年12月釋出。此次改版的首要目標是消除Python 2.x版本中出現的大量差異。Python 3向後移植到Python 2.6。它還包含一個名為python2to3的實用程式,用於促進Python 2程式碼到Python 3的自動轉換。

Python 2.x生命週期結束

即使在Python 3釋出之後,Python軟體基金會也繼續支援Python 2分支,併發布增量微版本,直到2019年。但是,它決定在2020年底停止支援,當時Python 2.7.17是該分支中的最後一個版本。

當前版本

與此同時,Python的3.x分支中集成了越來越多的功能。截至目前,Python 3.11.2是2023年2月釋出的當前穩定版本。

Python 3.11的新功能

Python 3.11最重要的功能之一是速度的顯著提高。根據Python的官方文件,此版本的速度比前一個版本(3.10)快高達60%。它還指出,標準基準測試套件顯示執行速度提高了25%。

  • Python 3.11改進了異常訊息。發生異常時,它不會生成冗長的回溯資訊,而是直接顯示導致錯誤的確切表示式。

  • 根據PEP 678的建議,add_note()方法被新增到BaseException類中。您可以在except子句中呼叫此方法並傳遞自定義錯誤訊息。

  • 它還在maths模組中添加了cbroot()函式。它返回給定數字的立方根。

  • 標準庫中添加了一個新的模組tomllib。可以使用tomllib模組函式解析TOML(Tom's Obvious Minimal Language)。

Python - 特性

在本章中,讓我們重點介紹一些使Python廣受歡迎的重要特性。

Python易於學習

這是Python流行的最重要原因之一。Python的關鍵字集有限。其特性如簡單的語法、使用縮排避免大括號的混亂以及不需要預先宣告變數的動態型別,幫助初學者快速輕鬆地學習Python。

Python是基於直譯器的

任何程式語言中的指令都必須轉換為機器程式碼才能由處理器執行。程式語言要麼基於編譯器,要麼基於直譯器。

對於編譯器,會生成整個源程式的機器語言版本。即使只有一個錯誤語句,轉換也會失敗。因此,對於初學者來說,開發過程很繁瑣。C系列語言(包括C、C++、Java、C#等)都是基於編譯器的。

Python是一種基於直譯器的語言。直譯器一次從原始碼中獲取一條指令,將其轉換為機器程式碼並執行它。在第一次出現錯誤之前的指令將被執行。憑藉此功能,更容易除錯程式,因此對於初級程式設計師來說,它有助於逐步增強信心。因此,Python是一種對初學者友好的語言。

Python是互動式的

標準Python發行版帶有一個互動式shell,其工作原理是REPL(讀取-評估-列印-迴圈)。shell顯示Python提示符>>>。您可以鍵入任何有效的Python表示式並按Enter鍵。Python直譯器會立即返回響應,並且提示符將返回以讀取下一個表示式。

>>> 2*3+1
7
>>> print ("Hello World")
Hello World

互動模式特別有用,可以熟悉庫並測試其功能。您可以在編寫程式之前在互動模式下嘗試小的程式碼片段。

Python是多正規化的

Python是一種完全面向物件的語言。Python程式中的所有內容都是物件。但是,Python可以方便地封裝其面向物件特性,用作命令式或過程式語言——例如C。Python還提供了一些類似於函數語言程式設計的功能。此外,還開發了一些第三方工具來支援其他程式設計正規化,例如面向方面程式設計和邏輯程式設計。

Python的標準庫

儘管它只有很少的關鍵字(只有35個),但Python軟體卻附帶了一個由大量模組和包組成的標準庫。因此,Python對程式設計需求(如序列化、資料壓縮、網際網路資料處理等等)提供了開箱即用的支援。Python以其“自帶電池”的方式而聞名。

Python Important Features

Python是開源的和跨平臺的

Python的標準發行版可以從https://python.club.tw/downloads/免費下載,沒有任何限制。您可以下載適用於各種作業系統的預編譯二進位制檔案。此外,原始碼也是免費提供的,這就是它屬於開源類別的原因。

Python軟體(以及文件)是在Python軟體基金會許可下發布的。這是一個BSD風格的寬鬆軟體許可證,並且與GNU GPL(通用公共許可證)相容。

Python是一種跨平臺語言。預編譯的二進位制檔案可用於各種作業系統平臺,例如Windows、Linux、Mac OS、Android OS。Python的參考實現稱為CPython,是用C語言編寫的。您可以下載原始碼併為您的作業系統平臺進行編譯。

Python程式首先編譯成一箇中間平臺無關的位元組碼。然後,直譯器中的虛擬機器執行位元組碼。這種行為使Python成為一種跨平臺語言,因此Python程式可以輕鬆地從一個作業系統平臺移植到另一個作業系統平臺。

Python用於GUI應用程式

Python的標準發行版有一個優秀的圖形庫,稱為TKinter。它是對廣受歡迎的GUI工具包TCL/Tk的Python移植。您可以在Python中構建具有吸引力的使用者友好型GUI應用程式。GUI工具包通常是用C/C++編寫的。許多工具包已被移植到Python。例如PyQt、WxWidgets、PySimpleGUI等。

Python的資料庫連線

幾乎任何型別的資料庫都可以用作Python應用程式的後端。DB-API是一組資料庫驅動程式軟體規範,用於讓Python與關係資料庫通訊。使用許多第三方庫,Python也可以與MongoDB等NoSQL資料庫一起工作。

Python是可擴充套件的

可擴充套件性是指新增新功能或修改現有功能的能力。如前所述,CPython(Python的參考實現)是用C語言編寫的。因此,可以輕鬆地用C語言編寫模組/庫並將它們合併到標準庫中。Python還有其他實現,例如Jython(用Java編寫)和IPython(用C#編寫)。因此,可以使用Java和C#分別編寫和合並這些實現中的新功能。

Python活躍的開發者社群

由於Python的流行和開源性質,大量的Python開發者經常在線上論壇和會議上互動。Python軟體基金會也擁有龐大的成員基礎,參與該組織的使命是“推廣、保護和發展Python程式語言”。

Python也享有重要的機構支援。主要的IT公司谷歌、微軟和Meta透過準備文件和其他資源做出了巨大貢獻。

Python vs C++

Python和C++都是最流行的程式語言之一。它們都有各自的優點和缺點。在本章中,我們將瞭解它們的特性。

編譯型與解釋型

與C語言一樣,C++也是一種基於編譯器的語言。編譯器將整個程式碼轉換為特定於所用作業系統的機器語言程式碼和處理器架構。

Python是基於直譯器的語言。直譯器逐行執行原始碼。

跨平臺性

當在Linux上編譯C++原始碼(例如hello.cpp)時,它只能在任何其他執行Linux作業系統的計算機上執行。如果需要在其他作業系統上執行,則需要重新編譯。

Python直譯器不會生成編譯後的程式碼。原始碼在每次在任何作業系統上執行時都會轉換為位元組碼,無需任何更改或額外步驟。

可移植性

Python程式碼很容易從一個作業系統移植到另一個作業系統。C++程式碼不可移植,因為如果作業系統發生更改,則必須重新編譯。

開發速度

C++程式編譯成機器程式碼。因此,它的執行速度比基於直譯器的語言快。

Python直譯器不會生成機器程式碼。中間位元組碼到機器語言的轉換在每次程式執行時都會進行。

如果程式需要頻繁使用,則C++比Python更高效。

易於學習

與C++相比,Python具有更簡單的語法。其程式碼更易於閱讀。一開始編寫C++程式碼看起來很 daunting,因為語法規則很複雜,例如使用大括號和分號來結束語句。

Python不使用大括號來標記語句塊。相反,它使用縮排。相同縮排級別的語句構成一個塊。這使得Python程式更易於閱讀。

靜態型別與動態型別

C++是一種靜態型別語言。儲存資料的變數型別需要在開始時宣告。未宣告的變數不能使用。一旦宣告變數的型別,就只能將該型別的數值儲存在其中。

Python是一種動態型別語言。它不需要在賦值之前宣告變數。由於變數可以儲存任何型別的資料,因此它被稱為動態型別。

面向物件概念

C++和Python都實現了面向物件程式設計的概念。C++比Python更接近OOP理論。C++支援資料封裝的概念,因為變數的可見性可以定義為公共的、私有的和受保護的。

Python沒有定義可見性的規定。與C++不同,Python不支援方法過載。因為它被動態型別化,所以預設情況下所有方法都是多型的。

C++實際上是C的擴充套件。可以說,在C中添加了額外的關鍵字以便它支援OOP。因此,我們可以在C++中編寫C型別的過程式程式。

Python是一種完全面向物件的語言。Python的資料模型是這樣的,即使您可以採用過程式方法,Python內部也會使用面向物件的方法。

垃圾回收

C++使用指標的概念。C++程式中未使用的記憶體不會自動清除。在C++中,垃圾回收過程是手動進行的。因此,C++程式可能會遇到與記憶體相關的異常行為。

Python具有自動垃圾回收機制。因此,Python程式更健壯,並且不太容易出現與記憶體相關的錯誤。

應用領域

因為C++程式直接編譯成機器程式碼,所以它更適合系統程式設計、編寫裝置驅動程式、嵌入式系統和作業系統實用程式。

Python程式適合應用程式程式設計。它目前的應用領域主要是資料科學、機器學習、API開發等。

下表總結了C++和Python的比較:

標準 C++ Python
執行 基於編譯器 基於直譯器
型別 靜態型別 動態型別
可移植性 不可移植 高度可移植
垃圾回收 手動 自動
語法 繁瑣 簡單
效能 執行速度更快 執行速度較慢
應用領域 嵌入式系統、裝置驅動程式 機器學習、Web應用程式

Python - Hello World 程式

“Hello World”程式是用通用程式語言編寫的基本計算機程式碼,用作測試程式。它不要求任何輸入,並在輸出控制檯上顯示“Hello World”訊息。它用於測試編譯和執行程式所需的軟體是否已正確安裝。

使用Python直譯器顯示“Hello World”訊息非常容易。從作業系統的命令終端啟動直譯器,並從Python提示符發出print語句,如下所示:

PS C:\Users\mlath> python
Python 3.11.2 (tags/v3.11.2:878ead1, Feb 7 2023, 16:38:35) [MSC v.1934 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> print ("Hello World")
Hello World

同樣,在Linux系統中也會列印“Hello World”訊息。

mvl@GNVBGL3:~$ python3
Python 3.10.6 (main, Mar 10 2023, 10:55:28) [GCC 11.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> print ("Hello World")
Hello World

Python直譯器也可以在指令碼模式下工作。開啟任何文字編輯器,輸入以下文字並儲存為Hello.py

print ("Hello World")

對於Windows作業系統,開啟命令提示符終端(CMD)並執行程式,如下所示:

C:\Python311>python hello.py
Hello World

終端顯示“Hello World”訊息。

hello world

在Ubuntu Linux系統上工作時,您需要遵循相同的步驟,儲存程式碼並從Linux終端執行。我們使用vi編輯器儲存程式。

run on linux terminal

從Linux終端執行程式

mvl@GNVBGL3:~$ python3 hello.py
Hello World

在Linux中,您可以將Python程式轉換為可執行指令碼。程式碼中的第一條語句應該是shebang。它必須包含Python可執行檔案的路徑。在Linux中,Python安裝在/usr/bin目錄中,可執行檔案的名稱為python3。因此,我們將此語句新增到hello.py檔案中

#!/usr/bin/python3
print ("Hello World")

您還需要使用chmod +x命令授予檔案可執行許可權

mvl@GNVBGL3:~$ chmod +x hello.py

然後,您可以使用以下命令列執行程式:

mvl@GNVBGL3:~$ ./hello.py

輸出如下所示:

output hello world

因此,我們可以使用直譯器模式和指令碼模式在Python中編寫和執行“Hello World”程式。

Python - 應用領域

Python是一種通用程式語言。它適用於開發各種軟體應用程式。在過去幾年中,Python成為以下應用領域開發人員的首選語言:

用於資料科學的Python

Python在流行度排行榜上最近的迅速崛起,很大程度上是由於它的資料科學庫。Python已成為資料科學家的必備技能。如今,即時Web應用程式、移動應用程式和其他裝置會生成海量資料。Python的資料科學庫幫助公司從這些資料中生成業務洞察。

NumPy、Pandas和Matplotlib等庫廣泛用於將數學演算法應用於資料並生成視覺化效果。Anaconda和ActiveState等商業和社群Python發行版捆綁了資料科學所需的所有必要庫。

用於機器學習的Python

Scikit-learn和TensorFlow等Python庫有助於根據過去的資料構建預測趨勢(如客戶滿意度、股票預測值等)的模型。機器學習應用程式包括(但不限於)醫學診斷、統計套利、籃子分析、銷售預測等。

用於Web開發的Python

Python的Web框架促進了快速的Web應用程式開發。Django、Pyramid、Flask在Web開發人員社群中非常流行。等等,使開發和部署簡單和複雜的Web應用程式變得非常容易。

最新版本的Python提供非同步程式設計支援。現代Web框架利用此功能來開發快速高效的Web應用程式和API。

用於計算機視覺和影像處理的Python

OpenCV是一個廣泛流行的用於捕獲和處理影像的庫。影像處理演算法從影像中提取資訊,重建影像和影片資料。計算機視覺使用影像處理進行人臉檢測和模式識別。OpenCV是一個C++庫。它的Python移植由於其快速開發特性而被廣泛使用。

計算機視覺的一些應用領域包括機器人技術、工業監控和自動化、生物識別技術等。

用於嵌入式系統和物聯網的Python

Micropython(https://micropython.org/)是一個輕量級版本,尤其適用於Arduino等微控制器。許多自動化產品、機器人技術、物聯網和資訊亭應用程式都是圍繞Arduino構建的,並使用Micropython進行程式設計。Raspberry Pi也是非常流行的低成本單板計算機,用於此類應用程式。

用於作業排程和自動化的Python

Python在自動化CRON(Command Run ON)作業方面找到了其最早的應用之一。某些任務(如定期資料備份)可以用Python指令碼編寫,並安排由作業系統排程程式自動呼叫。

許多軟體產品(如Maya)嵌入Python API來編寫自動化指令碼(類似於Excel宏)。

線上嘗試Python

如果您是Python新手,建議您在繼續在計算機上安裝Python軟體之前,透過嘗試許多線上資源之一來熟悉該語言的語法和功能。

您可以從Python官方網站的主頁啟動Python互動式shell https://python.club.tw/

python's official website

在Python提示符(>>>)前面,可以輸入和評估任何有效的Python表示式。

python code

Tutorialspoint網站也有一個Coding Ground部分:

(https://tutorialspoint.tw/codingground.htm)

在這裡,您可以找到各種語言(包括Python)的線上編譯器。訪問https://tutorialspoint.tw/execute_python_online.php。您可以試驗Python直譯器的互動模式和指令碼模式。

python_coding_ground.jpg

Python - 直譯器

Python是一種基於直譯器的語言。在Linux系統中,Python的可執行檔案安裝在/usr/bin/目錄中。對於Windows,可執行檔案(python.exe)位於安裝資料夾中(例如C:\python311)。本章將介紹Python直譯器的工作原理、其互動模式和指令碼模式。

Python程式碼一次執行一條語句。Python直譯器有兩個組成部分。翻譯器檢查語句的語法。如果正確,它會生成中間位元組碼。有一個Python虛擬機器,然後將位元組碼轉換為本機二進位制程式碼並執行它。下圖說明了該機制

Python Interpreter

Python直譯器具有互動模式和指令碼模式。

互動模式

當從命令列終端啟動時沒有任何附加選項,Python提示符>>>出現,並且Python直譯器的工作原理是REPL(讀取、評估、列印、迴圈)。在Python提示符前面輸入的每個命令都會被讀取、翻譯和執行。一個典型的互動會話如下所示。

>>> price = 100
>>> qty = 5
>>> ttl = price*qty
>>> ttl
500
>>> print ("Total = ", ttl)
Total = 500

要關閉互動式會話,請輸入行尾字元(對於Linux為ctrl+D,對於Windows為ctrl+Z)。您也可以在Python提示符前鍵入quit()並按Enter鍵返回到作業系統提示符。

標準Python發行版附帶的互動式shell不具備行編輯、歷史搜尋、自動完成等功能。您可以使用其他高階互動式直譯器軟體,例如IPythonbpython

指令碼模式

無需像在互動式環境中那樣一次輸入並獲得一條指令的結果,而是可以將一組指令儲存在文字檔案中,確保其具有.py副檔名,並將名稱用作Python命令的命令列引數。

使用任何文字編輯器(例如Linux上的vim或Windows上的Notepad)將以下幾行儲存為prog1.py

print ("My first program")
price = 100
qty = 5
ttl = price*qty
print ("Total = ", ttl)

使用此名稱作為命令列引數啟動Python。

C:\Users\Acer>python prog1.py
My first program
Total = 500

請注意,即使Python執行整個指令碼,它仍然是一次執行一條語句。

對於Java等基於編譯器的語言,除非整個程式碼沒有錯誤,否則不會將原始碼轉換為位元組碼。另一方面,在Python中,語句會一直執行到遇到第一個錯誤為止。

讓我們故意在上述程式碼中引入一個錯誤。

print ("My first program")
price = 100
qty = 5
ttl = prive*qty #Error in this statement
print ("Total = ", ttl)

請注意拼寫錯誤的變數prive而不是price。嘗試像以前一樣再次執行指令碼:

C:\Users\Acer>python prog1.py
My first program
Traceback (most recent call last):
  File "C:\Python311\prog1.py", line 4, in <module>
   ttl = prive*qty
   ^^^^^
NameError: name 'prive' is not defined. Did you mean: 'price'?

請注意,錯誤語句之前的語句已執行,然後出現錯誤訊息。因此,現在很清楚Python指令碼是以解釋方式執行的。

除了像上面那樣執行Python指令碼之外,指令碼本身也可以在Linux中像shell指令碼一樣成為自執行指令碼。您必須在指令碼頂部新增一行shebang。shebang指示哪個可執行檔案用於解釋指令碼中的Python語句。指令碼的第一行以#!開頭,後跟Python可執行檔案的路徑。

修改prog1.py指令碼如下:

#! /usr/bin/python3.11
print ("My first program")
price = 100
qty = 5
ttl = price*qty
print ("Total = ", ttl)

要將指令碼標記為自執行指令碼,請使用chmod命令

user@ubuntu20:~$ chmod +x prog1.py

您現在可以直接執行指令碼,而無需將其用作命令列引數。

user@ubuntu20:~$ ./hello.py

IPython

IPython(代表Interactive Python)是一個增強的、功能強大的Python互動式環境,與標準Python shell相比,它具有許多功能。IPython最初由Fernando Perez於2001年開發。

IPython具有以下重要特性:

  • IPython的物件自省能力,可以在執行時檢查物件的屬性。

  • 它的語法高亮顯示有助於識別語言元素,例如關鍵字、變數等。

  • 互動歷史被內部儲存,可以重現。

  • 關鍵字、變數和函式名稱的製表符完成是最重要的功能之一。

  • IPython的Magic命令系統可用於控制Python環境和執行作業系統任務。

  • 它是Jupyter筆記本和其他Jupyter專案的前端工具的主要核心。

使用PIP安裝程式實用程式安裝IPython。

pip3 install ipython

從命令列啟動IPython

C:\Users\Acer>ipython
Python 3.11.2 (tags/v3.11.2:878ead1, Feb 7 2023, 16:38:35) [MSC v.1934
64 bit (AMD64)] on win32
Type 'copyright', 'credits' or 'license' for more information
IPython 8.4.0 -- An enhanced Interactive Python. Type '?' for help.
In [1]:

與標準直譯器中的常規>>>提示符不同,您會注意到兩個主要的IPython提示符,如下所述:

  • In[1]出現在任何輸入表示式之前。

  • Out[1]出現在輸出出現之前。

In [1]: price = 100
In [2]: quantity = 5
In [3]: ttl = price*quantity
In [4]: ttl
Out[4]: 500
In [5]:

製表符完成是IPython提供的最有用的增強功能之一。當您在物件前面的點之後按製表鍵時,IPython會彈出相應的合適方法列表。

在以下示例中,定義了一個字串。在“.”符號後按製表鍵,作為響應,將顯示字串類的屬性。您可以導航到所需的一個。

example

IPython透過在物件前面加上“?”來提供任何物件的資訊(自省)。它包括類文件字串、函式定義和建構函式詳細資訊。例如,要探索上面定義的字串物件var,請在輸入提示符中輸入var?。

In [5]: var = "Hello World"
In [6]: var?
Type: str
String form: Hello World
Length: 11
Docstring:
str(object='') -> str
str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or
errors is specified, then the object must expose a data buffer
that will be decoded using the given encoding and error handler.
Otherwise, returns the result of object.__str__() (if defined)
or repr(object).
encoding defaults to sys.getdefaultencoding().
errors defaults to 'strict'.

IPython的magic函式非常強大。行magic允許您在IPython中執行DOS命令。讓我們在IPython控制檯中執行dir命令

In [8]: !dir *.exe
 Volume in drive F has no label.
 Volume Serial Number is E20D-C4B9
 
 Directory of F:\Python311

07-02-2023 16:55            103,192 python.exe
07-02-2023 16:55            101,656 pythonw.exe
                2 File(s)    204,848 bytes
                0 Dir(s)  105,260,306,432 bytes free

Jupyter Notebook是一個基於Web的介面,用於Python、Julia、R和許多其他程式設計環境。對於Python,它使用IPython作為其主要核心。

Python - 環境搭建

學習Python的第一步是在您的機器上安裝它。如今,大多數計算機,特別是安裝了Linux作業系統的計算機,都預裝了Python。但是,它可能不是最新版本。

在本節中,我們將學習如何在Linux、Windows和Mac OS上安裝最新版本的Python,Python 3.11.2

所有作業系統的最新版本的Python都可以在PSF的官方網站上下載。

PSFs_official_website

在Ubuntu Linux上安裝Python

要檢查是否已安裝Python,請開啟Linux終端並輸入以下命令:

user@ubuntu20:~$ python3 --version

在Ubuntu Linux中,安裝Python最簡單的方法是使用apt(高階打包工具)。始終建議更新所有已配置儲存庫中的軟體包列表。

user@ubuntu20:~$ sudo apt update

即使更新後,根據您使用的Ubuntu版本,最新版本的Python也可能無法安裝。要克服這個問題,請新增deadsnakes儲存庫。

user@ubuntu20:~$ sudo apt-get install software-properties-common
user@ubuntu20:~$ sudo add-apt-repository ppa:deadsnakes/ppa

再次更新軟體包列表。

user@ubuntu20:~$ sudo apt update

要安裝最新的Python 3.11版本,請在終端中輸入以下命令:

user@ubuntu20:~$ sudo apt-get install python3.11

檢查它是否已正確安裝。

user@ubuntu20:~$ python3.11
Python 3.11.2 (main, Feb 8 2023, 14:49:24) [GCC 9.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> print ("Hello World")
Hello World
>>>

在Windows上安裝Python

需要注意的是,Python 3.10及更高版本無法安裝在Windows 7或更早的作業系統上。

推薦的安裝Python的方法是使用官方安裝程式。主頁上提供了最新穩定版本的連結。它也可以在https://python.club.tw/downloads/windows/.找到。

您可以找到適用於32位和64位架構的可嵌入包和安裝程式。

embeddable_packages

讓我們下載64位Windows安裝程式:

(https://python.club.tw/ftp/python/3.11.2/python-3.11.2-amd64.exe)

雙擊已下載檔案的所在位置以啟動安裝。

Image-9.jpg

雖然您可以直接單擊“立即安裝”按鈕繼續,但建議選擇路徑相對較短的安裝資料夾,並選中第二個複選框以更新PATH變數。

接受安裝嚮導中其餘步驟的預設設定以完成安裝。

Image-10

開啟 Windows 命令提示符終端並執行 Python 以檢查安裝是否成功。

C:\Users\Acer>python
Python 3.11.2 (tags/v3.11.2:878ead1, Feb 7 2023, 16:38:35) [MSC v.1934
64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>

Python 的標準庫包含一個名為 **IDLE** 的可執行模組,它是 **整合開發和學習環境 (Integrated Development and Learning Environment)** 的縮寫。從 Windows 開始選單中找到並啟動它。

idle

IDLE 包含 Python shell(互動式直譯器)和一個可自定義的多視窗文字編輯器,具有語法高亮、智慧縮排、自動完成等功能。它是跨平臺的,因此在 Windows、macOS 和 Linux 上的工作方式相同。它還有一個偵錯程式,可以設定斷點、單步執行以及檢視全域性和區域性名稱空間。

在 macOS 上安裝 Python

早期版本的 macOS 預裝了 Python 2.7。但是,由於該版本不再受支援,因此已被停用。因此,您需要自行安裝 Python。

在 Mac 計算機上,可以透過兩種方法安裝 Python:

  • 使用官方安裝程式

  • 使用 homebrew 手動安裝

您可以在官方網站的下載頁面上找到 macOS 64 位通用 2 安裝程式:

https://python.club.tw/ftp/python/3.11.2/python-3.11.2-macos11.pkg

安裝過程與 Windows 上大致相同。通常,在嚮導步驟中接受預設選項即可完成工作。

installation_process

此安裝嚮導還會安裝常用的實用程式,例如 PIP 和 IDLE。

或者,您可以選擇從命令列安裝。如果您尚未安裝 Mac 的包管理器 **Homebrew**,則需要先安裝它。您可以按照以下說明進行安裝:https://docs.brew.sh/Installation

之後,開啟終端並輸入以下命令:

brew update && brew upgrade
brew install python3

現在將安裝最新版本的 Python。

從原始碼安裝 Python

如果您是一位經驗豐富的開發人員,並且精通 C++ 和 Git 工具,則可以按照本節中的說明構建 Python 可執行檔案以及標準庫中的模組。

您必須擁有您正在使用的作業系統的 C 編譯器。在 Ubuntu 和 macOS 中,可以使用 **gcc** 編譯器。對於 Windows,您應該安裝 Visual Studio 2017 或更高版本。

在 Linux/Mac 上構建 Python 的步驟

從 Python 的官方網站或其 GitHub 儲存庫下載最新版本的原始碼。

下載原始碼壓縮包:https://python.club.tw/ftp/python/3.11.2/Python3.11.2.tgz

使用以下命令解壓檔案:

tar -xvzf /home/python/Python-3.11.2.tgz

或者,克隆 Python 的 GitHub 儲存庫的主分支。(您應該已安裝 git)

git clone -b main https://github.com/python/cpython

原始碼中包含一個 configure 指令碼。執行此指令碼將建立 Makefile。

./configure --enable-optimizations

然後,使用 make 工具構建檔案,然後使用 make install 將最終檔案放入 /usr/bin/ 目錄。

make
make install

Python 已成功從原始碼構建。

如果您使用的是 Windows,請確保已安裝 **Visual Studio 2017** 和 **Git for Windows**。使用與上述相同的命令克隆 Python 原始碼儲存庫。

在放置原始碼的資料夾中開啟 Windows 命令提示符。執行以下批處理檔案

PCbuild\get_externals.bat

這將下載原始碼依賴項(OpenSSL、Tk 等)。

開啟 Visual Studio 和 **PCbuild/sbuild.sln** 解決方案,並構建(按 F10)除錯資料夾顯示 **python_d.exe**,這是 Python 可執行檔案的除錯版本。

要從命令提示符構建,請使用以下命令:

PCbuild\build.bat -e -d -p x64

因此,在本節中,您學習瞭如何從預構建的二進位制檔案以及從原始碼安裝 Python。

設定 PATH

安裝 Python 軟體後,應能夠從檔案系統的任何位置訪問它。為此,需要更新 **PATH** 環境變數。系統 PATH 是一個由分號 (;) 分隔的資料夾名稱組成的字串。每當從命令列呼叫可執行程式時,作業系統都會在 PATH 變數中列出的資料夾中搜索它。我們需要將 Python 的安裝資料夾新增到 PATH 字串。

對於 Windows 作業系統,如果您在安裝嚮導的第一個螢幕上啟用了“將 python.exe 新增到系統路徑”選項,則路徑將自動更新。要手動執行此操作,請從“高階系統設定”中開啟“環境變數”部分。

setting up the path

編輯 Path 變數,並新增一個新條目。輸入已安裝 Python 的安裝資料夾的名稱,然後按確定。

edit the path variable

要在 Linux 中為特定會話新增 Python 目錄到路徑,請執行以下操作:

**在 bash shell (Linux) 中** - 輸入 **export PATH="$PATH:/usr/bin/python3.11"** 並按 Enter。

Python 命令列選項

我們知道,只需呼叫 Python 可執行檔案即可從終端呼叫互動式 Python 直譯器。請注意,啟動互動式會話不需要任何附加引數或選項。

user@ubuntu20:~$ python3.11
Python 3.11.2 (main, Feb 8 2023, 14:49:24) [GCC 9.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> print ("Hello World")
Hello World
>>>

Python 直譯器還響應以下命令列選項:

-c <command>

直譯器執行字串中一個或多個語句,用換行符 (;) 分隔。

user@ubuntu20:~$ python3 -c "a=2;b=3;print(a+b)"
5

-m <module-name>

直譯器將命名模組的內容作為 __main__ 模組執行。由於引數是模組名稱,因此您不得提供副檔名 (.py)。

考慮以下示例。這裡,標準庫中的 timeit 模組具有命令列介面。-s 選項設定模組的引數。

C:\Users\Acer>python -m timeit -s "text = 'sample string'; char = 'g'
'char in text'"
5000000 loops, best of 5: 49.4 nsec per loop

<script>

直譯器執行包含在具有 .py 副檔名的指令碼中的 Python 程式碼,該副檔名必須是檔案系統路徑(絕對或相對)。

假設當前目錄中存在一個名為 hello.py 的文字檔案,其中包含 print ("Hello World") 語句。以下是指令碼選項的命令列用法。

C:\Users\Acer>python hello.py
Hello World

? 或 -h 或 −help

此命令列選項列印所有命令列選項和相應環境變數的簡短描述並退出。

-V 或 --version

此命令列選項列印 Python 版本號

C:\Users\Acer>python -V
Python 3.11.2
C:\Users\Acer>python --version
Python 3.11.2

Python 環境變數

作業系統使用路徑環境變數來搜尋任何可執行檔案(不僅僅是 Python 可執行檔案)。特定於 Python 的環境變數允許您配置 Python 的行為。例如,要檢查哪些資料夾位置才能匯入模組。通常,Python 直譯器會在當前資料夾中搜索模組。您可以設定一個或多個備用資料夾位置。

Python 環境變數可以暫時設定為當前會話,也可以像路徑變數一樣持久地新增到系統屬性中。

PYTHONPATH

如上所述,如果您希望直譯器除了當前資料夾外還要在其他資料夾中搜索模組,則一個或多個此類資料夾位置將儲存為 PYTHONPATH 變數。

首先,將 **hello.py** 指令碼儲存在與 Python 安裝資料夾不同的資料夾中,例如 **c:\modulepath\hello.py**

要使模組全域性可用於直譯器,請設定 PYTHONPATH

C:\Users\Acer>set PYTHONPATH= c:\modulepath
C:\Users\Acer>echo %PYTHONPATH%
c:\modulepath

現在,即使是從 c:\modulepath 目錄以外的任何目錄,您也可以匯入該模組。

>>> import hello
Hello World
>>>

PYTHONHOME

設定此變數以更改標準 Python 庫的位置。預設情況下,在 Linux 中搜索庫的位置為 **/usr/local/pythonversion**,在 Windows 中為 **instalfolder\lib**。例如,**c:\python311\lib**。

PYTHONSTARTUP

通常,此變數設定為一個 Python 指令碼,您希望每次啟動 Python 直譯器時自動執行該指令碼。

讓我們建立一個簡單的指令碼,如下所示,並將其另存為 Python 安裝資料夾中的 **startup.py**:

print ("Example of Start up file")
print ("Hello World")

現在設定 PYTHONSTARTUP 變數併為其分配此檔案的名稱。之後啟動 Python 直譯器。在您獲得提示符之前,它會顯示此指令碼的輸出。

F:\311_2>set PYTHONSTARTUP=startup.py
F:\311_2>echo %PYTHONSTARTUP%
startup.py
F:\311_2>python
Python 3.11.2 (tags/v3.11.2:878ead1, Feb 7 2023, 16:38:35) [MSC v.1934
64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
Example of Start up file
Hello World
>>>

PYTHONCASEOK

此環境變數僅可在 Windows 和 macOS 上使用,而不能在 Linux 上使用。它會導致 Python 忽略 import 語句中的大小寫。

PYTHONVERBOSE

如果此變數設定為非空字串,則等效於指定 python -v 命令。每次初始化模組時,它都會列印一條訊息,顯示位置(檔名或內建模組)。如果設定為整數(例如 2),則等效於指定兩次 -v。(python --v)。

PYTHONDONTWRITEBYTECODE

通常,匯入的模組會被編譯成 **.pyc** 檔案。如果此變數設定為非空字串,則在匯入源模組時不會建立 .pyc 檔案。

PYTHONWARNINGS

Python 的警告訊息將重定向到標準錯誤流 **sys.stderr**。此環境變數等效於 python -W 選項。此變數允許以下值:

  • PYTHONWARNINGS=default # 每個呼叫位置警告一次

  • PYTHONWARNINGS=error  # 轉換為異常

  • PYTHONWARNINGS=always  # 每次都警告

  • PYTHONWARNINGS=module  # 每個呼叫模組警告一次

  • PYTHONWARNINGS=once  # 每個 Python 程序警告一次

  • PYTHONWARNINGS=ignore  # 從不警告

Python - 虛擬環境

在本節中,您將瞭解 Python 中的虛擬環境是什麼,如何建立和使用虛擬環境來構建 Python 應用程式。

當您在計算機上安裝 Python 軟體時,可以從檔案系統的任何位置使用它。這是系統範圍的安裝。

在使用 Python 開發應用程式時,可能需要使用 pip 實用程式安裝一個或多個庫(例如,**pip3 install somelib**)。此外,一個應用程式(例如 App1)可能需要特定版本的庫(例如 **somelib 1.0**)。同時,另一個 Python 應用程式(例如 App2)可能需要同一庫的新版本(例如 **somelib 2.0**)。因此,透過安裝新版本,App1 的功能可能會因同一庫的兩個不同版本之間的衝突而受損。

可以透過在同一臺機器上提供兩個隔離的 Python 環境來避免此衝突。這些稱為虛擬環境。虛擬環境是一個單獨的目錄結構,包含隔離的安裝,其中包含 Python 直譯器、標準庫和其他模組的本地副本。

下圖顯示了使用虛擬環境的優勢。使用全域性 Python 安裝,可以建立多個虛擬環境,每個環境都具有同一庫的不同版本,從而避免衝突。

python virtual environment

標準 Python 發行版中的 **venv** 模組支援此功能。使用以下命令建立新的虛擬環境。

C:\Users\Acer>md\pythonapp
C:\Users\Acer>cd\pythonapp
C:\pythonapp>python -m venv myvenv

這裡,**myvenv** 是將建立新的 Python 虛擬環境的資料夾,顯示以下目錄結構:

Directory of C:\pythonapp\myvenv
22-02-2023 09:53 <DIR> .
22-02-2023 09:53 <DIR> ..
22-02-2023 09:53 <DIR> Include
22-02-2023 09:53 <DIR> Lib
22-02-2023 09:53 77 pyvenv.cfg
22-02-2023 09:53 <DIR> Scripts

用於啟用和停用虛擬環境以及 Python 直譯器的本地副本的實用程式將放置在 scripts 資料夾中。

Directory of C:\pythonapp\myvenv\scripts
22-02-2023 09:53 <DIR> .
22-02-2023 09:53 <DIR> ..
22-02-2023 09:53 2,063 activate
22-02-2023 09:53 992 activate.bat
22-02-2023 09:53 19,611 Activate.ps1
22-02-2023 09:53 393 deactivate.bat
22-02-2023 09:53 106,349 pip.exe
22-02-2023 09:53 106,349 pip3.10.exe
22-02-2023 09:53 106,349 pip3.exe
22-02-2023 09:53 242,408 python.exe
22-02-2023 09:53 232,688 pythonw.exe

要啟用此新的虛擬環境,請執行 Scripts 資料夾中的 **activate.bat**。

C:\pythonapp>myvenv\scripts\activate
(myvenv) C:\pythonapp>

請注意括號中的虛擬環境名稱。Scripts 資料夾包含 Python 直譯器的本地副本。您可以在此虛擬環境中啟動 Python 會話。

要確認此 Python 會話是否在虛擬環境中,請檢查 **sys.path**。

(myvenv) C:\pythonapp>python
Python 3.10.1 (tags/v3.10.1:2cd268a, Dec 6 2021, 19:10:37) [MSC v.1929
64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.path
['', 'C:\\Python310\\python310.zip', 'C:\\Python310\\DLLs',
'C:\\Python310\\lib', 'C:\\Python310', 'C:\\pythonapp\\myvenv',
'C:\\pythonapp\\myvenv\\lib\\site-packages']
>>>

此虛擬環境的 scripts 資料夾還包含 pip 實用程式。如果您從 PyPI 安裝軟體包,則該軟體包僅在此虛擬環境中有效。要停用此環境,請執行deactivate.bat

Python - 基本語法

在 Python 中,“語法”指的是構成語句或表示式的規則。Python 語言以其簡潔明瞭的語法而聞名。與其他語言相比,它還具有有限的關鍵字集和更簡單的標點符號規則。本章,讓我們瞭解 Python 的基本語法。

Python 程式由預定義的關鍵字和識別符號組成,這些識別符號代表函式、類、模組等。Python 對在 Python 原始碼中形成識別符號、編寫語句和註釋有明確的規則。

Python 關鍵字

一組預定義的關鍵字是任何程式語言最重要的方面。這些關鍵字是保留字。它們具有預定義的含義,必須僅用於其預定義的目的以及根據預定義的語法規則。程式設計邏輯是用這些關鍵字編碼的。

截至 Python 3.11 版本,Python 中有 35 (三十五) 個關鍵字。要獲取 Python 關鍵字列表,請在 Python shell 中輸入以下 help 命令。

>>> help("keywords")

Here is a list of the Python keywords. Enter any keyword to get more
help.
1. False 10. class 19. from 28. or
2. None 11. continue 20. global 29. pass
3. True 12. def 21. if 30. raise
4. and 13. del 22. import 31. return
5. as 14. elif 23. in 32. try
6. assert 15. else 24. is 33. while
7. async 16. except 25. lambda 34. with
8. await 17. finally 26. nonlocal 35. yield
9. break 18. for 27. not

所有關鍵字都是字母的,所有關鍵字(除了 False、None 和 True)都小寫。關鍵字列表也由關鍵字模組中定義的 kwlist 屬性給出。

>>> import keyword
>>> keyword.kwlist
['False', 'None', 'True', 'and', 'as', 'assert', 'async', 'await',
'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except',
'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is',
'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try',
'while', 'with', 'yield']

如何驗證任何單詞是否是關鍵字?大多數 Python IDE 提供彩色語法高亮顯示功能,其中關鍵字以特定顏色表示。

下面是在 VS Code 中的 Python 程式碼示例。關鍵字(if 和 else)、識別符號和常量以不同的顏色方案顯示。

vs_code

keyword 模組還有一個 iskeyword() 函式。對於有效的關鍵字,它返回 True,否則返回 False。

>>> import keyword
>>> keyword.iskeyword("else")
True
>>> keyword.iskeyword("Hello")
False

Python 關鍵字可以大致分為以下幾類:

值關鍵字 True, False, None
運算子關鍵字 and, or, not, in, is
條件流程關鍵字 if, elif, else
迴圈控制關鍵字 for, while, break, continue
結構關鍵字 def, class, with, pass, lambda
返回關鍵字 return, yield
匯入關鍵字 import, from, as
異常處理關鍵字 try, except, raise, finally, assert
非同步程式設計關鍵字 async, await
變數作用域關鍵字 del, global, nonlocal

我們將在本教程中逐步學習每個關鍵字的用法。

Python 識別符號

Python 程式中除關鍵字之外的各種元素稱為識別符號。識別符號是使用者為原始碼中的變數、函式、類、模組、包等賦予的名稱。Python 制定了某些規則來形成識別符號。這些規則是:

  • 識別符號應以字母(小寫或大寫)或下劃線 (_) 開頭。後面可以跟一個或多個字母數字字元或下劃線。

  • 不允許使用任何關鍵字作為識別符號,因為關鍵字具有預定義的含義。

  • 按照慣例,類的名稱以大寫字母開頭。其他元素(如變數或函式)以小寫字母開頭。

  • 根據另一個 Python 約定,變數名前面的單個下劃線用於指示私有變數。

  • 在識別符號開頭使用兩個下劃線表示該變數是強私有的。

  • 兩個前導和尾隨下劃線在語言本身中用於特殊目的。例如,__add__,__init__

根據上述規則,以下是一些有效的識別符號:

  • Student
  • score
  • aTotal
  • sum_age
  • __count
  • TotalValue
  • price1
  • cost_of_item
  • __init__

以下也給出一些無效的識別符號形式:

  • 1001
  • Name of student
  • price-1
  • ft.in

需要注意的是,識別符號區分大小寫。因此,Name 和 name 是兩個不同的識別符號。

Python 縮排

在程式碼中使用縮排是 Python 語法的重要特徵之一。在程式中,您可能需要將多個語句組合在一起作為一個塊。例如,如果條件為真/假,則有多個語句。不同的程式語言有不同的方法來標記類、函式、條件和迴圈等構造中語句組的作用域和範圍。C、C++、Java 等使用花括號來標記塊。Python 使用統一的縮排標記語句塊,從而提高了程式碼的可讀性。

要標記塊的開頭,請鍵入 ":" 符號並按 Enter 鍵。任何 Python 感知的編輯器(如 IDLE 或 VS Code)都會轉到下一行,留下額外的空格(稱為縮排)。塊中的後續語句遵循相同的縮排級別。要指示塊的結束,請透過按退格鍵取消縮排空格。以下示例說明了在 Python 中使用縮排的情況。

python_indents

在這個階段,您可能不理解程式碼是如何工作的。但不用擔心。只需檢視冒號符號後縮排級別是如何增加的。

Python 語句

Python 中的語句是 Python 直譯器可以執行的任何指令。語句包含一個或多個關鍵字、運算子、識別符號、用於標記塊開頭的 : 符號或作為續行符的反斜槓 \。

語句可以是簡單的賦值語句,例如 amount = 1000,也可以是複合語句,其中多個語句分組在一起構成統一縮排的塊,如條件或迴圈結構。

您可以在互動式 shell 的 Python 提示符前面或編輯器視窗中輸入語句。通常,Python 直譯器將以 Enter 鍵(稱為換行符)結尾的文字識別為語句。因此,編輯器中的每一行都是一個語句,除非它以註釋字元 (#) 開頭。

print ("My first program")
price = 100
qty = 5
ttl = price*qty
print ("Total = ", ttl)

以上程式碼中的每一行都是一個語句。有時,Python 語句可能會跨越多行。為此,請使用反斜槓 (\) 作為續行符。長字串可以方便地拆分為多行,如下所示:

name = "Ravi"
string = "Hello {} \
Welcome to Python Tutorial \
from TutorialsPoint".format(name)
print (string)

該字串(包含嵌入式字串變數名)跨越多行,以提高可讀性。輸出將為:

Hello Ravi Welcome to Python Tutorial from TutorialsPoint

續行符還有助於以更易讀的方式編寫冗長的算術表示式。

例如,方程式 $\frac{(a+b)\times (c−d)}{(a−b)\times (c+d)}$ 在 Python 中編碼如下:

a=10
b=5
c=5
d=10
expr = (a+b)*(c-d)/ \
   (a-b)*(c+d)
print (expr)

如果列表、元組或字典物件中的專案跨越多行,則不需要使用反斜槓符號 (\)。

Subjects = ["English", "French", "Sanskrit",
   "Physics", "Maths",
   "Computer Sci", "History"]

Python 還允許使用分號在一個編輯器行中放置多個語句。檢視以下示例:

a=10; b=5; c=5; d=10
if a>10: b=20; c=50

Python - 變數

在本章中,您將學習什麼是 Python 中的變數以及如何使用它們。

屬於不同資料型別的資料項儲存在計算機的記憶體中。計算機的記憶體位置內部以二進位制形式表示數字或地址。資料也以二進位制形式儲存,因為計算機的工作原理是基於二進位制表示。在下圖中,字串May和數字18顯示為儲存在記憶體位置中。

memory

如果您瞭解組合語言,您將轉換這些資料項和記憶體地址,併發出機器語言指令。然而,這並非對每個人都容易。諸如 Python 直譯器之類的語言翻譯器執行這種型別的轉換。它將物件儲存在隨機選擇的記憶體位置中。Python 的內建id()函式返回儲存物件的位置。

>>> "May"
>>> id("May")
2167264641264
>>> 18
18
>>> id(18)
140714055169352

一旦資料儲存在記憶體中,就應該重複訪問它以執行某個過程。顯然,從其 ID 獲取資料很麻煩。像 Python 這樣的高階語言使得可以為記憶體位置提供合適的別名或標籤。

在上面的示例中,讓我們將 May 的位置標記為 month,將儲存 18 的位置標記為 age。Python 使用賦值運算子 (=) 將物件與標籤繫結。

>>> month="May"
>>> age=18

資料物件 (May) 和其名稱 (month) 具有相同的 id()。18 和 age 的 id() 也相同。

>>> id(month)
2167264641264
>>> id(age)
140714055169352

標籤是一個識別符號。它通常被稱為變數。Python 變數是一個符號名稱,它是對物件的引用或指標。

命名約定

變數名由使用者指定,並遵循形成識別符號的規則。

  • Python 變數名應以字母(小寫或大寫)或下劃線 (_) 開頭。後面可以跟一個或多個字母數字字元或下劃線。

  • 不允許使用任何關鍵字作為 Python 變數,因為關鍵字具有預定義的含義。

  • Python 中的變數名區分大小寫。因此,age 和 Age 不能互換使用。

  • 您應該選擇助記的變數名,以便它指示目的。它不應過於簡短,也不應過於冗長。

如果變數名包含多個單詞,我們應該使用以下命名模式:

  • 駝峰式命名法 - 第一個字母是小寫,但每個後續單詞的第一個字母是大寫。例如:kmPerHour、pricePerLitre

  • 帕斯卡命名法 - 每個單詞的第一個字母都是大寫。例如:KmPerHour、PricePerLitre

  • 蛇形命名法 - 使用單個下劃線 (_) 字元分隔單詞。例如:km_per_hour、price_per_litre

一旦您使用變數來標識資料物件,就可以重複使用它而無需其 id() 值。在這裡,我們有一個矩形的變數高度和寬度。我們可以用這些變數計算面積和周長。

>>> width=10
>>> height=20
>>> area=width*height
>>> area
200
>>> perimeter=2*(width+height)
>>> perimeter
60

編寫指令碼或程式時,變數的使用特別有利。以下指令碼也使用上述變數。

#! /usr/bin/python3.11
width = 10
height = 20
area = width*height
perimeter = 2*(width+height)
print ("Area = ", area)
print ("Perimeter = ", perimeter)

使用 .py 副檔名儲存上述指令碼,並從命令列執行。結果將為:

Area = 200
Perimeter = 60

賦值語句

在 C/C++ 和 Java 等語言中,需要在為變數賦值之前宣告變數及其型別。Python 中不需要這種變數的預先宣告。

Python 使用 = 符號作為賦值運算子。變數識別符號的名稱出現在 = 符號的左側。對其右側的表示式進行求值,並將值賦給變數。以下是賦值語句的示例:

>>> counter = 10
>>> counter = 10 # integer assignment
>>> price = 25.50 # float assignment
>>> city = "Hyderabad" # String assignment
>>> subjects = ["Physics", "Maths", "English"] # List assignment
>>> mark_list = {"Rohit":50, "Kiran":60, "Lata":70} # dictionary
assignment

Python 的內建print()函式顯示一個或多個變數的值。

>>> print (counter, price, city)
10 25.5 Hyderabad
>>> print (subjects)
['Physics', 'Maths', 'English']
>>> print (mark_list)
{'Rohit': 50, 'Kiran': 60, 'Lata': 70}

= 符號右側任何表示式的值都將賦給左側的變數。

>>> x = 5
>>> y = 10
>>> z = x+y

但是,不允許 = 運算子左側的表示式和右側的變數。

>>> x = 5
>>> y = 10
>>> x+y=z
   File "<stdin>", line 1
   x+y=z
   ^^^
SyntaxError: cannot assign to expression here. Maybe you meant '=='
instead of '='?

雖然 z=x+y 和 x+y=z 在數學上是等價的,但在這裡並非如此。這是因為 = 是等式符號,而在 Python 中它是賦值運算子。

多重賦值

在 Python 中,您可以在單個語句中初始化多個變數。在以下情況下,三個變數具有相同的值。

>>> a=10
>>> b=10
>>> c=10

您可以使用以下單個賦值語句來執行此操作,而不是單獨的賦值:

>>> a=b=c=10
>>> print (a,b,c)
10 10 10

在以下情況下,我們有三個具有不同值的變數。

>>> a=10
>>> b=20
>>> c=30

這些單獨的賦值語句可以組合成一個。您需要在 = 運算子的左側給出逗號分隔的變數名,在右側給出逗號分隔的值。

>>> a,b,c = 10,20,30
>>> print (a,b,c)
10 20 30

變數的概念在 Python 中的工作方式與在 C/C++ 中不同。

在 C/C++ 中,變數是命名的記憶體位置。如果 a=10 並且 b=10,則兩者都是兩個不同的記憶體位置。讓我們假設它們的記憶體地址分別為 100 和 200。

named memory location

如果為“a”賦予不同的值(例如 50),則地址 100 中的 10 將被覆蓋。

Image-20

Python 變數引用的是物件本身,而不是記憶體位置。一個物件只在記憶體中儲存一次。多個變數實際上是同一個物件的多個標籤。

address_100

語句 a=50 在記憶體中的某個位置建立一個新的 **int** 物件 50,而物件 10 仍然被 "b" 引用。

address_150

此外,如果你將另一個值賦給 b,物件 10 將保持未被引用狀態。

address_200

Python 的垃圾回收機制會釋放任何未被引用的物件佔用的記憶體。

Python 的身份運算子 **is** 如果兩個運算元具有相同的 id() 值,則返回 True。

>>> a=b=10
>>> a is b
True
>>> id(a), id(b)
(140731955278920, 140731955278920)

Python - 資料型別

計算機是一種資料處理裝置。計算機將資料儲存在其記憶體中,並根據給定的程式對其進行處理。資料是對某個物件的事實的一種表示。

一些資料的例子:

  • **學生資料** - 姓名、性別、班級、分數、年齡、費用等。

  • **圖書館書籍資料** - 書名、作者、出版商、價格、頁數、出版年份等。

  • **辦公室員工資料** - 姓名、職位、薪水、部門、分公司等。

資料型別表示一種值,並決定可以對其執行哪些操作。數值、非數值和布林值(true/false)資料是最明顯的資料型別。但是,每種程式語言都有其自身的分類,這在很大程度上反映了其程式設計理念。

Python 根據下圖所示的不同資料型別來識別資料:

data_types

Python 的資料模型定義了四種主要資料型別:數字、序列、集合和字典(也稱為對映)。

數字型別

任何具有數值的資料項都是數字。Python 中有四種標準的數字資料型別:整數、浮點數、布林值和複數。它們在 Python 庫中都有內建的類,分別稱為 **int、float、bool** 和 **complex**。

在 Python 中,數字是其對應類的物件。例如,整數 123 是 **int** 類的物件。類似地,9.99 是一個浮點數,它是 float 類的物件。

Python 的標準庫有一個內建函式 **type()**,它返回給定物件的類。在這裡,它用於檢查整數和浮點數的型別。

>>> type(123)
<class 'int'>
>>> type(9.99)
<class 'float'>

浮點數的小數部分也可以用 **科學計數法** 表示。數字 -0.000123 等效於其科學計數法 1.23E-4(或 1.23e-4)。

複數由兩部分組成:**實部** 和 **虛部**。它們由 '+' 或 '-' 符號分隔。虛部字尾為 'j',它是虛數單位。-1 的平方根 ($\sqrt{−1}$) 定義為虛數。Python 中的複數表示為 x+yj,其中 x 是實部,y 是虛部。因此,5+6j 是一個複數。

>>> type(5+6j)
<class 'complex'>

布林值只有兩個可能的值,分別由關鍵字 **True** 和 **False** 表示。它們分別對應於整數 1 和 0。

>>> type (True)
<class 'bool'>
>>> type(False)
<class 'bool'>

使用 Python 的算術運算子,可以執行加法、減法等運算。

序列型別

序列是一種集合資料型別。它是一個有序的專案集合。序列中的專案具有從 0 開始的位置索引。它在概念上類似於 C 或 C++ 中的陣列。Python 中定義了三種序列型別:字串、列表和元組。

Python 中的字串

字串是由一個或多個 Unicode 字元組成的序列,用單引號、雙引號或三引號(也稱為反引號)括起來。只要字元序列相同,單引號、雙引號或三引號就沒有區別。因此,以下字串表示方式是等效的。

>>> 'Welcome To TutorialsPoint'
'Welcome To TutorialsPoint'
>>> "Welcome To TutorialsPoint"
'Welcome To TutorialsPoint'
>>> '''Welcome To TutorialsPoint'''
'Welcome To TutorialsPoint'

Python 中的字串是 **str** 類的物件。可以使用 **type()** 函式進行驗證。

>>> type("Welcome To TutorialsPoint")
<class 'str'>

如果要將一些用雙引號括起來的文字嵌入到字串中,則字串本身應該用單引號括起來。要嵌入用單引號括起來的文字,字串應該用雙引號括起來。

>>> 'Welcome to "Python Tutorial" from TutorialsPoint'
'Welcome to "Python Tutorial" from TutorialsPoint'
>>> "Welcome to 'Python Tutorial' from TutorialsPoint"
"Welcome to 'Python Tutorial' from TutorialsPoint"

由於字串是一個序列,因此其中的每個字元都具有從 0 開始的位置索引。要使用三引號構成字串,可以使用三個單引號或三個雙引號——這兩個版本是類似的。

>>> '''Welcome To TutorialsPoint'''
'Welcome To TutorialsPoint'
>>> """Welcome To TutorialsPoint"""
'Welcome To TutorialsPoint'

三引號字串可用於構成多行字串。

>>> '''
... Welcome To
... Python Tutorial
... from TutorialsPoint
... '''
'\nWelcome To\nPython Tutorial \nfrom TutorialsPoint\n'

字串是一種非數值資料型別。顯然,我們不能對其執行算術運算。但是,可以執行諸如 **切片** 和 **連線** 等操作。Python 的 str 類定義了許多用於字串處理的有用方法。我們將在後續關於字串的章節中學習這些方法。

Python 中的列表

在 Python 中,列表是任何型別資料項的有序集合。資料項用逗號 (,) 分隔,並用方括號 (**[]**) 括起來。列表也是一個序列,因此。

列表中的每個專案都有一個索引,用於指明其在集合中的位置。索引從 0 開始。

Python 中的列表看起來類似於 C 或 C++ 中的陣列。但是,兩者之間存在一個重要的區別。在 C/C++ 中,陣列是同類型資料的同質集合。Python 列表中的專案可以是不同型別的。

>>> [2023, "Python", 3.11, 5+6j, 1.23E-4]

Python 中的列表是 **list** 類的物件。我們可以使用 type() 函式進行檢查。

>>> type([2023, "Python", 3.11, 5+6j, 1.23E-4])
<class 'list'>

如前所述,列表中的專案可以是任何資料型別。這意味著列表物件也可以是另一個列表中的專案。在這種情況下,它將成為巢狀列表。

>>> [['One', 'Two', 'Three'], [1,2,3], [1.0, 2.0, 3.0]]

列表項也可以是元組、字典、集合或使用者定義類的物件。

列表作為序列,它支援與字串一樣切片和連線操作。使用 Python 內建列表類中提供的方法/函式,我們可以新增、刪除或更新專案,並按所需順序對專案進行排序或重新排列。我們將在後續章節中學習這些方面。

Python 中的元組

在 Python 中,元組是任何型別資料項的有序集合。資料項用逗號 (,) 分隔,並用圓括號 () 括起來。元組也是一個序列,因此元組中的每個專案都有一個索引,用於指明其在集合中的位置。索引從 0 開始。

>>> (2023, "Python", 3.11, 5+6j, 1.23E-4)

在 Python 中,元組是 **tuple** 類的物件。我們可以使用 type() 函式進行檢查。

>>> type((2023, "Python", 3.11, 5+6j, 1.23E-4))
<class 'tuple'>

與列表一樣,元組中的專案也可以是列表、元組本身或任何其他 Python 類的物件。

>>> (['One', 'Two', 'Three'], 1,2.0,3, (1.0, 2.0, 3.0))

要形成元組,圓括號是可選的。用逗號分隔的資料項,沒有任何包圍符號,預設情況下被視為元組。

>>> 2023, "Python", 3.11, 5+6j, 1.23E-4
(2023, 'Python', 3.11, (5+6j), 0.000123)

列表和元組這兩種序列型別看起來很相似,只是分隔符不同,列表使用方括號 ([]),而元組使用圓括號。但是,列表和元組之間存在一個主要

區別。列表是可變物件,而元組是 **不可變** 的。不可變物件意味著一旦它儲存在記憶體中,就不能更改。

讓我們嘗試理解可變性的概念。我們有一個具有相同資料項的列表和元組物件。

>>> l1=[1,2,3]
>>> t1=(1,2,3)

兩者都是序列,因此兩者中的每個專案都有一個索引。兩者中索引號為 1 的專案都是 2。

>>> l1[1]
2
>>> t1[1]
2

讓我們嘗試將列表和元組中索引號為 1 的專案的值從 2 更改為 20。

>>> l1[1]
2
>>> t1[1]
2
>>> l1[1]=20
>>> l1
[1, 20, 3]
>>> t1[1]=20
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment

錯誤訊息 **'tuple' object does not support item assignment** 告訴您,一旦形成元組物件,就不能對其進行修改。這稱為不可變物件。

元組的不可變性還意味著 Python 的 tuple 類不具有在元組中新增、刪除或排序專案的功能。但是,由於它是一個序列,我們可以執行切片和連線操作。

字典型別

Python 的字典是 **對映** 型別的一個例子。對映物件將一個物件的價值與另一個物件對映。在語言字典中,我們有單詞及其相應含義的配對。配對的兩部分是鍵(單詞)和值(含義)。類似地,Python 字典也是 **鍵:值** 對的集合。這些對用逗號分隔,並放在花括號 {} 中。為了在鍵和值之間建立對映,在兩者之間使用分號 ':' 符號。

>>> {1:'one', 2:'two', 3:'three'}

字典中的每個鍵必須唯一,並且應該是數字、字串或元組。值物件可以是任何型別,並且可以與多個鍵對映(它們不必唯一)。

在 Python 中,字典是內建 **dict** 類的物件。我們可以使用 type() 函式進行檢查。

>>> type({1:'one', 2:'two', 3:'three'})
<class 'dict'>

Python 的字典不是序列。它是一個專案集合,但每個專案(鍵:值對)不像字串、列表或元組那樣由位置索引標識。因此,不能對字典執行切片操作。字典是可變物件,因此可以使用 dict 類中定義的相應功能執行新增、修改或刪除操作。這些操作將在後續章節中解釋。

集合型別

集合是 Python 對數學中定義的集合的實現。Python 中的集合是一個集合,但它不是像字串、列表或元組那樣有索引或有序的集合。集合中不能出現多個相同的物件,而在列表和元組中,同一個物件可以出現多次。

集合中用逗號分隔的專案放在花括號中。集合中的專案可以是不同資料型別的。

>>> {2023, "Python", 3.11, 5+6j, 1.23E-4}
{(5+6j), 3.11, 0.000123, 'Python', 2023}

請注意,集合中的專案可能不遵循輸入時的順序。Python 會最佳化專案的位置,以便根據數學中定義的集合執行操作。

Python 的集合是內建 **set** 類的物件,可以使用 type() 函式進行檢查。

>>> type({2023, "Python", 3.11, 5+6j, 1.23E-4})
<class 'set'>

集合只能儲存不可變物件,例如數字(int、float、complex 或 bool)、字串或元組。如果你試圖將列表或字典放入集合中,Python 將引發 **TypeError**。

>>> {['One', 'Two', 'Three'], 1,2,3, (1.0, 2.0, 3.0)}
Traceback (most recent call last):
   File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

**雜湊** 是計算機科學中的一種機制,它可以更快地在計算機記憶體中搜索物件。**只有不可變物件才是可雜湊的**。

即使集合不允許可變項,集合本身也是可變的。因此,可以使用內建 set 類中的方法對集合物件執行新增/刪除/更新操作。Python 還有一組運算子來執行集合操作。這些方法和運算子將在後面的章節中解釋。

Python - 型別轉換

在製造業中,鑄造是將液態或熔融金屬澆入模具中,然後使其冷卻以獲得所需形狀的過程。在程式設計中,強制型別轉換是指將一個型別的物件轉換為另一種型別。在這裡,我們將學習 Python 中的型別轉換。

在Python中,存在不同的資料型別,例如數字、序列、對映等。你可能會遇到這種情況:你擁有某種型別的資料,但想以另一種形式使用它。例如,使用者輸入了一個字串,但你想將其用作數字。Python的型別轉換機制允許你做到這一點。

Python中的隱式轉換

轉換分為兩種型別——**隱式**和**顯式**。

當任何語言的編譯器/直譯器自動將一種型別物件轉換為另一種型別時,這稱為隱式轉換。Python是一種強型別語言。它不允許在不相關的型別之間進行自動型別轉換。例如,字串不能轉換為任何數字型別。但是,整數可以轉換為浮點數。其他語言,例如JavaScript,是一種弱型別語言,其中整數會被強制轉換為字串以進行連線。

請注意,每種型別的記憶體需求不同。例如,Python中的整數物件佔用4個位元組的記憶體,而浮點數物件由於其小數部分需要8個位元組。因此,Python直譯器不會自動將浮點數轉換為整數,因為這會導致資料丟失。另一方面,透過將其小數部分設定為0,可以輕鬆地將整數轉換為浮點數。

當對一個整數和一個浮點數運算元進行任何算術運算時,就會發生隱式整數到浮點數的轉換。

我們有一個整數和一個浮點變數

>>> a=10 # int object
>>> b=10.5 # float object

為了執行它們的加法,整數物件10被升級為10.0。它是一個浮點數,但等效於其之前的數值。現在我們可以執行兩個浮點數的加法。

>>> c=a+b
>>> print (c)
20.5

在隱式型別轉換中,位元組大小較小的物件會被升級以匹配運算中其他物件的位元組大小。例如,布林物件在與浮點數物件相加之前,首先被升級為整數,然後升級為浮點數。在下面的示例中,我們嘗試將布林物件新增到浮點數中。

>>> a=True
>>> b=10.5
>>> c=a+b
>>> print (c)
11.5

請注意,True 等於 1,False 等於 0。

儘管自動或隱式轉換僅限於**int**到**float**的轉換,但可以使用Python的內建函式執行顯式轉換,例如將字串轉換為整數。

int() 函式

Python的內建int()函式將整數字面量轉換為整數物件,將浮點數轉換為整數,如果字串本身具有有效的整數字面量表示形式,則將字串轉換為整數。

使用int()函式並傳入int物件作為引數等效於直接宣告一個**int**物件。

>>> a = int(10)
>>> a
10

與以下相同:

>>> a = 10
>>> a
10
>>> type(a)
<class 'int>

如果int()函式的引數是浮點數物件或浮點表示式,它將返回一個int物件。例如:

>>> a = int(10.5) #converts a float object to int
>>> a
10
>>> a = int(2*3.14) #expression results float, is converted to int
>>> a
6
>>> type(a)
<class 'int'>

如果給定布林物件作為引數,int()函式也會返回整數1。

>>> a=int(True)
>>> a
1
>>> type(a)
<class 'int'>

字串轉換為整數

int()函式僅當字串包含有效的整數表示形式時,才從字串物件返回整數。

>>> a = int("100")
>>> a
100
>>> type(a)
<class 'int'>
>>> a = ("10"+"01")
>>> a = int("10"+"01")
>>> a
1001
>>> type(a)
<class 'int'>

但是,如果字串包含非整數表示形式,Python將引發ValueError。

>>> a = int("10.5")
Traceback (most recent call last):
   File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: '10.5'
>>> a = int("Hello World")
Traceback (most recent call last):
   File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: 'Hello World'

int()函式還可以從二進位制、八進位制和十六進位制字串返回整數。為此,函式需要一個base引數,該引數必須分別為2、8或16。字串應該具有有效的二進位制/八進位制/十六進位制表示形式。

二進位制字串轉換為整數

字串應僅由1和0組成,基數應為2。

>>> a = int("110011", 2)
>>> a
51

二進位制數110011的十進位制等效值為51。

八進位制字串轉換為整數

字串應僅包含0到7的數字,基數應為8。

>>> a = int("20", 8)
>>> a
16

八進位制20的十進位制等效值為16。

十六進位制字串轉換為整數

字串應僅包含十六進位制符號,即0-9和A、B、C、D、E或F。基數應為16。

>>> a = int("2A9", 16)
>>> a
681

十六進位制2A9的十進位制等效值為681。

你可以使用Windows、Ubuntu或智慧手機上的計算器應用程式輕鬆驗證這些轉換。

float() 函式

float()是Python中的內建函式。如果引數是浮點字面量、整數或具有有效浮點表示形式的字串,它將返回一個浮點數物件。

使用float()函式並傳入float物件作為引數等效於直接宣告一個float物件。

>>> a = float(9.99)
>>> a
9.99
>>> type(a)
<class 'float'>

與以下相同:

>>> a = 9.99
>>> a
9.99
>>> type(a)
<class 'float'>

如果float()函式的引數是整數,則返回值是一個浮點數,其小數部分設定為0。

>>> a = float(100)
>>> a
100.0
>>> type(a)
<class 'float'>

如果字串包含有效的浮點數,float()函式將從字串返回浮點數物件;否則,將引發ValueError。

>>> a = float("9.99")
>>> a
9.99
>>> type(a)
<class 'float'>
>>> a = float("1,234.50")
Traceback (most recent call last):
   File "<stdin>", line 1, in <module>
ValueError: could not convert string to float: '1,234.50'

這裡出現ValueError的原因是字串中存在逗號。

為了進行字串到浮點數的轉換,浮點數的科學計數法也被認為是有效的。

>>> a = float("1.00E4")
>>> a
10000.0
>>> type(a)
<class 'float'>
>>> a = float("1.00E-4")
>>> a
0.0001
>>> type(a)
<class 'float'>

str() 函式

我們看到了Python如何從相應的字串表示中獲取整數或浮點數。str()函式則相反。它用引號(')包圍整數或浮點數物件以返回一個str物件。str()函式返回字串。

任何Python物件的表示。在本節中,我們將看到Python中str()函式的不同示例。

str()函式具有三個引數。第一個必需引數(或自變數)是我們要獲取其字串表示的物件。其他兩個運算子encoding和errors是可選的。

我們將在Python控制檯中執行str()函式,以輕鬆驗證返回的物件是一個字串,並帶有包圍的引號(') 。

整數轉換為字串

>>> a = str(10)
>>> a
'10'
>>> type(a)
<class 'str'>

浮點數轉換為字串

str()函式將具有兩種浮點數表示法的浮點數物件轉換為字串物件:標準表示法(用小數點分隔整數和小數部分)和科學計數法。

>>> a=str(11.10)
>>> a
'11.1'
>>> type(a)
<class 'str'>
>>> a = str(2/5)
>>> a
'0.4'
>>> type(a)
<class 'str'>

在第二種情況下,除法表示式作為引數傳遞給str()函式。請注意,表示式首先被求值,然後結果被轉換為字串。

使用E或e以及正負冪的科學計數法表示的浮點數將使用str()函式轉換為字串。

>>> a=str(10E4)
>>> a
'100000.0'
>>> type(a)
<class 'str'>
>>> a=str(1.23e-4)
>>> a
'0.000123'
>>> type(a)
<class 'str'>

當布林常量作為引數輸入時,它會被(')包圍,以便True變為'True'。列表和元組物件也可以作為引數傳遞給str()函式。生成的字串是被(')包圍的列表/元組。

>>> a=str('True')
>>> a
'True'
>>> a=str([1,2,3])
>>> a
'[1, 2, 3]'
>>> a=str((1,2,3))
>>> a
'(1, 2, 3)'
>>> a=str({1:100, 2:200, 3:300})
>>> a
'{1: 100, 2: 200, 3: 300}'

序列型別的轉換

列表、元組和字串是Python的序列型別。它們是有序或索引的專案集合。

可以使用**list()**函式將字串和元組轉換為列表物件。類似地,**tuple()**函式將字串或列表轉換為元組。

我們將建立這三種序列型別的物件,並研究它們的相互轉換。

>>> a=[1,2,3,4,5]
>>> b=(1,2,3,4,5)
>>> c="Hello"
### list() separates each character in the string and builds the list
>>> obj=list(c)
>>> obj
['H', 'e', 'l', 'l', 'o']
### The parentheses of tuple are replaced by square brackets
>>> obj=list(b)
>>> obj
[1, 2, 3, 4, 5]
### tuple() separates each character from string and builds a tuple of
characters
>>> obj=tuple(c)
>>> obj
('H', 'e', 'l', 'l', 'o')
### square brackets of list are replaced by parentheses.
>>> obj=tuple(a)
>>> obj
(1, 2, 3, 4, 5)
### str() function puts the list and tuple inside the quote symbols.
>>> obj=str(a)
>>> obj
'[1, 2, 3, 4, 5]'
>>> obj=str(b)
>>> obj
'(1, 2, 3, 4, 5)'

因此,Python的顯式型別轉換功能允許在內建函式的幫助下將一種資料型別轉換為另一種資料型別。

Python - Unicode 系統

軟體應用程式通常需要以多種不同的語言(例如英語、法語、日語、希伯來語或印地語)顯示輸出訊息。Python的字串型別使用Unicode標準來表示字元。它使程式能夠處理所有這些不同的字元。

字元是文字中最小的組成部分。'A'、'B'、'C'等都是不同的字元。'È'和'Í'也是如此。

根據Unicode標準,字元由碼點表示。碼點值是0到0x10FFFF範圍內的整數。

碼點序列在記憶體中表示為一組碼元,對映到8位位元組。將Unicode字串轉換為位元組序列的規則稱為字元編碼。

存在三種類型的編碼:UTF-8、UTF-16和UTF-32。UTF代表**Unicode轉換格式**。

從Python 3.0開始,內建支援Unicode。**str**型別包含Unicode字元,因此使用單引號、雙引號或三引號字串語法建立的任何字串都儲存為Unicode。Python原始碼的預設編碼為UTF-8。

因此,字串可能包含Unicode字元的字面表示(3/4)或其Unicode值(\u00BE)。

var = "3/4"
print (var)
var = "\u00BE"
print (var)

以上程式碼將產生以下**輸出**:

'3/4'
3/4

在下面的示例中,字串'10'使用1和0的Unicode值儲存,它們分別是\u0031和u0030。

var = "\u0031\u0030"
print (var)

它將產生以下**輸出**:

10

字串以人類可讀的格式顯示文字,而位元組以二進位制資料儲存字元。編碼將資料從字元字串轉換為一系列位元組。解碼將位元組轉換回人類可讀的字元和符號。重要的是不要

混淆這兩種方法。encode是字串方法,而decode是Python位元組物件的方。

在下面的示例中,我們有一個字串變數,其中包含ASCII字元。ASCII是Unicode字元集的子集。encode()方法用於將其轉換為位元組物件。

string = "Hello"
tobytes = string.encode('utf-8')
print (tobytes)
string = tobytes.decode('utf-8')
print (string)

decode()方法將位元組物件轉換回str物件。使用的編碼方法是utf-8。

b'Hello'
Hello

在下面的示例中,盧比符號(₹)使用其Unicode值儲存在變數中。我們將字串轉換為位元組,然後轉換回str。

string = "\u20B9"
print (string)
tobytes = string.encode('utf-8')
print (tobytes)
string = tobytes.decode('utf-8')
print (string)

執行上述程式碼時,將產生以下**輸出**:

₹
b'\xe2\x82\xb9'
₹

Python - 字面量

在計算機科學中,字面量是在原始碼中表示固定值的表示法。例如,在賦值語句中。

x = 10

這裡10是一個字面量,因為表示10的數值直接儲存在記憶體中。但是,

y = x*2

這裡,即使表示式計算結果為20,它也沒有直接包含在原始碼中。你也可以使用內建的int()函式宣告一個int物件:

x = int(10)

但是,這也是一種間接的例項化方式,而不是字面量。

你可以使用字面量表示法來建立任何內建資料型別的物件。

整數字面量

任何僅包含數字符號(0到9)的表示法都會建立一個**int**型別的物件。使用賦值運算子,可以將如此宣告的物件由變數引用。

請看下面的**示例**:

x = 10
y = -25
z = 0

Python允許將整數表示為八進位制數或十六進位制數。僅包含八個數字符號(0到7)但以0o或0O為字首的數字表示是八進位制數。

x = 0O34

類似地,一系列十六進位制符號(0到9以及a到f),以0x或0X為字首,表示十六進位制形式的整數。

x = 0X1C

但是,需要注意的是,即使使用八進位制或十六進位制字面量表示法,Python在內部仍將其視為**int**型別。

# Using Octal notation
x = 0O34
print ("0O34 in octal is", x, type(x))
# Using Hexadecimal notation
x = 0X1c
print ("0X1c in Hexadecimal is", x, type(x))

執行此程式碼時,將產生以下**輸出**:

0O34 in octal is 28 <class 'int'>
0X1c in Hexadecimal is 28 <class 'int'>

浮點字面量

浮點數由整數部分和小數部分組成。按照慣例,小數點符號(.)在浮點數的字面量表示中分隔這兩個部分。例如,

x = 25.55
y = 0.05
z = -12.2345

對於過大或過小的浮點數,如果小數點前或後的位數過多,則使用科學計數法進行緊湊的字面表示。整數部分之後跟著 E 或 e 符號,後面跟著正整數或負整數。

例如,數字 1.23E05 等於 123000.00。類似地,1.23e-2 等於 0.0123

# Using normal floating point notation
x = 1.23
print ("1.23 in normal float literal is", x, type(x))
# Using Scientific notation
x = 1.23E5
print ("1.23E5 in scientific notation is", x, type(x))
x = 1.23E-2
print ("1.23E-2 in scientific notation is", x, type(x))

在這裡,您將得到以下輸出

1.23 in normal float literal is 1.23 <class 'float'>
1.23E5 in scientific notation is 123000.0 <class 'float''>
1.23E-2 in scientific notation is 0.0123 <class 'float''>

複數字面量

複數由實部和虛部組成。虛部是任何數字(整數或浮點數)乘以“-1”的平方根。

($\sqrt{−1}$)。在字面表示中,($\sqrt{−1}$) 用 "j" 或 "J" 表示。因此,複數的字面表示形式為 x+yj。

#Using literal notation of complex number
x = 2+3j
print ("2+3j complex literal is", x, type(x))
y = 2.5+4.6j
print ("2.5+4.6j complex literal is", x, type(x))

這段程式碼將產生以下輸出

2+3j complex literal is (2+3j) <class 'complex'>
2.5+4.6j complex literal is (2+3j) <class 'complex'>

字串字面量

字串物件是 Python 中的序列資料型別之一。它是 Unicode 程式碼點的不可變序列。程式碼點是一個數字,根據 Unicode 標準對應於一個字元。字串是 Python 內建類 'str' 的物件。

字串字面量是用單引號 ('hello')、雙引號 ("hello") 或三引號 ('''hello''' 或 """hello""") 將一系列字元括起來來編寫的。

var1='hello'
print ("'hello' in single quotes is:", var1, type(var1))
var2="hello"
print ('"hello" in double quotes is:', var1, type(var1))
var3='''hello'''
print ("''''hello'''' in triple quotes is:", var1, type(var1))
var4="""hello"""
print ('"""hello""" in triple quotes is:', var1, type(var1))

在這裡,您將得到以下輸出

'hello' in single quotes is: hello <class 'str'>
"hello" in double quotes is: hello <class 'str'>
''''hello'''' in triple quotes is: hello <class 'str'>
"""hello""" in triple quotes is: hello <class 'str'>

如果需要將雙引號作為字串的一部分嵌入,則字串本身應放在單引號中。另一方面,如果要嵌入單引號文字,則字串應放在雙引號中。

var1='Welcome to "Python Tutorial" from TutorialsPoint'
print (var1)
var2="Welcome to 'Python Tutorial' from TutorialsPoint"
print (var2)

它將產生以下**輸出**:

Welcome to "Python Tutorial" from TutorialsPoint
Welcome to 'Python Tutorial' from TutorialsPoint

列表字面量

Python 中的列表物件是其他資料型別物件的集合。列表是有序的專案集合,這些專案不一定是相同型別的。集合中的各個物件透過從零開始的索引訪問。

列表物件的字面表示是用一個或多個專案完成的,這些專案用逗號分隔,並用方括號 [] 括起來。

L1=[1,"Ravi",75.50, True]
print (L1, type(L1))

它將產生以下**輸出**:

[1, 'Ravi', 75.5, True] <class 'list'>

元組字面量

Python 中的元組物件是其他資料型別物件的集合。元組是有序的專案集合,這些專案不一定是相同型別的。集合中的各個物件透過從零開始的索引訪問。

元組物件的字面表示是用一個或多個專案完成的,這些專案用逗號分隔,並用圓括號 () 括起來。

T1=(1,"Ravi",75.50, True)
print (T1, type(T1))

它將產生以下**輸出**:

[1, 'Ravi', 75.5, True] <class tuple>

Python 序列的預設分隔符是圓括號,這意味著沒有圓括號的逗號分隔序列也相當於元組的宣告。

T1=1,"Ravi",75.50, True
print (T1, type(T1))

在這裡,您也將得到相同的輸出

[1, 'Ravi', 75.5, True] <class tuple>

字典字面量

與列表或元組一樣,字典也是一種集合資料型別。但是,它不是序列。它是一個無序的專案集合,每個專案都是一個鍵值對。值透過 ":" 符號繫結到鍵。用逗號分隔的一個或多個鍵值對放在花括號內,形成一個字典物件。

capitals={"USA":"New York", "France":"Paris", "Japan":"Tokyo",
"India":"New Delhi"}
numbers={1:"one", 2:"Two", 3:"three",4:"four"}
points={"p1":(10,10), "p2":(20,20)}

鍵應該是不可變的物件。數字、字串或元組可以用作鍵。一個集合中鍵不能出現多次。如果一個鍵出現多次,則只保留最後一個。值可以是任何資料型別。一個值可以分配給多個鍵。例如:

staff={"Krishna":"Officer", "Rajesh":"Manager", "Ragini":"officer", "Anil":"Clerk", "Kavita":"Manager"}

Python - 運算子

在 Python 以及任何程式語言中,運算子都是預定義的符號(有時是關鍵字),用於對一個或多個運算元執行某些最常用的操作。

運算子型別

Python 語言支援以下型別的運算子:

  • 算術運算子

  • 比較(關係)運算子

  • 賦值運算子

  • 邏輯運算子

  • 位運算子

  • 成員運算子

  • 身份運算子

讓我們逐一看看這些運算子。

Python - 算術運算子

在 Python 中,數字是最常用的資料型別。Python 使用與大家熟悉的算術基本運算相同的符號,即 "+" 表示加法,“-” 表示減法,“*” 表示乘法(大多數程式語言使用 "*" 代替數學/代數中使用的 "x"),“/” 表示除法(同樣代替數學中使用的 "÷")。

此外,Python 還定義了更多算術運算子。它們是 "%"(模運算)、"**"(指數運算)和 "//"(地板除)。

算術運算子是二元運算子,因為它們作用於兩個運算元。Python 完全支援混合算術。也就是說,這兩個運算元可以是兩種不同的數字型別。在這種情況下,Python 會擴充套件較窄的運算元。整數物件比浮點數物件窄,浮點數比複數物件窄。因此,整數和浮點數的算術運算結果是浮點數。浮點數和複數的結果是複數,類似地,整數和複數物件的運算結果是複數物件。

讓我們用例子來學習這些運算子。

Python - 加法運算子 (+)

這個運算子讀作加號,是一個基本的算術運算子。它將兩側的兩個數值運算元相加並返回加法結果。

在下面的示例中,兩個整型變數是 "+" 運算子的運算元。

a=10
b=20
print ("Addition of two integers")
print ("a =",a,"b =",b,"addition =",a+b)

它將產生以下**輸出**:

Addition of two integers
a = 10 b = 20 addition = 30

整數和浮點數相加的結果是浮點數。

a=10
b=20.5
print ("Addition of integer and float")
print ("a =",a,"b =",b,"addition =",a+b)

它將產生以下**輸出**:

Addition of integer and float
a = 10 b = 20.5 addition = 30.5

將浮點數加到複數的結果是複數。

a=10+5j
b=20.5
print ("Addition of complex and float")
print ("a=",a,"b=",b,"addition=",a+b)

它將產生以下**輸出**:

Addition of complex and float
a= (10+5j) b= 20.5 addition= (30.5+5j)

Python - 減法運算子 (-)

這個運算子,稱為減號,從第一個運算元中減去第二個運算元。如果第二個運算元較大,則結果數為負數。

第一個例子顯示了兩個整數的減法。

a=10
b=20
print ("Subtraction of two integers:")
print ("a =",a,"b =",b,"a-b =",a-b)
print ("a =",a,"b =",b,"b-a =",b-a)

結果:

Subtraction of two integers
a = 10 b = 20 a-b = -10
a = 10 b = 20 b-a = 10

整數和浮點數的減法遵循相同的原理。

a=10
b=20.5
print ("subtraction of integer and float")
print ("a=",a,"b=",b,"a-b=",a-b)
print ("a=",a,"b=",b,"b-a=",b-a)

它將產生以下**輸出**:

subtraction of integer and float
a= 10 b= 20.5 a-b= -10.5
a= 10 b= 20.5 b-a= 10.5

在涉及複數和浮點數的減法中,參與運算的是實部。

a=10+5j
b=20.5
print ("subtraction of complex and float")
print ("a=",a,"b=",b,"a-b=",a-b)
print ("a=",a,"b=",b,"b-a=",b-a)

它將產生以下**輸出**:

subtraction of complex and float
a= (10+5j) b= 20.5 a-b= (-10.5+5j)
a= (10+5j) b= 20.5 b-a= (10.5-5j)

Python - 乘法運算子 (*)

*(星號)符號在 Python 中定義為乘法運算子(在許多語言中也是如此)。它返回其兩側兩個運算元的乘積。如果任何一個運算元為負,則結果也為負。如果兩個都是負數,則結果為正數。更改運算元的順序不會更改結果

a=10
b=20
print ("Multiplication of two integers")
print ("a =",a,"b =",b,"a*b =",a*b)

它將產生以下**輸出**:

Multiplication of two integers
a = 10 b = 20 a*b = 200

在乘法中,浮點運算元可以具有標準小數點表示法或科學計數法。

a=10
b=20.5
print ("Multiplication of integer and float")
print ("a=",a,"b=",b,"a*b=",a*b)
a=-5.55
b=6.75E-3
print ("Multiplication of float and float")
print ("a =",a,"b =",b,"a*b =",a*b)

它將產生以下**輸出**:

Multiplication of integer and float
a = 10 b = 20.5 a-b = -10.5
Multiplication of float and float
a = -5.55 b = 0.00675 a*b = -0.037462499999999996

對於涉及一個複數運算元的乘法運算,另一個運算元會乘以複數的實部和虛部。

a=10+5j
b=20.5
print ("Multiplication of complex and float")
print ("a =",a,"b =",b,"a*b =",a*b)

它將產生以下**輸出**:

Multiplication of complex and float
a = (10+5j) b = 20.5 a*b = (205+102.5j)

Python - 除法運算子 (/)

"/" 符號通常稱為正斜槓。除法運算子的結果是分子(左運算元)除以分母(右運算元)。如果任何一個運算元為負,則結果數為負。由於無窮大無法儲存在記憶體中,如果分母為 0,則 Python 會引發 ZeroDivisionError。

在 Python 中,除法運算子的結果始終是浮點數,即使兩個運算元都是整數。

a=10
b=20
print ("Division of two integers")
print ("a=",a,"b=",b,"a/b=",a/b)
print ("a=",a,"b=",b,"b/a=",b/a)

它將產生以下**輸出**:

Division of two integers
a= 10 b= 20 a/b= 0.5
a= 10 b= 20 b/a= 2.0

在除法中,浮點運算元可以具有標準小數點表示法或科學計數法。

a=10
b=-20.5
print ("Division of integer and float")
print ("a=",a,"b=",b,"a/b=",a/b)
a=-2.50
b=1.25E2
print ("Division of float and float")
print ("a=",a,"b=",b,"a/b=",a/b)

它將產生以下**輸出**:

Division of integer and float
a= 10 b= -20.5 a/b= -0.4878048780487805
Division of float and float
a= -2.5 b= 125.0 a/b= -0.02

當其中一個運算元是複數時,會發生另一個運算元與複數物件的兩部分(實部和虛部)之間的除法。

a=7.5+7.5j
b=2.5
print ("Division of complex and float")
print ("a =",a,"b =",b,"a/b =",a/b)
print ("a =",a,"b =",b,"b/a =",b/a)

它將產生以下**輸出**:

Division of complex and float
a = (7.5+7.5j) b = 2.5 a/b = (3+3j)
a = (7.5+7.5j) b = 2.5 b/a = (0.16666666666666666-0.16666666666666666j)

如果分子為 0,則除法的結果始終為 0,除非分母為 0,在這種情況下,Python 會引發 ZeroDivisionError,並顯示“除以零”錯誤訊息。

a=0
b=2.5
print ("a=",a,"b=",b,"a/b=",a/b)
print ("a=",a,"b=",b,"b/a=",b/a)

它將產生以下**輸出**:

a= 0 b= 2.5 a/b= 0.0
Traceback (most recent call last):
  File "C:\Users\mlath\examples\example.py", line 20, in <module>
     print ("a=",a,"b=",b,"b/a=",b/a)
                                 ~^~
ZeroDivisionError: float division by zero

Python - 模運算子 (%)

Python 將 "%" 符號定義為模運算子。它返回分母除以分子後的餘數。它也可以稱為餘數運算子。模運算子的結果是在整數商之後剩下的數字。例如,當 10 除以 3 時,商為 3,餘數為 1。因此,10%3(通常讀作 10 模 3)的結果為 1。

如果兩個運算元都是整數,則模值為整數。如果分子完全可被整除,則餘數為 0。如果分子小於分母,則模等於分子。如果分母為 0,則 Python 會引發 ZeroDivisionError。

a=10
b=2
print ("a=",a, "b=",b, "a%b=", a%b)
a=10
b=4
print ("a=",a, "b=",b, "a%b=", a%b)
print ("a=",a, "b=",b, "b%a=", b%a)
a=0
b=10
print ("a=",a, "b=",b, "a%b=", a%b)
print ("a=", a, "b=", b, "b%a=",b%a)

它將產生以下**輸出**:

a= 10 b= 2 a%b= 0
a= 10 b= 4 a%b= 2
a= 10 b= 4 b%a= 4
a= 0 b= 10 a%b= 0
Traceback (most recent call last):
  File "C:\Users\mlath\examples\example.py", line 13, in <module>
    print ("a=", a, "b=", b, "b%a=",b%a)
                                    ~^~
ZeroDivisionError: integer modulo by zero

如果任何一個運算元是浮點數,則模值始終是浮點數。

a=10
b=2.5
print ("a=",a, "b=",b, "a%b=", a%b)
a=10
b=1.5
print ("a=",a, "b=",b, "a%b=", a%b)
a=7.7
b=2.5
print ("a=",a, "b=",b, "a%b=", a%b)
a=12.4
b=3
print ("a=",a, "b=",b, "a%b=", a%b)

它將產生以下**輸出**:

a= 10 b= 2.5 a%b= 0.0
a= 10 b= 1.5 a%b= 1.0
a= 7.7 b= 2.5 a%b= 0.20000000000000018
a= 12.4 b= 3 a%b= 0.40000000000000036

Python 不接受複數用作模運算中的運算元。它會丟擲 TypeError: unsupported operand type(s) for %。

Python - 指數運算子 (**)

Python 使用 **(雙星號)作為指數運算子(有時稱為乘方運算子)。因此,對於 a**b,可以說 a 的 b 次方,甚至 a 的 b 次冪。

如果在指數表示式中,兩個運算元都是整數,則結果也是整數。如果其中一個是浮點數,則結果是浮點數。類似地,如果其中一個運算元是複數,則指數運算子返回複數。

如果底數為 0,則結果為 0;如果指數為 0,則結果始終為 1。

a=10
b=2
print ("a=",a, "b=",b, "a**b=", a**b)
a=10
b=1.5
print ("a=",a, "b=",b, "a**b=", a**b)
a=7.7
b=2
print ("a=",a, "b=",b, "a**b=", a**b)
a=1+2j
b=4
print ("a=",a, "b=",b, "a**b=", a**b)
a=12.4
b=0
print ("a=",a, "b=",b, "a**b=", a**b)
print ("a=",a, "b=",b, "b**a=", b**a)

它將產生以下**輸出**:

a= 10 b= 2 a**b= 100
a= 10 b= 1.5 a**b= 31.622776601683793
a= 7.7 b= 2 a**b= 59.290000000000006
a= (1+2j) b= 4 a**b= (-7-24j)
a= 12.4 b= 0 a**b= 1.0
a= 12.4 b= 0 b**a= 0.0

Python - 地板除運算子 (//)

地板除也稱為整數除法。Python 使用 //(雙正斜槓)符號來實現此目的。與返回餘數的模運算不同,地板除給出所涉及運算元除法的商。

如果兩個運算元都是正數,則地板除運算子返回一個去除小數部分的數字。例如,9.8 除以 2 的地板除結果為 4(純除法為 4.9,去除小數部分,結果為 4)。

但是,如果其中一個運算元為負數,則結果將遠離零舍入(朝負無窮大)。-9.8 除以 2 的地板除結果為 -5(純除法為 -4.9,遠離 0 舍入)。

a=9
b=2
print ("a=",a, "b=",b, "a//b=", a//b)
a=9
b=-2
print ("a=",a, "b=",b, "a//b=", a//b)
a=10
b=1.5
print ("a=",a, "b=",b, "a//b=", a//b)
a=-10
b=1.5
print ("a=",a, "b=",b, "a//b=", a//b)

它將產生以下**輸出**:

a= 9 b= 2 a//b= 4
a= 9 b= -2 a//b= -5
a= 10 b= 1.5 a//b= 6.0
a= -10 b= 1.5 a//b= -7.0

Python - 複數算術運算

當兩個運算元都是複數物件時,算術運算子的行為略有不同。

複數的加法和減法是各自實部和虛部的簡單加法/減法。

a=2.5+3.4j
b=-3+1.0j
print ("Addition of complex numbers - a=",a, "b=",b, "a+b=", a+b)
print ("Subtraction of complex numbers - a=",a, "b=",b, "a-b=", a-b)

它將產生以下**輸出**:

Addition of complex numbers - a= (2.5+3.4j) b= (-3+1j) a+b= (-0.5+4.4j)
Subtraction of complex numbers - a= (2.5+3.4j) b= (-3+1j) a-b=
(5.5+2.4j)

複數的乘法類似於代數中兩個二項式的乘法。如果 "a+bj" 和 "x+yj" 是兩個複數,則它們的乘法由以下公式給出:

(a+bj)*(x+yj) = ax+ayj+xbj+byj2 = (ax-by)+(ay+xb)j

例如:

a=6+4j
b=3+2j
c=a*b
c=(18-8)+(12+12)j
c=10+24j

以下程式確認結果:

a=6+4j
b=3+2j
print ("Multplication of complex numbers - a=",a, "b=",b, "a*b=", a*b)

要了解兩個複數的除法是如何進行的,我們應該使用複數的共軛。Python 的複數物件有一個 conjugate() 方法,它返回一個虛部符號反轉的複數。

>>> a=5+6j
>>> a.conjugate()
(5-6j)

要除以兩個複數,請將分子和分母都除以分母的共軛。

a=6+4j
b=3+2j
c=a/b
c=(6+4j)/(3+2j)
c=(6+4j)*(3-2j)/3+2j)*(3-2j)
c=(18-12j+12j+8)/(9-6j+6j+4)
c=26/13
c=2+0j

要驗證,請執行以下程式碼:

a=6+4j
b=3+2j
print ("Division of complex numbers - a=",a, "b=",b, "a/b=", a/b)

Python 中的 Complex 類不支援模運算子 (%) 和地板除運算子 (//)。

Python - 賦值運算子

=(等於)符號在 Python 中定義為賦值運算子。其右側的 Python 表示式的值將分配給其左側的單個變數。程式設計中(尤其是在 Python 中)的 = 符號不應與它在數學中的用法混淆,在數學中它表示符號兩側的表示式相等。

除了簡單的賦值運算子外,Python 還提供了一些賦值運算子用於高階用途。它們被稱為累積或增強賦值運算子。在本節中,我們將學習使用 Python 中定義的增強賦值運算子。

考慮以下Python語句:

a=10
b=5
a=a+b
print (a)

起初,至少對於程式設計新手但懂數學的人來說,“a=a+b”這個語句看起來很奇怪。a怎麼可能等於“a+b”?然而,需要再次強調的是,這裡的“=”符號是賦值運算子,而不是用來表示左邊和右邊的相等。

因為它是一個賦值操作,右側的表示式計算結果為15,該值被賦值給a。

在語句“a+=b”中,兩個運算子“+”和“=”可以組合成一個“+=”運算子。它被稱為加法賦值運算子。它在一個語句中執行兩個運算元“a”和“b”的加法,並將結果賦值給左邊的運算元“a”。

+=運算子是一個增強型運算子。它也稱為累加運算子,因為它將“b”新增到“a”中,並將結果重新賦值給變數a。

Python對所有算術和比較運算子都有增強型賦值運算子。

Python - 增強型加法運算子(+=)

此運算子在一個語句中組合了加法和賦值。由於Python支援混合算術運算,兩個運算元可以是不同型別。但是,如果右運算元的型別更寬,則左運算元的型別會更改為右運算元的型別。

下面的例子將有助於理解“+=”運算子是如何工作的:

a=10
b=5
print ("Augmented addition of int and int")
a+=b #equivalent to a=a+b
print ("a=",a, "type(a):", type(a))
a=10
b=5.5
print ("Augmented addition of int and float")
a+=b #equivalent to a=a+b
print ("a=",a, "type(a):", type(a))
a=10.50
b=5+6j
print ("Augmented addition of float and complex")
a+=b #equivalent to a=a+b
print ("a=",a, "type(a):", type(a))

它將產生以下**輸出**:

Augmented addition of int and int
a= 15 type(a): <class 'int'>
Augmented addition of int and float
a= 15.5 type(a): <class 'float'>
Augmented addition of float and complex
a= (15.5+6j) type(a): <class 'complex'>

Python - 增強型減法運算子(-=)

使用-=符號在一個語句中執行減法和賦值操作。“a-=b”語句執行“a=a-b”賦值。運算元可以是任何數字型別。Python對大小較小的物件執行隱式型別轉換。

a=10
b=5
print ("Augmented subtraction of int and int")
a-=b #equivalent to a=a-b
print ("a=",a, "type(a):", type(a))
a=10
b=5.5
print ("Augmented subtraction of int and float")
a-=b #equivalent to a=a-b
print ("a=",a, "type(a):", type(a))
a=10.50
b=5+6j
print ("Augmented subtraction of float and complex")
a-=b #equivalent to a=a-b
print ("a=",a, "type(a):", type(a))

它將產生以下**輸出**:

Augmented subtraction of int and int
a= 5 type(a): <class 'int'>
Augmented subtraction of int and float
a= 4.5 type(a): <class 'float'>
Augmented subtraction of float and complex
a= (5.5-6j) type(a): <class 'complex'>

Python - 增強型乘法運算子(*=)

*=運算子的工作原理類似。“a*=b”執行乘法和賦值操作,等效於“a=a*b”。對於兩個複數的增強型乘法,適用上一章中討論的乘法規則。

a=10
b=5
print ("Augmented multiplication of int and int")
a*=b #equivalent to a=a*b
print ("a=",a, "type(a):", type(a))
a=10
b=5.5
print ("Augmented multiplication of int and float")
a*=b #equivalent to a=a*b
print ("a=",a, "type(a):", type(a))
a=6+4j
b=3+2j
print ("Augmented multiplication of complex and complex")
a*=b #equivalent to a=a*b
print ("a=",a, "type(a):", type(a))

它將產生以下**輸出**:

Augmented multiplication of int and int
a= 50 type(a): <class 'int'>
Augmented multiplication of int and float
a= 55.0 type(a): <class 'float'>
Augmented multiplication of complex and complex
a= (10+24j) type(a): <class 'complex'>

Python - 增強型除法運算子(/=)

組合符號"/="充當除法和賦值運算子,因此“a/=b”等效於“a=a/b”。int或float運算元的除法運算結果為float。兩個複數的除法返回一個複數。下面是增強型除法運算子的示例。

a=10
b=5
print ("Augmented division of int and int")
a/=b #equivalent to a=a/b
print ("a=",a, "type(a):", type(a))
a=10
b=5.5
print ("Augmented division of int and float")
a/=b #equivalent to a=a/b
print ("a=",a, "type(a):", type(a))
a=6+4j
b=3+2j
print ("Augmented division of complex and complex")
a/=b #equivalent to a=a/b
print ("a=",a, "type(a):", type(a))

它將產生以下**輸出**:

Augmented division of int and int
a= 2.0 type(a): <class 'float'>
Augmented division of int and float
a= 1.8181818181818181 type(a): <class 'float'>
Augmented division of complex and complex
a= (2+0j) type(a): <class 'complex'>

Python - 增強型取模運算子(%=)

要在單個語句中執行取模和賦值操作,請使用%=運算子。與取模運算子一樣,它的增強版本也不支援複數。

a=10
b=5
print ("Augmented modulus operator with int and int")
a%=b #equivalent to a=a%b
print ("a=",a, "type(a):", type(a))
a=10
b=5.5
print ("Augmented modulus operator with int and float")
a%=b #equivalent to a=a%b
print ("a=",a, "type(a):", type(a))

它將產生以下**輸出**:

Augmented modulus operator with int and int
a= 0 type(a): <class 'int'>
Augmented modulus operator with int and float
a= 4.5 type(a): <class 'float'>

Python - 增強型指數運算子(**=)

**=運算子計算“a”的“b”次冪,並將值重新賦值給“a”。下面是一些例子:

a=10
b=5
print ("Augmented exponent operator with int and int")
a**=b #equivalent to a=a**b
print ("a=",a, "type(a):", type(a))
a=10
b=5.5
print ("Augmented exponent operator with int and float")
a**=b #equivalent to a=a**b
print ("a=",a, "type(a):", type(a))
a=6+4j
b=3+2j
print ("Augmented exponent operator with complex and complex")
a**=b #equivalent to a=a**b
print ("a=",a, "type(a):", type(a))

它將產生以下**輸出**:

Augmented exponent operator with int and int
a= 100000 type(a): <class 'int'>
Augmented exponent operator with int and float
a= 316227.7660168379 type(a): <class 'float'>
Augmented exponent operator with complex and complex
a= (97.52306038414744-62.22529992036203j) type(a): <class 'complex'>

Python - 增強型地板除運算子(//=)

要在單個語句中執行地板除和賦值,請使用//=運算子。“a//=b”等效於“a=a//b”。此運算子不能與複數一起使用。

a=10
b=5
print ("Augmented floor division operator with int and int")
a//=b #equivalent to a=a//b
print ("a=",a, "type(a):", type(a))
a=10
b=5.5
print ("Augmented floor division operator with int and float")
a//=b #equivalent to a=a//b
print ("a=",a, "type(a):", type(a))

它將產生以下**輸出**:

Augmented floor division operator with int and int
a= 2 type(a): <class 'int'>
Augmented floor division operator with int and float
a= 1.0 type(a): <class 'float'>

Python - 比較運算子

Python中的比較運算子在Python的條件語句(**if, else**和**elif**)和迴圈語句(while和for迴圈)中非常重要。像算術運算子一樣,比較運算子(也稱為關係運算符,“<”代表小於,“>”代表大於)也是眾所周知的。

Python使用另外兩個運算子,將“=”符號與這兩個運算子組合。“<=”符號表示小於或等於。“>=”符號表示大於或等於。

Python還有另外兩個比較運算子,形式為“==”和“!=”。它們分別表示等於和不等於運算子。因此,Python中共有六個比較運算子。

< 小於 a
> 大於 a>b
<= 小於或等於 a<=b
>= 大於或等於 a>=b
== 等於 a==b
!= 不等於 a!=b

比較運算子本質上是二元的,需要兩個運算元。包含比較運算子的表示式稱為布林表示式,始終返回True或False。

a=5
b=7
print (a>b)
print (a<b)

它將產生以下**輸出**:

False
True

兩個運算元可以是Python字面量、變數或表示式。由於Python支援混合算術運算,您可以使用任何數字型別的運算元。

以下程式碼演示了Python的**比較運算子與整數**的使用:

print ("Both operands are integer")
a=5
b=7
print ("a=",a, "b=",b, "a>b is", a>b)
print ("a=",a, "b=",b,"a<b is",a<b)
print ("a=",a, "b=",b,"a==b is",a==b)
print ("a=",a, "b=",b,"a!=b is",a!=b)

它將產生以下**輸出**:

Both operands are integer
a= 5 b= 7 a>b is False
a= 5 b= 7 a<b is True
a= 5 b= 7 a==b is False
a= 5 b= 7 a!=b is True

浮點數比較

在下面的示例中,比較了一個整數和一個浮點型運算元。

print ("comparison of int and float")
a=10
b=10.0
print ("a=",a, "b=",b, "a>b is", a>b)
print ("a=",a, "b=",b,"a<b is",a<b)
print ("a=",a, "b=",b,"a==b is",a==b)
print ("a=",a, "b=",b,"a!=b is",a!=b)

它將產生以下**輸出**:

comparison of int and float
a= 10 b= 10.0 a>b is False
a= 10 b= 10.0 a<b is False
a= 10 b= 10.0 a==b is True
a= 10 b= 10.0 a!=b is False

複數比較

雖然複數物件是Python中的數字資料型別,但它的行為與其他型別不同。Python不支援<和>運算子,但它支援等於(==)和不等於(!=)運算子。

print ("comparison of complex numbers")
a=10+1j
b=10.-1j
print ("a=",a, "b=",b,"a==b is",a==b)
print ("a=",a, "b=",b,"a!=b is",a!=b)

它將產生以下**輸出**:

comparison of complex numbers
a= (10+1j) b= (10-1j) a==b is False
a= (10+1j) b= (10-1j) a!=b is True

使用小於或大於運算子會得到TypeError。

print ("comparison of complex numbers")
a=10+1j
b=10.-1j
print ("a=",a, "b=",b,"a<b is",a<b)
print ("a=",a, "b=",b,"a>b is",a>b)

它將產生以下**輸出**:

comparison of complex numbers
Traceback (most recent call last):
  File "C:\Users\mlath\examples\example.py", line 5, in <module>
    print ("a=",a, "b=",b,"a<b is",a<b)
                                      ^^^
TypeError: '<' not supported between instances of 'complex' and
'complex

布林值比較

Python中的布林物件實際上是整數:True是1,False是0。實際上,Python將任何非零數字視為True。在Python中,可以比較布林物件。“False < True”為True!

print ("comparison of Booleans")
a=True
b=False
print ("a=",a, "b=",b,"a<b is",a<b)
print ("a=",a, "b=",b,"a>b is",a>b)
print ("a=",a, "b=",b,"a==b is",a==b)
print ("a=",a, "b=",b,"a!=b is",a!=b)

它將產生以下**輸出**:

comparison of Booleans
a= True b= False a<b is False
a= True b= False a>b is True
a= True b= False a==b is False
a= True b= False a!=b is True

序列型別比較

在Python中,只能對類似的序列物件進行比較。字串物件只能與另一個字串進行比較。列表不能與元組進行比較,即使兩者具有相同的專案。

print ("comparison of different sequence types")
a=(1,2,3)
b=[1,2,3]
print ("a=",a, "b=",b,"a<b is",a<b)

它將產生以下**輸出**:

comparison of different sequence types
Traceback (most recent call last):
  File "C:\Users\mlath\examples\example.py", line 5, in <module>
    print ("a=",a, "b=",b,"a<b is",a<b)
                                       ^^^
TypeError: '<' not supported between instances of 'tuple' and 'list'

序列物件透過詞法排序機制進行比較。比較從第0個索引處的專案開始。如果它們相等,則比較移動到下一個索引,直到某個索引處的專案不相等,或者其中一個序列用盡。如果一個序列是另一個序列的初始子序列,則較短的序列是較小的(較小的)序列。

哪個運算元更大取決於它們不相等的索引處專案的數值差異。例如,“BAT”>“BAR”為True,因為T在Unicode順序中位於R之後。

如果兩個序列的所有專案都比較相等,則認為這兩個序列相等。

print ("comparison of strings")
a='BAT'
b='BALL'
print ("a=",a, "b=",b,"a<b is",a<b)
print ("a=",a, "b=",b,"a>b is",a>b)
print ("a=",a, "b=",b,"a==b is",a==b)
print ("a=",a, "b=",b,"a!=b is",a!=b)

它將產生以下**輸出**:

comparison of strings
a= BAT b= BALL a<b is False
a= BAT b= BALL a>b is True
a= BAT b= BALL a==b is False
a= BAT b= BALL a!=b is True

在下面的示例中,比較了兩個元組物件:

print ("comparison of tuples")
a=(1,2,4)
b=(1,2,3)
print ("a=",a, "b=",b,"a<b is",a<b)
print ("a=",a, "b=",b,"a>b is",a>b)
print ("a=",a, "b=",b,"a==b is",a==b)
print ("a=",a, "b=",b,"a!=b is",a!=b)

它將產生以下**輸出**:

a= (1, 2, 4) b= (1, 2, 3) a<b is False
a= (1, 2, 4) b= (1, 2, 3) a>b is True
a= (1, 2, 4) b= (1, 2, 3) a==b is False
a= (1, 2, 4) b= (1, 2, 3) a!=b is True

字典物件比較

對於Python的字典,未定義使用“<”和“>”運算子。對於這些運算元,報告TypeError: '<' not supported between instances of 'dict' and 'dict'。

相等性比較檢查兩個字典專案的長度是否相同。字典的長度是其中鍵值對的數量。

Python字典只是按長度進行比較。元素較少的字典被認為小於元素較多的字典。

print ("comparison of dictionary objects")
a={1:1,2:2}
b={2:2, 1:1, 3:3}
print ("a=",a, "b=",b,"a==b is",a==b)
print ("a=",a, "b=",b,"a!=b is",a!=b)

它將產生以下**輸出**:

comparison of dictionary objects
a= {1: 1, 2: 2} b= {2: 2, 1: 1, 3: 3} a==b is False
a= {1: 1, 2: 2} b= {2: 2, 1: 1, 3: 3} a!=b is True

Python - 邏輯運算子

使用Python中的邏輯運算子,我們可以形成複合布林表示式。這些邏輯運算子的每個運算元本身就是一個布林表示式。例如,

age>16 and marks>80
percentage<50 or attendance<75

除了關鍵字False之外,Python還將None、所有型別的數字零以及空序列(字串、元組、列表)、空字典和空集合解釋為False。所有其他值都被視為True。

Python中有三個邏輯運算子。它們是“and”、“or”和“not”。它們必須是小寫。

“and”運算子

為了使複合布林表示式為True,兩個運算元都必須為True。如果任何一個或兩個運算元計算結果為False,則表示式返回False。下表顯示了各種情況。

a b a and b
F F F
F T F
T F F
T T T

“or”運算子

相反,“or”運算子如果任何一個運算元為True,則返回True。為了使複合布林表示式為False,兩個運算元都必須為False,如下表所示:

a b a or b
F F F
F T T
T F F
T T T

“not”運算子

這是一個一元運算子。它反轉其後跟的布林運算元的狀態。因此,not True變為False,not False變為True。

a not (a)
F T
T F

Python直譯器如何評估邏輯運算子?

表示式“x and y”首先評估“x”。如果“x”為false,則返回其值;否則,評估“y”並返回結果值。

logical_operator

表示式“x or y”首先評估“x”;如果“x”為true,則返回其值;否則,評估“y”並返回結果值。

x_or_y

下面給出了一些邏輯運算子的用例:

x = 10
y = 20
print("x > 0 and x < 10:",x > 0 and x < 10)
print("x > 0 and y > 10:",x > 0 and y > 10)
print("x > 10 or y > 10:",x > 10 or y > 10)
print("x%2 == 0 and y%2 == 0:",x%2 == 0 and y%2 == 0)
print ("not (x+y>15):", not (x+y)>15)

它將產生以下**輸出**:

x > 0 and x < 10: False
x > 0 and y > 10: True
x > 10 or y > 10: True
x%2 == 0 and y%2 == 0: True
not (x+y>15): False

我們可以使用非布林運算元與邏輯運算子。在這裡,我們需要注意到任何非零數字和非空序列都被評估為True。因此,邏輯運算子的相同真值表適用。

在下面的示例中,數值運算元用於邏輯運算子。“x”、“y”的值為True,“z”為False

x = 10
y = 20
z = 0
print("x and y:",x and y)
print("x or y:",x or y)
print("z or x:",z or x)
print("y or z:", y or z)

它將產生以下**輸出**:

x and y: 20
x or y: 10
z or x: 10
y or z: 20

在下面的示例中,字串變數被視為True,空元組被視為False:

a="Hello"
b=tuple()
print("a and b:",a and b)
print("b or a:",b or a)

它將產生以下**輸出**:

a and b: ()
b or a: Hello

最後,下面的兩個列表物件是非空的。因此,x and y返回後者,x or y返回前者。

x=[1,2,3]
y=[10,20,30]
print("x and y:",x and y)
print("x or y:",x or y)

它將產生以下**輸出**:

x and y: [10, 20, 30]
x or y: [1, 2, 3]

Python - 位運算子

Python的按位運算子通常與整數型別物件一起使用。但是,它不是將物件作為一個整體對待,而是將其視為位字串。對字串中的每個位執行不同的操作。

Python有六個按位運算子-&、|、^、~、<<和>>。所有這些運算子(除了~)本質上都是二元的,因為它們作用於兩個運算元。每個運算元都是一個二進位制數字(位)1或0。

Python - 按位與運算子(&)

按位與運算子有點類似於邏輯與運算子。只有當兩個位運算元都是1(即True)時,它才返回True。所有組合如下:

0 & 0 is 0
1 & 0 is 0
0 & 1 is 0
1 & 1 is 1

當使用整數作為運算元時,兩者都轉換為等效的二進位制數,&操作對每個數字的對應位進行操作,從最低有效位開始,向最高有效位移動。

讓我們取兩個整數60和13,並將它們分別賦值給變數a和b。

a=60
b=13
print ("a:",a, "b:",b, "a&b:",a&b)

它將產生以下**輸出**:

a: 60 b: 13 a&b: 12

為了瞭解Python如何執行該操作,請獲取每個變數的二進位制等效值。

print ("a:", bin(a))
print ("b:", bin(b))

它將產生以下**輸出**:

a: 0b111100
b: 0b1101

為了方便起見,對每個數字使用標準的8位格式,因此“a”是00111100,“b”是00001101。讓我們手動對這兩個數字的每個對應位執行與運算。

            0011 1100
                &
            0000 1101
            -------------
            0000 1100

將結果二進位制數轉換回整數。您將得到12,這是前面獲得的結果。

>>> int('00001100',2)
12

Python - 按位或運算子(|)

“|”符號(稱為**管道**)是按位或運算子。如果任何位運算元為1,則結果為1,否則為0。

0 | 0 is 0
0 | 1 is 1
1 | 0 is 1
1 | 1 is 1

取相同的值a=60,b=13。“|”運算的結果為61。獲取它們的二進位制等效值。

a=60
b=13
print ("a:",a, "b:",b, "a|b:",a|b)
print ("a:", bin(a))
print ("b:", bin(b))

它將產生以下**輸出**:

a: 60 b: 13 a|b: 61
a: 0b111100
b: 0b1101

要手動執行“|”運算,請使用8位格式。

                0011 1100
                    |
                0000 1101
                -------------
                0011 1101

將二進位制數轉換回整數以核對結果:

>>> int('00111101',2)
61

Python - 二進位制異或運算子(^)

XOR 代表異或 (exclusive OR)。這意味著對兩個位元進行或運算的結果,只有當且僅當其中一個位元為 1 時,結果才為 1。

0 ^ 0 is 0
0 ^ 1 is 1
1 ^ 0 is 1
1 ^ 1 is 0

讓我們對 a=60 和 b=13 進行異或運算。

a=60
b=13
print ("a:",a, "b:",b, "a^b:",a^b)

它將產生以下**輸出**:

a: 60 b: 13 a^b: 49

現在我們手動執行按位異或。

            0011 1100
                ^
            0000 1101
            -------------
            0011 0001

int() 函式顯示 00110001 為 49。

>>> int('00110001',2)
49

Python – 二進位制非運算子 (~)

此運算子是邏輯非運算子的二進位制等效運算子。它翻轉每個位元,使 1 替換為 0,0 替換為 1,並返回原始數字的補碼。Python 使用 2 的補碼方法。對於正整數,它只需反轉位元即可獲得。對於負數 -x,它使用 (x-1) 的位元模式並對所有位元進行補碼(從 1 切換到 0 或從 0 切換到 1)。因此:(對於 8 位表示)

-1 is complement(1 - 1) = complement(0) = "11111111"
-10 is complement(10 - 1) = complement(9) = complement("00001001") = "11110110".

對於 a=60,其補碼為 −

a=60
print ("a:",a, "~a:", ~a)

它將產生以下**輸出**:

a: 60 ~a: -61

Python – 左移運算子 (<<)

左移運算子將最高有效位向右移動“<<”符號右側的數字位數。因此,“x << 2” 會將二進位制表示的 x 的最高兩位向右移動。讓我們對 60 進行左移。

a=60
print ("a:",a, "a<<2:", a<<2)

它將產生以下**輸出**:

a: 60 a<<2: 240

這是如何發生的?讓我們使用 60 的二進位制等效值,並將其左移 2 位。

            0011 1100
             <<
                 2
            -------------
            1111 0000

將二進位制轉換為整數。它是 240。

>>> int('11110000',2)
240

Python – 右移運算子 (>>)

右移運算子將最低有效位向左移動“>>”符號右側的數字位數。因此,“x >> 2” 會將二進位制表示的 x 的最低兩位向左移動。讓我們對 60 進行右移。

a=60
print ("a:",a, "a>>2:", a>>2)

它將產生以下**輸出**:

a: 60 a>>2: 15

以下是 60 的手動右移操作 −

         0011 1100
         >>
             2
         -------------
         0000 1111

使用 int() 函式將上述二進位制數轉換為整數。它是 15。

>>> int('00001111',2)
15

Python - 成員運算子

Python 中的成員運算子幫助我們確定給定容器型別物件中是否存在某個項,或者換句話說,某個項是否是給定容器型別物件的成員。

Python 有兩個成員運算子:“in”和“not in”。兩者都返回布林結果。“in”運算子的結果與“not in”運算子的結果相反。

您可以使用 in 運算子檢查子字串是否出現在較大的字串中,任何項是否出現在列表或元組中,或者子列表或子元組是否包含在列表或元組中。

在下面的示例中,檢查不同的子字串是否屬於字串 var="TutorialsPoint"。Python 基於其 Unicode 值區分字元。因此,“To”與“to”不同。還要注意,如果“in”運算子返回 True,“not in”運算子則計算為 False。

var = "TutorialsPoint"
a = "P"
b = "tor"
c = "in"
d = "To"
print (a, "in", var, ":", a in var)
print (b, "not in", var, ":", b not in var)
print (c, "in", var, ":", c in var)
print (d, "not in", var, ":", d not in var)

它將產生以下**輸出**:

P in TutorialsPoint : True
tor not in TutorialsPoint : False
in in TutorialsPoint : True
To not in TutorialsPoint : True

您可以使用“in/not in”運算子檢查項在列表或元組中的成員資格。

var = [10,20,30,40]
a = 20
b = 10
c = a-b
d = a/2
print (a, "in", var, ":", a in var)
print (b, "not in", var, ":", b not in var)
print (c, "in", var, ":", c in var)
print (d, "not in", var, ":", d not in var)

它將產生以下**輸出**:

20 in [10, 20, 30, 40] : True
10 not in [10, 20, 30, 40] : False
10 in [10, 20, 30, 40] : True
10.0 not in [10, 20, 30, 40] : False

在最後一種情況下,“d”是浮點數,但它仍然與列表中的 10(一個**int**)比較為 True。即使以其他格式(如二進位制、八進位制或十六進位制)表示的數字也被給出,成員運算子也會說明它是否在序列中。

>>> 0x14 in [10, 20, 30, 40]
True

但是,如果您嘗試檢查列表或元組中是否存在兩個連續的數字,“in”運算子將返回 False。如果列表/元組本身包含連續數字作為序列,則它返回 True。

var = (10,20,30,40)
a = 10
b = 20
print ((a,b), "in", var, ":", (a,b) in var)
var = ((10,20),30,40)
a = 10
b = 20
print ((a,b), "in", var, ":", (a,b) in var)

它將產生以下**輸出**:

(10, 20) in (10, 20, 30, 40) : False
(10, 20) in ((10, 20), 30, 40) : True

Python 的成員運算子也適用於集合物件。

var = {10,20,30,40}
a = 10
b = 20
print (b, "in", var, ":", b in var)
var = {(10,20),30,40}
a = 10
b = 20
print ((a,b), "in", var, ":", (a,b) in var)

它將產生以下**輸出**:

20 in {40, 10, 20, 30} : True
(10, 20) in {40, 30, (10, 20)} : True

允許將 in 和 not in 運算子與字典物件一起使用。但是,Python 只檢查鍵的集合,而不是值的集合。

var = {1:10, 2:20, 3:30}
a = 2
b = 20
print (a, "in", var, ":", a in var)
print (b, "in", var, ":", b in var)

它將產生以下**輸出**:

2 in {1: 10, 2: 20, 3: 30} : True
20 in {1: 10, 2: 20, 3: 30} : False

Python - 身份運算子

Python 具有兩個身份運算子 is 和 is not。兩者都返回相反的布林值。“is”運算子如果兩個運算元物件共享相同的記憶體位置,則計算結果為 True。可以使用“id()”函式獲得物件的記憶體位置。如果兩個變數的 id() 相同,“is”運算子返回 True(因此,is not 返回 False)。

a="TutorialsPoint"
b=a
print ("id(a), id(b):", id(a), id(b))
print ("a is b:", a is b)
print ("b is not a:", b is not a)

它將產生以下**輸出**:

id(a), id(b): 2739311598832 2739311598832
a is b: True
b is not a: False

列表和元組物件的處理方式不同,這在最初看起來可能很奇怪。在下面的示例中,兩個列表“a”和“b”包含相同的項。但它們的 id() 不同。

a=[1,2,3]
b=[1,2,3]
print ("id(a), id(b):", id(a), id(b))
print ("a is b:", a is b)
print ("b is not a:", b is not a)

它將產生以下**輸出**:

id(a), id(b): 1552612704640 1552567805568
a is b: False
b is not a: True

列表或元組僅包含各個項的記憶體位置,而不是項本身。因此,“a”包含在特定位置的 10、20 和 30 整數物件的地址,這可能與“b”的不同。

print (id(a[0]), id(a[1]), id(a[2]))
print (id(b[0]), id(b[1]), id(b[2]))

它將產生以下**輸出**:

140734682034984 140734682035016 140734682035048
140734682034984 140734682035016 140734682035048

由於“a”和“b”的兩個位置不同,“**is**”運算子即使這兩個列表包含相同的數字,也返回 False。

Python - 註釋

計算機程式中的註釋是一段文字,旨在作為原始碼中的解釋性或描述性註釋,編譯器/直譯器在生成機器語言程式碼時不應考慮它。在源程式中大量使用註釋,使所有相關人員更容易理解演算法的語法、用法和邏輯等。

在 Python 指令碼中,符號 # 表示註釋行的開始。它在編輯器中有效到行尾。如果 # 是行的第一個字元,則整行都是註釋。如果在行中間使用,則其之前的文字是有效的 Python 表示式,而其後的文字則被視為註釋。

# this is a comment
print ("Hello World")
print ("How are you?") #also a comment but after a statement.

在 Python 中,沒有規定編寫多行註釋或塊註釋。(如 C/C++ 中,/* .. */ 內的多行被視為多行註釋)。

每行都應在開頭使用“#”符號標記為註釋。許多 Python IDE 都有快捷鍵可以將一段語句標記為註釋。

如果三引號多行字串不是函式或類的文件字串,它也被視為註釋。

'''
First line in the comment
Second line in the comment
Third line in the comment
'''
print ("Hello World")

Python - 使用者輸入

每個計算機應用程式都應具有在執行時接受使用者資料的規定。這使應用程式具有互動性。根據其開發方式,應用程式可以以在控制檯**(sys.stdin)**中輸入的文字、圖形佈局或基於 Web 的介面形式接受使用者輸入。在本章中,我們將學習 Python 如何從控制檯接受使用者輸入,並在控制檯上顯示輸出。

Python 直譯器以互動模式和指令碼模式工作。雖然互動模式非常適合快速評估,但效率較低。對於重複執行相同的指令集,應使用指令碼模式。

讓我們編寫一個簡單的 Python 指令碼開始。

#! /usr/bin/python3.11
name = "Kiran"
city = "Hyderabad"
print ("Hello My name is", name)
print ("I am from", city)

將上述程式碼儲存為 hello.py 並從命令列執行它。以下是輸出

C:\python311> python var1.py
Hello My name is Kiran
I am from Hyderabad

程式只是列印其中的兩個變數的值。如果重複執行程式,每次都會顯示相同的輸出。要將程式用於另一個名稱和城市,您可以編輯程式碼,將名稱更改為“Ravi”,將城市更改為“Chennai”。每次需要分配不同的值時,都必須編輯程式、儲存和執行,這不是理想的方法。

input() 函式

顯然,您需要某種機制來在執行時(程式執行時)為變數分配不同的值。Python 的**input()**函式完成了這項工作。

Python 的標準庫具有 input() 函式。

>>> var = input()

當直譯器遇到它時,它會等待使用者從標準輸入流(鍵盤)輸入資料,直到按下 Enter 鍵。字元序列可以儲存在字串變數中以供進一步使用。

讀取 Enter 鍵後,程式將繼續執行下一條語句。讓我們更改程式以將使用者輸入儲存在 name 和 city 變數中。

#! /usr/bin/python3.11
name = input()
city = input()
print ("Hello My name is", name)
print ("I am from ", city)

執行時,您會發現游標正在等待使用者的輸入。輸入 name 和 city 的值。使用輸入的資料,將顯示輸出。

Ravi
Chennai
Hello My name is Ravi
I am from Chennai

現在,程式中沒有為變數分配任何特定值。每次執行時,都可以輸入不同的值。因此,您的程式已成為真正的互動式程式。

在 input() 函式內,您可以提供**提示**文字,該文字將在您執行程式碼時出現在游標之前。

#! /usr/bin/python3.11
name = input("Enter your name : ")
city = input("enter your city : ")
print ("Hello My name is", name)
print ("I am from ", city)

執行程式時,會顯示提示訊息,基本上幫助使用者知道輸入什麼。

Enter your name: Praveen Rao
enter your city: Bengaluru
Hello My name is Praveen Rao
I am from Bengaluru

數字輸入

讓我們編寫一個 Python 程式碼,從使用者處接受矩形的寬度和高度並計算面積。

#! /usr/bin/python3.11
width = input("Enter width : ")
height = input("Enter height : ")
area = width*height
print ("Area of rectangle = ", area)

執行程式,輸入寬度和高度。

Enter width: 20
Enter height: 30
Traceback (most recent call last):
  File "C:\Python311\var1.py", line 5, in <module>
   area = width*height
TypeError: can't multiply sequence by non-int of type 'str'

為什麼這裡會出現**TypeError**?原因是,Python 總是將使用者輸入讀取為字串。因此,width="20" 和 height="30" 是字串,顯然您不能執行兩個字串的乘法。

為了克服這個問題,我們將使用**int()**,這是 Python 標準庫中的另一個內建函式。它將字串物件轉換為整數。

要從使用者處接受整數輸入,請將輸入讀取為字串,並使用 int() 函式將其型別轉換為整數 −

w= input("Enter width : ")
width=int(w)
h= input("Enter height : ")
height=int(h)

您可以將輸入和型別轉換語句組合在一個語句中 −

#! /usr/bin/python3.11
width = int(input("Enter width : "))
height = int(input("Enter height : "))
area = width*height
print ("Area of rectangle = ", area)

現在您可以向程式中的兩個變數輸入任何整數值 −

Enter width: 20
Enter height: 30
Area of rectangle = 600

Python 的**float()**函式將字串轉換為浮點數物件。以下程式接受使用者輸入並將其解析為浮點變數 rate,並計算使用者也輸入的金額的利息。

#! /usr/bin/python3.11
amount = float(input("Enter Amount : "))
rate = float(input("Enter rate of interest : "))
interest = amount*rate/100
print ("Amount: ", amount, "Interest: ", interest)

程式要求使用者輸入金額和利率;並顯示結果如下 −

Enter Amount: 12500
Enter rate of interest: 6.5
Amount: 12500.0 Interest: 812.5

print() 函式

Python 的 print() 函式是一個內建函式。它是最常用的函式,它在 Python 的控制檯或標準輸出**(sys.stdout)**上顯示括號中給出的 Python 表示式的值。

print ("Hello World ")

括號內可以有任意數量的 Python 表示式。它們必須用逗號分隔。列表中的每個項都可以是任何 Python 物件或有效的 Python 表示式。

#! /usr/bin/python3.11
a = "Hello World"
b = 100
c = 25.50
d = 5+6j
print ("Message: a)
print (b, c, b-c)
print(pow(100, 0.5), pow(c,2))

第一次呼叫 print() 顯示字串文字和字串變數。第二個列印兩個變數的值及其差值。**pow()**函式計算數字的平方根和變數的平方值。

Message Hello World
100 25.5 74.5
10.0 650.25

如果 print() 函式的括號中有多個用逗號分隔的物件,則這些值用空格“ ”分隔。要使用任何其他字元作為分隔符,請為 print() 函式定義**sep**引數。此引數應位於要列印的表示式列表之後。

在 print() 函式的以下輸出中,變數用逗號分隔。

#! /usr/bin/python3.11
city="Hyderabad"
state="Telangana"
country="India"
print(city, state, country, sep=',')

sep=',' 的效果可以在結果中看到 −

Hyderabad,Telangana,India

print() 函式預設在末尾發出換行符 ('\n')。結果,下一個 print() 語句的輸出出現在控制檯的下一行。

city="Hyderabad"
state="Telangana"
print("City:", city)
print("State:", state)

顯示兩行作為輸出 −

City: Hyderabad
State: Telangana

為了使這兩行出現在同一行,請在第一個 print() 函式中定義**end**引數並將其設定為空格字串“ ”。

city="Hyderabad"
state="Telangana"
country="India"
print("City:", city, end=" ")
print("State:", state)

兩個 print() 函式的輸出都連續出現。

City: Hyderabad State: Telangana

Python - 數字

大多數情況下,您在所做的一切中都會處理數字。顯然,任何計算機應用程式都處理數字。因此,包括 Python 在內的程式語言都內建支援儲存和處理數字資料。

在本章中,我們將詳細學習 Python 數字型別的屬性。

三種數字型別,整數**(int)**、浮點數**(float)**和**複數**,內置於 Python 直譯器中。Python 還具有內建的布林資料型別**bool**。它可以被視為 int 型別的子型別,因為它的兩個可能值 True 和 False 分別表示整數 1 和 0。

Python – 整數

在Python中,任何沒有小數部分的數字都是整數。(注意,如果一個數字的小數部分為0,並不意味著它就是一個整數。例如,數字10.0不是整數,它是一個小數部分為0的浮點數,其數值為10。)整數可以是零、正整數或負整數。例如,1234、0、-55。

建立整數物件有三種方法:字面量表示法、任何計算結果為整數的表示式,以及使用int()函式。

字面量是在原始碼中直接表示常量的表示法。例如:

>>> a =10

但是,請看下面整數變數c的賦值。

a=10
b=20
c=a+b
print ("a:", a, "type:", type(a))

它將產生以下**輸出**:

a: 10 type: <class 'int'>

這裡,c確實是一個整數變數,但是表示式a+b首先被計算,其值間接地賦值給c。

建立整數物件的第三種方法是使用int()函式的返回值。它將浮點數或字串轉換為整數。

>>> a=int(10.5)
>>> b=int("100")

您可以將整數表示為二進位制、八進位制或十六進位制數。但是,在內部,物件儲存為整數。

二進位制數

僅由二進位制數字(1和0)組成並以0b為字首的數字是二進位制數。如果將二進位制數賦給變數,它仍然是int變數。

要以二進位制形式表示整數,請直接將其儲存為字面量,或使用int()函式,其中基數設定為2。

a=0b101
print ("a:",a, "type:",type(a))
b=int("0b101011",2)
print ("b:",b, "type:",type(b))

它將產生以下**輸出**:

a: 5 type: <class 'int'>
b: 43 type: <class 'int'>

Python中還有一個bin()函式。它返回整數的二進位制字串等價物。

a=43
b=bin(a)
print ("Integer:",a, "Binary equivalent:",b)

它將產生以下**輸出**:

Integer: 43 Binary equivalent: 0b101011

八進位制數

八進位制數僅由數字0到7組成。為了指定整數使用八進位制表示法,需要在其前面加上0o(小寫O)或0O(大寫O)。八進位制數的字面量表示如下:

a=0O107
print (a, type(a))

它將產生以下**輸出**:

71 <class 'int'>

請注意,該物件在內部儲存為整數。八進位制數107的十進位制等價物是71。

由於八進位制數系統有8個符號(0到7),其基數為8。因此,在使用int()函式將八進位制字串轉換為整數時,需要將base引數設定為8。

a=int('20',8)
print (a, type(a))

它將產生以下**輸出**:

16 <class 'int'>

八進位制30的十進位制等價物是16。

在下面的程式碼中,從八進位制表示法獲得了兩個int物件,並執行了它們的加法運算。

a=0O56
print ("a:",a, "type:",type(a))
b=int("0O31",8)
print ("b:",b, "type:",type(b))
c=a+b
print ("addition:", c)

它將產生以下**輸出**:

a: 46 type: <class 'int'>
b: 25 type: <class 'int'>
addition: 71

要獲取整數的八進位制字串,請使用oct()函式。

a=oct(71)
print (a, type(a))

十六進位制數

顧名思義,十六進位制數系統中有16個符號。它們是0-9和A到F。前10個數字與十進位制數字相同。字母A、B、C、D、E和F分別相當於11、12、13、14、15和16。可以使用這些字母符號的大寫或小寫。

對於十六進位制表示法的整數的字面量表示,請在其前面加上0x0X

a=0XA2
print (a, type(a))

它將產生以下**輸出**:

162 <class 'int'>

要將十六進位制字串轉換為整數,請在int()函式中將基數設定為16。

a=int('0X1e', 16)
print (a, type(a))

嘗試執行以下程式碼片段。它接收一個十六進位制字串,並返回整數。

num_string = "A1"
number = int(num_string, 16)
print ("Hexadecimal:", num_string, "Integer:",number)

它將產生以下**輸出**:

Hexadecimal: A1 Integer: 161

但是,如果字串包含任何十六進位制符號表之外的符號(例如X001),則會引發以下錯誤:

Traceback (most recent call last):
  File "C:\Python311\var1.py", line 4, in <module>
    number = int(num_string, 16)
ValueError: invalid literal for int() with base 16: 'X001'

Python的標準庫具有hex()函式,您可以使用它來獲取整數的十六進位制等價物。

a=hex(161)
print (a, type(a))

它將產生以下**輸出**:

0xa1 <class 'str'>

儘管整數可以表示為二進位制、八進位制或十六進位制,但在內部它仍然是整數。因此,在執行算術運算時,表示法無關緊要。

a=10 #decimal
b=0b10 #binary
c=0O10 #octal
d=0XA #Hexadecimal
e=a+b+c+d
print ("addition:", e)

它將產生以下**輸出**:

addition: 30

Python——浮點數

浮點數具有整數部分和小數部分,由小數點符號(.)分隔。預設情況下,該數字為正數,對於負數,請在其前面加上減號(-)符號。

浮點數是Python的float類的物件。要儲存float物件,您可以使用字面量表示法,使用算術表示式的值,或使用float()函式的返回值。

使用字面量是最直接的方法。只需將帶小數部分的數字賦給變數。以下每個語句都聲明瞭一個float物件。

>>> a=9.99
>>> b=0.999
>>> c=-9.99
>>> d=-0.999

在Python中,對浮點數的小數點後可以有多少位數字沒有限制。但是,為了縮短表示法,使用Ee符號。E代表10的冪。例如,E4是10的4次冪(或10的4次方),e-3是10的-3次冪。

在科學計數法中,數字具有係數和指數部分。係數應為大於或等於1但小於10的浮點數。因此,1.23E+3、9.9E-5和1E10是使用科學計數法的浮點數的示例。

>>> a=1E10
>>> a
10000000000.0
>>> b=9.90E-5
>>> b
9.9e-05
>>> 1.23E3
1230.0

形成float物件的第二種方法是間接的,使用表示式的結果。這裡,兩個浮點數的商被賦給一個變數,該變數引用一個float物件。

a=10.33
b=2.66
c=a/b
print ("c:", c, "type", type(c))

它將產生以下**輸出**:

c: 3.8834586466165413 type <class 'float'>

Python的float()函式返回一個float物件,如果其內容合適,則解析數字或字串。如果括號中沒有給出引數,則返回0.0,對於int引數,則新增小數部分0。

>>> a=float()
>>> a
0.0
>>> a=float(10)
>>> a
10.0

即使整數以二進位制、八進位制或十六進位制表示,float()函式也會返回小數部分為0的浮點數。

a=float(0b10)
b=float(0O10)
c=float(0xA)
print (a,b,c, sep=",")

它將產生以下**輸出**:

2.0,8.0,10.0

float()函式從包含浮點數的字串中檢索浮點數,該浮點數可以是標準小數點格式,也可以是科學計數法。

a=float("-123.54")
b=float("1.23E04")
print ("a=",a,"b=",b)

它將產生以下**輸出**:

a= -123.54 b= 12300.0

在數學中,無窮大是一個抽象的概念。從物理上講,無限大的數字永遠無法儲存在任何數量的記憶體中。但是,對於大多數計算機硬體配置,10的400次冪的非常大的數字由Inf表示。如果將“Infinity”用作float()函式的引數,它將返回Inf。

a=1.00E400
print (a, type(a))
a=float("Infinity")
print (a, type(a))

它將產生以下**輸出**:

inf <class 'float'>
inf <class 'float'>

另一個這樣的實體是Nan(代表非數字)。它表示任何未定義或無法表示的值。

>>> a=float('Nan')
>>> a
Nan

Python——複數

在本節中,我們將詳細瞭解Python中的複數資料型別。複數在電磁學、電子學、光學和量子理論的數學方程式和定律中得到了應用。傅立葉變換使用複數。它們用於計算波函式、設計濾波器、數位電子中的訊號完整性、射電天文學等。

複數由實部和虛部分組成,由"+"或"-"分隔。實部可以是任何浮點數(或它本身是一個複數)。虛部也是一個浮點數/複數,但乘以一個虛數。

在數學中,虛數“i”定義為-1的平方根($\sqrt{−1}$)。因此,複數表示為“x+yi”,其中x是實部,“y”是虛部的係數。

通常,為了避免與在電力理論中作為電流的用法混淆,使用符號“j”代替“i”來表示虛數。Python也使用“j”作為虛數。因此,“x+yj”是Python中複數的表示法。

與int或float資料型別一樣,可以使用字面量表示法或使用complex()函式來形成複數物件。以下所有語句都構成一個複數物件。

>>> a=5+6j
>>> a
(5+6j)
>>> type(a)
<class 'complex'>
>>> a=2.25-1.2J
>>> a
(2.25-1.2j)
>>> type(a)
<class 'complex'>
>>> a=1.01E-2+2.2e3j
>>> a
(0.0101+2200j)
>>> type(a)
<class 'complex'>

請注意,實部以及虛部的係數必須是浮點數,它們可以以標準小數點表示法或科學計數法表示。

Python的complex()函式有助於形成複數型別的物件。該函式接收實部和虛部的引數,並返回複數。

complex()函式有兩個版本,分別有兩個引數和一個引數。使用帶兩個引數的complex()是很直接的。它使用第一個引數作為實部,第二個引數作為虛部的係數。

a=complex(5.3,6)
b=complex(1.01E-2, 2.2E3)
print ("a:", a, "type:", type(a))
print ("b:", b, "type:", type(b))

它將產生以下**輸出**:

a: (5.3+6j) type: <class 'complex'>
b: (0.0101+2200j) type: <class 'complex'>

在上面的示例中,我們使用了x和y作為浮點引數。它們甚至可以是複數資料型別。

a=complex(1+2j, 2-3j)
print (a, type(a))

它將產生以下**輸出**:

(4+4j) <class 'complex'>

對上面的例子感到驚訝嗎?將“x”設為1+2j,將“y”設為2-3j。嘗試手動計算“x+yj”,你就會明白了。

complex(1+2j, 2-3j)
=(1+2j)+(2-3j)*j
=1+2j +2j+3
=4+4j

如果只為complex()函式使用一個數值引數,它將將其視為實部的值;虛部設定為0。

a=complex(5.3)
print ("a:", a, "type:", type(a))

它將產生以下**輸出**:

a: (5.3+0j) type: <class 'complex'>

如果其唯一引數是具有複數表示的字串,則complex()函式還可以將字串解析為複數。

在下面的程式碼片段中,提示使用者輸入一個複數。它用作引數。由於Python將輸入讀取為字串,因此該函式從中提取複數物件。

a= "5.5+2.3j"
b=complex(a)
print ("Complex number:", b)

它將產生以下**輸出**:

Complex number: (5.5+2.3j)

Python的內建complex類有兩個屬性realimag——它們從物件中返回實部和虛部的係數。

a=5+6j
print ("Real part:", a.real, "Coefficient of Imaginary part:", a.imag)

它將產生以下**輸出**:

Real part: 5.0 Coefficient of Imaginary part: 6.0

complex類還定義了一個conjugate()方法。它返回另一個複數,其虛數部分的符號相反。例如,x+yj的共軛是x-yj。

>>> a=5-2.2j
>>> a.conjugate()
(5+2.2j)

Python - 布林值

在Python中,bool是int型別的子型別。bool物件有兩個可能的值,它用Python關鍵字True和False初始化。

>>> a=True
>>> b=False
>>> type(a), type(b)
(<class 'bool'>, <class 'bool'>)

bool物件被接受為型別轉換函式的引數。對於True作為引數,int()函式返回1,float()返回1.0;而對於False,它們分別返回0和0.0。我們有一個單引數版本的complex()函式。

如果引數是複數物件,則將其作為實部,並將虛數係數設定為0。

a=int(True)
print ("bool to int:", a)
a=float(False)
print ("bool to float:", a)
a=complex(True)
print ("bool to complex:", a)

執行此程式碼後,您將得到以下輸出

bool to int: 1
bool to float: 0.0
bool to complex: (1+0j)

Python - 控制流

預設情況下,計算機程式中的指令以順序方式執行,從上到下,或從開始到結束。但是,這種順序執行的程式只能執行簡單的任務。我們希望程式具有決策能力,以便它根據不同的條件執行不同的步驟。

包括Python在內的多數程式語言都提供了控制指令執行流程的功能。通常,有兩種型別的控制流語句。

決策——程式能夠根據某個布林表示式的值決定要執行哪個可選指令組。

下圖說明了決策語句的工作方式:

decision making statements

迴圈或迭代——大多數過程都需要重複執行一組指令。在程式設計術語中,這稱為迴圈。如果流程不是指向下一步,而是重定向到任何之前的步驟,則構成一個迴圈。

下圖說明了迴圈的工作方式:

looping_works

如果控制無條件地返回,則會形成無限迴圈,這是不希望的,因為其餘程式碼將永遠不會被執行。

在條件迴圈中,語句塊的重複迭代會持續到滿足某個條件為止。

Python - 決策

Python的決策功能在其關鍵字中——if、else和elif。if關鍵字需要一個布林表示式,後跟冒號符號。

冒號(:)符號開始一個縮排塊。如果if語句中的布林表示式為True,則執行具有相同縮排級別的語句。如果表示式不為True(False),直譯器將繞過縮排塊,並繼續執行較早縮排級別的語句。

Python——if語句

下圖說明了Pythonif語句的工作方式:

if statement works

語法

上述流程圖中的邏輯由以下語法表達:

if expr==True:
   stmt1
   stmt2
   stmt3
   ..
   ..
Stmt4

if語句類似於其他語言中的if語句。if語句包含一個布林表示式,使用該表示式比較資料,並根據比較結果做出決定。

如果布林表示式計算結果為 True,則執行 if 語句內的語句塊。在 Python 中,程式碼塊中的語句在“:”符號後統一縮排。如果布林表示式的計算結果為 False,則執行程式碼塊結束後的第一組程式碼。

示例

讓我們考慮一個例子:如果客戶的購買金額 >1000,則有權享受 10% 的折扣;否則,不適用任何折扣。此流程圖顯示了該過程。

if_flowchart

在 Python 中,我們首先將折扣變數設定為 0,並接受使用者輸入的金額。

接下來是條件語句 if amt > 1000。使用冒號 ":" 開始條件程式碼塊,在其中計算適用的折扣。顯然,無論是否打折,下一條語句都會預設列印 amount-discount。如果適用折扣,則會減去折扣金額,否則為 0。

discount = 0
amount = 1200
if amount > 1000:
   discount = amount * 10 / 100
print("amount = ",amount - discount)

這裡金額為 1200,因此扣除 120 的折扣。執行程式碼後,您將得到以下輸出

amount = 1080.0

將變數 amount 更改為 800,然後再次執行程式碼。這次不適用任何折扣。您將得到以下輸出:

amount = 800

Python - if-else 語句

除了if 語句之外,還可以選擇使用 else 關鍵字。如果布林表示式(在 if 語句中)不為真,它提供了要執行的另一組語句。此流程圖顯示瞭如何使用 else 程式碼塊。

ifelse syntax

如果 expr 為 True,則執行 stmt1、2、3 程式碼塊,然後預設流程繼續執行 stmt7。但是,如果 expr 為 False,則執行程式碼塊 stmt4、5、6,然後繼續預設流程。

語法

上述流程圖的 Python 實現如下:

if expr==True:
   stmt1
   stmt2
   stmt3
else:
   stmt4
   stmt5
   stmt6
Stmt7

示例

讓我們透過以下示例瞭解 else 子句的用法。變數 age 可以取不同的值。如果表示式“age > 18”為真,則顯示“您有資格投票”的訊息;否則,應顯示“無資格”訊息。下面的流程圖說明了此邏輯。

if-else

它的 Python 實現很簡單。

age=25
print ("age: ", age)
if age>=18:
   print ("eligible to vote")
else:
   print ("not eligible to vote")

首先,將整數變數“age”設定為 25。

然後使用if 語句和表示式“age > 18”,後跟冒號“:”開始一個程式碼塊;如果“age >= 18”為真,則此程式碼塊將被執行。

要提供else 程式碼塊,請使用“else:”;當“age >= 18”為假時,包含訊息“無資格”的後續縮排程式碼塊將被執行。

執行此程式碼後,您將得到以下輸出

age: 25
eligible to vote

要測試else 程式碼塊,請將age更改為 12,然後再次執行程式碼。

age: 12
not eligible to vote

Python - elif 語句

elif 語句允許您檢查多個表示式的真假,並在其中一個條件計算結果為 TRUE 時執行一段程式碼。

else 語句類似,elif 語句是可選的。但是,與 else 不同的是,else 最多隻能有一個語句;而if 語句之後可以有任意數量的elif 語句。

語法

if expression1:
   statement(s)
elif expression2:
   statement(s)
elif expression3:
   statement(s)
else:
   statement(s)

示例

讓我們藉助以下示例瞭解 elif 的工作原理。

前面示例中使用的折扣結構已修改為不同的折扣等級:

  • 金額超過 10000 元,享受 20% 的折扣;

  • 金額在 5000-10000 元之間,享受 10% 的折扣;

  • 金額在 1000-5000 元之間,享受 5% 的折扣;

  • 金額小於 1000 元,不享受折扣。

下面的流程圖說明了這些條件:

if-elif

示例

我們可以使用if-else 語句編寫上述邏輯的 Python 程式碼:

amount = int(input('Enter amount: '))
if amount > 10000:
   discount = amount * 20 / 100
else:
   if amount > 5000:
      discount = amount * 10 / 100
   else:
      if amount > 1000:
         discount = amount * 5 / 100
      else:
         dicount = 0
print('amount: ',amount - discount)

雖然程式碼可以完美執行,但如果您檢視每個 if 和 else 語句的縮排級別不斷增加,如果還有更多條件,則會難以管理。

elif 語句使程式碼更易於閱讀和理解。

elif 是“else if”的縮寫。它允許將邏輯排列在第一個 if 語句之後的 elif 語句級聯中。如果第一個if 語句計算結果為假,則會逐一評估後續的 elif 語句,如果滿足任何一個條件,則退出級聯。

級聯中的最後一個是else 程式碼塊,當所有前面的 if/elif 條件都失敗時,它將出現。

amount = 800
print('amount = ',amount)
if amount > 10000:
   discount = amount * 20 / 100
elif amount > 5000:
   discount = amount * 10 / 100
elif amount > 1000:
   discount = amount * 5 / 100
else:
   discount=0

print('payable amount = ',amount - discount)

設定amount 來測試所有可能的條件:800、2500、7500 和 15000。輸出將相應變化:

amount: 800
payable amount = 800
amount: 2500
payable amount = 2375.0
amount: 7500
payable amount = 6750.0
amount: 15000
payable amount = 12000.0

巢狀 if 語句

可能存在這樣的情況:在某個條件結果為真之後,您想檢查另一個條件。在這種情況下,可以使用巢狀if 結構。

在巢狀 if 結構中,可以在另一個 if...elif...else 結構中使用 if...elif...else 結構。

語法

巢狀if...elif...else 結構的語法如下:

if expression1:
   statement(s)
   if expression2:
      statement(s)
   elif expression3:
      statement(s)3
   else
      statement(s)
elif expression4:
   statement(s)
else:
   statement(s)

示例

現在讓我們來看一段 Python 程式碼來了解它的工作原理:

# !/usr/bin/python3
num=8
print ("num = ",num)
if num%2==0:
   if num%3==0:
      print ("Divisible by 3 and 2")
   else:
      print ("divisible by 2 not divisible by 3")
else:
   if num%3==0:
      print ("divisible by 3 not divisible by 2")
   else:
      print ("not Divisible by 2 not divisible by 3")

執行上述程式碼時,它會產生以下輸出

num = 8
divisible by 2 not divisible by 3
num = 15
divisible by 3 not divisible by 2
num = 12
Divisible by 3 and 2
num = 5
not Divisible by 2 not divisible by 3

Python - match-case 語句

在 3.10 版本之前,Python 缺乏類似於 C 或 C++ 中 switch-case 的功能。在 Python 3.10 中,引入了一種稱為 match-case 的模式匹配技術,它類似於“switch case”結構。

match 語句接受一個表示式,並將它的值與作為一個或多個 case 程式碼塊給出的後續模式進行比較。它的用法更類似於 Rust 或 Haskell 等語言中的模式匹配,而不是 C 或 C++ 中的 switch 語句。只有第一個匹配的模式才會被執行。還可以從值中提取元件(序列元素或物件屬性)到變數中。

語法

match-case 的基本用法是將變數與一個或多個值進行比較。

match variable_name:
   case 'pattern 1' : statement 1
   case 'pattern 2' : statement 2
   ...
   case 'pattern n' : statement n

示例

下面的程式碼包含一個名為 weekday() 的函式。它接收一個整數引數,將其與所有可能的星期幾數字值匹配,並返回相應的星期幾名稱。

def weekday(n):
   match n:
      case 0: return "Monday"
      case 1: return "Tuesday"
      case 2: return "Wednesday"
      case 3: return "Thursday"
      case 4: return "Friday"
      case 5: return "Saturday"
      case 6: return "Sunday"
      case _: return "Invalid day number"
print (weekday(3))
print (weekday(6))
print (weekday(7))

輸出

執行後,此程式碼將產生以下輸出:

Thursday
Sunday
Invalid day number

函式中的最後一個 case 語句使用 "_" 作為要比較的值。它用作萬用字元 case,如果所有其他 case 都為假,則將執行它。

組合 case

有時,可能存在這樣的情況:對於多個 case,需要採取類似的操作。為此,您可以使用由 "|" 符號表示的 OR 運算子組合 case。

示例

def access(user):
   match user:
      case "admin" | "manager": return "Full access"
      case "Guest": return "Limited access"
      case _: return "No access"
print (access("manager"))
print (access("Guest"))
print (access("Ravi"))

輸出

上面的程式碼定義了一個名為 access() 的函式,它有一個字串引數,表示使用者的名稱。對於 admin 或 manager 使用者,系統授予完全訪問許可權;對於 Guest,訪問許可權有限;對於其餘使用者,則無訪問許可權。

Full access
Limited access
No access

列表作為引數

由於 Python 可以將表示式與任何字面量匹配,因此您可以使用列表作為 case 值。此外,對於列表中數量可變的專案,可以使用 "*" 運算子將其解析為序列。

示例

def greeting(details):
   match details:
      case [time, name]:
         return f'Good {time} {name}!'
      case [time, *names]:
         msg=''
         for name in names:
            msg+=f'Good {time} {name}!\n'
         return msg

print (greeting(["Morning", "Ravi"]))
print (greeting(["Afternoon","Guest"]))
print (greeting(["Evening", "Kajal", "Praveen", "Lata"]))

輸出

執行後,此程式碼將產生以下輸出:

Good Morning Ravi!
Good Afternoon Guest!
Good Evening Kajal!
Good Evening Praveen!
Good Evening Lata!

在“case”子句中使用“if”

通常,Python 將表示式與字面量 case 進行匹配。但是,它允許您在 case 子句中包含 if 語句,用於對匹配變數進行條件計算。

在下面的示例中,函式引數是金額和期限的列表,需要計算金額小於或大於 10000 的利息。條件包含在case 子句中。

示例

def intr(details):
   match details:
      case [amt, duration] if amt<10000:
         return amt*10*duration/100
      case [amt, duration] if amt>=10000:
         return amt*15*duration/100
print ("Interest = ", intr([5000,5]))
print ("Interest = ", intr([15000,3]))

輸出

執行後,此程式碼將產生以下輸出:

Interest = 2500.0
Interest = 6750.0

Python - for 迴圈

Python 中的for 迴圈能夠迭代任何序列(例如列表或字串)的專案。

語法

for iterating_var in sequence:
   statements(s)

如果序列包含表示式列表,則先對其進行計算。然後,序列中的第一個專案(位於第 0 個索引處)將分配給迭代變數 iterating_var。

接下來,執行語句塊。列表中的每個專案都將分配給 iterating_var,並且語句塊將一直執行,直到整個序列耗盡。

下面的流程圖說明了for 迴圈的工作原理:

forloop

由於迴圈針對序列中的每個成員元素執行,因此無需顯式驗證控制迴圈的布林表示式(如while 迴圈)。

列表、元組或字串等序列物件稱為可迭代物件,因為 for 迴圈會迭代集合。任何迭代器物件都可以由for 迴圈迭代。

字典的 items()、keys() 和 values() 方法返回的檢視物件也是可迭代的,因此我們可以使用它們執行for 迴圈。

Python 的內建 range() 函式返回一個迭代器物件,該物件流式傳輸一系列數字。我們可以使用 range 執行 for 迴圈。

將“for”與字串一起使用

字串是由 Unicode 字母組成的序列,每個字母都有一個位置索引。以下示例比較每個字元,並顯示它是否不是母音('a'、'e'、'i'、'o' 或 'u')。

示例

zen = '''
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
'''
for char in zen:
   if char not in 'aeiou':
      print (char, end='')

輸出

執行後,此程式碼將產生以下輸出:

Btfl s bttr thn gly.
Explct s bttr thn mplct.
Smpl s bttr thn cmplx.
Cmplx s bttr thn cmplctd.

將“for”與元組一起使用

Python 的元組物件也是一個索引序列,因此我們可以使用for 迴圈遍歷其專案。

示例

在下面的示例中,for 迴圈遍歷包含整數的元組,並返回所有數字的總和。

numbers = (34,54,67,21,78,97,45,44,80,19)
total = 0
for num in numbers:
   total+=num
print ("Total =", total)

輸出

執行後,此程式碼將產生以下輸出:

Total = 539

將“for”與列表一起使用

Python 的列表物件也是一個索引序列,因此我們可以使用for 迴圈遍歷其專案。

示例

在下面的示例中,for 迴圈遍歷包含整數的列表,只打印能被 2 整除的整數。

numbers = [34,54,67,21,78,97,45,44,80,19]
total = 0
for num in numbers:
   if num%2 == 0:
      print (num)

輸出

執行後,此程式碼將產生以下輸出:

34
54
78
44
80

將“for”與範圍物件一起使用

Python 的內建 range() 函式返回一個範圍物件。Python 的範圍物件是一個迭代器,每次迭代都會生成一個整數。該物件包含從 start 到 stop 的整數,由 step 引數分隔。

語法

range() 函式具有以下語法:

range(start, stop, step)

引數

  • Start - 範圍的起始值。可選。預設為 0。

  • Stop - 範圍達到 stop-1。

  • Step - 範圍內的整數以 step 值遞增。可選,預設為 1。

返回值

range() 函式返回一個範圍物件。它可以解析為列表序列。

示例

numbers = range(5)
'''
start is 0 by default,
step is 1 by default,
range generated from 0 to 4
'''
print (list(numbers))
# step is 1 by default, range generated from 10 to 19
numbers = range(10,20)
print (list(numbers))
# range generated from 1 to 10 increment by step of 2
numbers = range(1, 10, 2)
print (list(numbers))

輸出

執行後,此程式碼將產生以下輸出:

[0, 1, 2, 3, 4]
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
[1, 3, 5, 7, 9]

示例

獲得範圍後,我們可以使用for 迴圈。

for num in range(5):
 print (num, end=' ')
print()
for num in range(10,20):
 print (num, end=' ')
print()
for num in range(1, 10, 2):
 print (num, end=' ')

輸出

執行後,此程式碼將產生以下輸出:

0 1 2 3 4
10 11 12 13 14 15 16 17 18 19
1 3 5 7 9

示例:數字的階乘

階乘是從 1 到該數字(例如 n)的所有數字的乘積。它也可以定義為 1、2 到 n 的乘積。

Factorial of a number n! = 1 * 2 * . . . . . * n

我們使用 range() 函式獲取從 1 到 n-1 的數字序列,並執行累積乘法以獲得階乘值。

fact=1
N = 5
for x in range(1, N+1):
   fact=fact*x
print ("factorial of {} is {}".format(N, fact))

輸出

執行後,此程式碼將產生以下輸出:

factorial of 5 is 120

在上程式中,更改 N 的值以獲得不同數字的階乘值。

將“for”迴圈與序列索引一起使用

要迭代序列,我們可以使用 range() 函式獲取索引列表。

Indices = range(len(sequence))

然後我們可以形成一個for 迴圈,如下所示:

numbers = [34,54,67,21,78]
indices = range(len(numbers))
for index in indices:
   print ("index:",index, "number:",numbers[index])

執行後,此程式碼將產生以下輸出

index: 0 number: 34
index: 1 number: 54
index: 2 number: 67
index: 3 number: 21
index: 4 number: 78

將“for”與字典一起使用

與列表、元組或字串不同,Python 中的字典資料型別不是序列,因為專案沒有位置索引。但是,仍然可以使用不同的技術遍歷字典。

在字典物件上執行簡單的for 迴圈會遍歷其中使用的鍵。

numbers = {10:"Ten", 20:"Twenty", 30:"Thirty",40:"Forty"}
for x in numbers:
   print (x)

執行後,此程式碼將產生以下輸出

10
20
30
40

一旦能夠獲取鍵,就可以使用方括號運算子或get() 方法輕鬆訪問其關聯的值。請檢視以下示例:

numbers = {10:"Ten", 20:"Twenty", 30:"Thirty",40:"Forty"}
for x in numbers:
   print (x,":",numbers[x])

它將產生以下**輸出**:

10 : Ten
20 : Twenty
30 : Thirty
40 : Forty

dict 類的 items()、keys() 和 values() 方法分別返回檢視物件 dict_items、dict_keys 和 dict_values。這些物件是迭代器,因此我們可以在其上執行 for 迴圈。

dict_items 物件是鍵值元組的列表,可以在其上執行 for 迴圈,如下所示:

numbers = {10:"Ten", 20:"Twenty", 30:"Thirty",40:"Forty"}
for x in numbers.items():
   print (x)

它將產生以下**輸出**:

(10, 'Ten')
(20, 'Twenty')
(30, 'Thirty')
(40, 'Forty')

這裡,“x”是來自 dict_items 迭代器的元組元素。我們可以進一步將此元組解包到兩個不同的變數中。檢視以下程式碼:

numbers = {10:"Ten", 20:"Twenty", 30:"Thirty",40:"Forty"}
for x,y in numbers.items():
   print (x,":", y)

它將產生以下**輸出**:

10 : Ten
20 : Twenty
30 : Thirty
40 : Forty

同樣,可以迭代 dict_keys 物件中的鍵集合。請檢視以下示例:

numbers = {10:"Ten", 20:"Twenty", 30:"Thirty",40:"Forty"}
for x in numbers.keys():
   print (x, ":", numbers[x])

它將產生相同的輸出

10 : Ten
20 : Twenty
30 : Thirty
40 : Forty

Python - for-else 迴圈

Python 支援將“else”語句與“for”迴圈語句一起使用。“else”語句如果與“for”迴圈一起使用,則在控制權轉移到主執行線之前序列耗盡時,將執行“else”語句。

下面的流程圖說明了如何將else 語句與for 迴圈一起使用:

for-else

示例

以下示例演示了else語句與for語句的組合。在計數小於5之前,會列印迭代計數。當計數變為5時,else塊中的列印語句會在控制權傳遞到主程式中的下一條語句之前執行。

for count in range(6):
   print ("Iteration no. {}".format(count))
else:
   print ("for loop over. Now in else block")
print ("End of for loop")

執行後,此程式碼將產生以下輸出

Iteration no. 1
Iteration no. 2
Iteration no. 3
Iteration no. 4
Iteration no. 5
for loop over. Now in else block
End of for loop

巢狀迴圈

Python程式語言允許在一個迴圈內使用另一個迴圈。以下部分顯示了一些示例來說明這個概念。

語法

for iterating_var in sequence:
   for iterating_var in sequence:
      statements(s)
      statements(s)

Python程式語言中巢狀while迴圈語句的語法如下:

while expression:
   while expression:
      statement(s)
   statement(s)

關於迴圈巢狀的最後一點說明是,您可以將任何型別的迴圈放在任何其他型別的迴圈內。例如,for迴圈可以放在while迴圈內,反之亦然。

示例

下面的程式使用巢狀for迴圈來顯示1-10的乘法表。

#!/usr/bin/python3
for i in range(1,11):
   for j in range(1,11):
      k=i*j
      print ("{:3d}".format(k), end=' ')
   print()

print()函式內迴圈具有end=' ',它附加空格而不是預設換行符。因此,數字將顯示在一行中。

最後一個print()將在內部for迴圈結束時執行。

執行上述程式碼時,它會產生以下輸出

  1   2   3   4   5   6   7   8   9  10 
  2   4   6   8  10  12  14  16  18  20 
  3   6   9  12  15  18  21  24  27  30 
  4   8  12  16  20  24  28  32  36  40 
  5  10  15  20  25  30  35  40  45  50 
  6  12  18  24  30  36  42  48  54  60 
  7  14  21  28  35  42  49  56  63  70 
  8  16  24  32  40  48  56  64  72  80 
  9  18  27  36  45  54  63  72  81  90 
 10  20  30  40  50  60  70  80  90 100 

Python - while迴圈

通常,計算機程式中步驟的執行流程是從開始到結束。但是,如果流程不是轉向下一步,而是重定向到任何較早的步驟,則構成一個迴圈。

Python程式語言中的while迴圈語句會重複執行目標語句,只要給定的布林表示式為真。

語法

Python程式語言中while迴圈的語法如下:

while expression:
   statement(s)

while關鍵字後跟一個布林表示式,然後是冒號符號,以開始一個縮排的語句塊。在這裡,statement(s)可以是單個語句,也可以是具有統一縮排的語句塊。條件可以是任何表示式,真值是任何非零值。只要布林表示式為真,迴圈就會迭代。

一旦表示式變為假,程式控制就會傳遞到緊跟在迴圈後面的行。

如果它未能變為假,迴圈將繼續執行,並且不會停止,除非強制停止。這樣的迴圈稱為無限迴圈,這在計算機程式中是不希望的。

下面的流程圖說明了while迴圈:

output hello world

示例1

在Python中,在程式設計結構之後以相同數量的字元空格縮排的所有語句都被認為是單個程式碼塊的一部分。Python使用縮排作為其語句分組的方法。

count=0
while count<5:
   count+=1
   print ("Iteration no. {}".format(count))

print ("End of while loop")

我們將計數變數初始化為0,迴圈執行直到“count<5”。在每次迭代中,都會遞增並檢查計數。如果它不是5,則進行下一次重複。在迴圈塊內,列印計數的瞬時值。當while條件變為假時,迴圈終止,並執行下一條語句,這裡是“while迴圈結束”訊息。

輸出

執行後,此程式碼將產生以下輸出:

Iteration no. 1
Iteration no. 2
Iteration no. 3
Iteration no. 4
Iteration no. 5
End of while loop

示例2

這是另一個使用while迴圈的示例。對於每次迭代,程式都會請求使用者輸入並持續重複,直到使用者輸入非數字字串。isnumeric()函式在輸入為整數時返回true,否則返回false。

var='0'
while var.isnumeric()==True:
   var=input('enter a number..')
   if var.isnumeric()==True:
      print ("Your input", var)
print ("End of while loop")

輸出

執行後,此程式碼將產生以下輸出:

enter a number..10
Your input 10
enter a number..100
Your input 100
enter a number..543
Your input 543
enter a number..qwer
End of while loop

無限迴圈

如果條件永遠不會變為FALSE,則迴圈將變成無限迴圈。使用while迴圈時必須謹慎,因為這種條件可能永遠不會解析為FALSE值。這會導致一個永不結束的迴圈。這樣的迴圈稱為無限迴圈。

無限迴圈可能在客戶端/伺服器程式設計中很有用,其中伺服器需要持續執行,以便客戶端程式可以根據需要與其進行通訊。

示例3

讓我們來看一個例子,瞭解無限迴圈如何在Python中工作:

#!/usr/bin/python3
var = 1
while var == 1 : # This constructs an infinite loop
   num = int(input("Enter a number :"))
   print ("You entered: ", num)
print ("Good bye!")

輸出

執行後,此程式碼將產生以下輸出:

Enter a number :20
You entered: 20
Enter a number :29
You entered: 29
Enter a number :3
You entered: 3
Enter a number :11
You entered: 11
Enter a number :22
You entered: 22
Enter a number :Traceback (most recent call last):
   File "examples\test.py", line 5, in
      num = int(input("Enter a number :"))
KeyboardInterrupt

上面的例子進入了一個無限迴圈,你需要使用CTRL+C來退出程式。

while-else迴圈

Python支援將else語句與while迴圈語句關聯。

如果else語句與while迴圈一起使用,則當條件在控制轉移到主執行線之前變為false時,將執行else語句。

下面的流程圖顯示瞭如何將elsewhile語句一起使用:

output hello world

示例

以下示例演示了else語句與while語句的組合。在計數小於5之前,會列印迭代計數。當計數變為5時,else塊中的列印語句會在控制權傳遞到主程式中的下一條語句之前執行。

count=0
while count<5:
   count+=1
   print ("Iteration no. {}".format(count))
else:
   print ("While loop over. Now in else block")
print ("End of while loop")

輸出

執行後,此程式碼將產生以下輸出

Iteration no. 1
Iteration no. 2
Iteration no. 3
Iteration no. 4
Iteration no. 5
While loop over. Now in else block
End of while loop

Python - break語句

迴圈控制語句

迴圈控制語句會改變其正常的執行順序。當執行離開作用域時,在該作用域中建立的所有自動物件都將被銷燬。

Python支援以下控制語句:

序號 控制語句及描述
1

break語句

終止迴圈語句並將執行轉移到緊跟在迴圈後面的語句。

2

continue語句

導致迴圈跳過其主體的其餘部分,並在重新迭代之前立即重新測試其條件。

3

pass語句

Python中的pass語句用於在語法上需要語句但不需要執行任何命令或程式碼時。

讓我們簡要地瞭解一下迴圈控制語句。

Python − break語句

break語句用於提前終止當前迴圈。放棄迴圈後,將在下一條語句處恢復執行,就像C中的傳統break語句一樣。

break最常見的用途是當觸發某些外部條件需要快速退出迴圈時。break語句可以用於while和for迴圈。

如果您使用的是巢狀迴圈,則break語句將停止執行最內層迴圈並開始執行程式碼塊後面的下一行程式碼。

語法

Python中break語句的語法如下:

break

流程圖

它的流程圖如下:

loop-break

示例1

現在讓我們來看一個例子,瞭解“break”語句如何在Python中工作:

#!/usr/bin/python3
print ('First example')
for letter in 'Python': # First Example
   if letter == 'h':
      break
   print ('Current Letter :', letter)
print ('Second example')
var = 10 # Second Example
while var > 0:
   print ('Current variable value :', var)
   var = var -1
   if var == 5:
      break
print ("Good bye!")

執行上述程式碼時,它會產生以下輸出

First example
Current Letter : P
Current Letter : y
Current Letter : t
Second example
Current variable value : 10
Current variable value : 9
Current variable value : 8
Current variable value : 7
Current variable value : 6
Good bye!

示例2

下面的程式演示了在遍歷列表的for迴圈中使用break。使用者輸入一個數字,該數字將在列表中搜索。如果找到它,則迴圈將以“已找到”訊息終止。

#!/usr/bin/python3
no=int(input('any number: '))
numbers=[11,33,55,39,55,75,37,21,23,41,13]
for num in numbers:
   if num==no:
      print ('number found in list')
      break
else:
   print ('number not found in list')

上述程式將產生以下輸出

any number: 33
number found in list
any number: 5
number not found in list

示例3:檢查質數

請注意,當遇到break語句時,Python會放棄迴圈中剩餘的語句,包括else塊。

以下示例利用此特性來查詢數字是否為質數。根據定義,如果一個數除了1和它本身之外不能被任何其他數整除,則它是質數。

以下程式碼在從2到所需數字-1的數字上執行for迴圈。如果它能被迴圈變數的任何值整除,則該數字不是質數,因此程式將從迴圈中中斷。如果該數字不能被2和x-1之間的任何數字整除,則else塊將列印該數字為質數的訊息。

num = 37
print ("Number: ", num)
for x in range(2,num):
   if num%x==0:
      print ("{} is not prime".format(num))
      break
else:
   print ("{} is prime".format(num))

輸出

為num分配不同的值以檢查它是否是質數。

Number: 37
37 is prime
Number: 49
49 is not prime

Python - continue語句

Python中的continue語句將控制權返回到當前迴圈的開頭。遇到時,迴圈開始下一次迭代,而不執行當前迭代中剩餘的語句。

continue語句可用於whilefor迴圈。

語法

continue

流程圖

continue語句的流程圖如下:

loop-continue

continue語句恰好與break相反。它跳過當前迴圈中剩餘的語句並開始下一次迭代。

示例1

現在讓我們來看一個例子,瞭解continue語句如何在Python中工作:

for letter in 'Python': # First Example
   if letter == 'h':
      continue
   print ('Current Letter :', letter)
var = 10 # Second Example
while var > 0:
   var = var -1
   if var == 5:
      continue
   print ('Current variable value :', var)
print ("Good bye!")

執行上述程式碼時,它會產生以下輸出

Current Letter : P
Current Letter : y
Current Letter : t
Current Letter : o
Current Letter : n
Current variable value : 9
Current variable value : 8
Current variable value : 7
Current variable value : 6
Current variable value : 4
Current variable value : 3
Current variable value : 2
Current variable value : 1
Current variable value : 0
Good bye!

示例2:檢查質因數

以下程式碼使用continue來查詢給定數字的質因數。為了找到質因數,我們需要從2開始連續除以給定數字,遞增除數並繼續相同的過程,直到輸入減少到1。

查詢質因數的演算法如下:

  • 接受使用者輸入(n)

  • 將除數(d)設定為2

  • 執行以下操作,直到n>1

  • 檢查給定數字(n)是否能被除數(d)整除。

  • 如果n%d==0

    • a. 列印d作為因數

    • 將n的新值設定為n/d

    • 從4重複

  • 如果不是

  • 將d遞增1

  • 從3重複

以下是用於此目的的Python程式碼:

num = 60
print ("Prime factors for: ", num)
d=2
while num>1:
   if num%d==0:
      print (d)
      num=num/d
      continue
   d=d+1

執行後,此程式碼將產生以下輸出

Prime factors for: 60
2
2
3
5

在上面的程式中為num分配不同的值(例如75),並測試其質因數的結果。

Prime factors for: 75
3
5
5

Python - pass語句

當語法上需要語句但不需要執行任何命令或程式碼時,使用pass語句。

pass語句是空操作;執行時不會發生任何事情。pass語句在程式碼最終將出現但尚未編寫的地方(即在存根中)也很有用。

語法

pass

示例

以下程式碼顯示瞭如何在Python中使用pass語句:

for letter in 'Python':
   if letter == 'h':
      pass
      print ('This is pass block')
   print ('Current Letter :', letter)
print ("Good bye!")

執行上述程式碼時,它會產生以下輸出

Current Letter : P
Current Letter : y
Current Letter : t
This is pass block
Current Letter : h
Current Letter : o
Current Letter : n
Good bye!

Python - 函式

函式是一塊組織良好的、可重用的程式碼,用於執行單個相關的操作。函式為您的應用程式提供了更好的模組化和高度的程式碼重用。

構建處理邏輯的自頂向下方法涉及定義獨立的可重用函式塊。可以透過傳遞所需資料(稱為引數引數)從任何其他函式呼叫函式。被呼叫的函式將其結果返回到呼叫環境。

python functions

Python函式的型別

Python提供以下型別的函式:

  • 內建函式

  • 在內建模組中定義的函式

  • 使用者定義函式

Python的標準庫包含許多內建函式。一些Python的內建函式是print()、int()、len()、sum()等。這些函式始終可用,因為它們在您啟動Python直譯器時就會載入到計算機的記憶體中。

標準庫還捆綁了許多模組。每個模組都定義了一組函式。這些函式並非隨時可用。您需要從各自的模組將其匯入記憶體。

除了內建函式和內建模組中的函式之外,您還可以建立自己的函式。這些函式稱為使用者定義的函式

Python定義函式

您可以定義自定義函式以提供所需的功能。以下是Python中定義函式的一些簡單規則。

  • 函式塊以關鍵字def開頭,後跟函式名和括號(()。

  • 任何輸入引數或引數都應放在這些括號內。您也可以在這些括號內定義引數。

  • 函式的第一條語句可以是可選語句;函式的文件字串或文件字串。

  • 每個函式內的程式碼塊以冒號(:)開頭並縮排。

  • 語句return [expression]退出函式,可以選擇將表示式傳遞迴呼叫方。沒有引數的return語句與return None相同。

語法

def functionname( parameters ):
   "function_docstring"
   function_suite
   return [expression]

預設情況下,引數具有位置行為,您需要按定義的順序通知它們。

定義函式後,您可以透過從另一個函式呼叫它或直接從Python提示符呼叫它來執行它。

示例

以下示例演示如何定義函式 greetings()。括號為空,因此沒有任何引數。

第一行是文件字串。函式塊以 return 語句結束。呼叫此函式時,將列印Hello world 訊息。

def greetings():
   "This is docstring of greetings function"
   print ("Hello World")
   return
greetings()

呼叫函式

定義函式僅為其賦予名稱,指定要包含在函式中的引數並構造程式碼塊。

一旦函式的基本結構確定,就可以透過從另一個函式呼叫它或直接從 Python 提示符呼叫它來執行它。以下是呼叫 printme() 函式的示例:

# Function definition is here
def printme( str ):
   "This prints a passed string into this function"
   print str
   return;
# Now you can call printme function
printme("I'm first call to user defined function!")
printme("Again second call to the same function")

執行上述程式碼時,它會產生以下輸出

I'm first call to user defined function!
Again second call to the same function

按引用傳遞與按值傳遞

Python 的函式呼叫機制與 C 和 C++ 的不同。主要有兩種函式呼叫機制:按值呼叫按引用呼叫

將變數傳遞給函式時,函式對其做了什麼?如果對其變數的任何更改都沒有反映在實際引數中,則它使用按值呼叫機制。另一方面,如果更改被反映出來,則它成為按引用呼叫機制。

Pass By Reference Vs Value

C/C++ 函式被稱為按值呼叫。當呼叫 C/C++ 中的函式時,實際引數的值將複製到表示形式引數的變數中。如果函式修改了形式引數的值,則不會反映傳遞給它的變數。

Python 使用按引用傳遞機制。由於 Python 中的變數是記憶體中物件的標籤或引用,因此用作實際引數和形式引數的變數實際上都引用記憶體中的同一個物件。我們可以透過檢查傳遞變數之前和之後的 id() 來驗證這一事實。

def testfunction(arg):
   print ("ID inside the function:", id(arg))
var="Hello"
print ("ID before passing:", id(var))
testfunction(var)

如果執行上述程式碼,則傳遞之前和函式內部的 id() 相同。

ID before passing: 1996838294128
ID inside the function: 1996838294128

這種行為還取決於傳遞的物件是可變的還是不可變的。Python 數值物件是不可變的。當傳遞數值物件,然後函式更改形式引數的值時,它實際上會在記憶體中建立一個新物件,而原始變數保持不變。

def testfunction(arg):
   print ("ID inside the function:", id(arg))
   arg=arg+1
   print ("new object after increment", arg, id(arg))

var=10
print ("ID before passing:", id(var))
testfunction(var)
print ("value after function call", var)

它將產生以下**輸出**:

ID before passing: 140719550297160
ID inside the function: 140719550297160
new object after increment 11 140719550297192
value after function call 10

現在讓我們將可變物件(例如列表或字典)傳遞給函式。它也是按引用傳遞的,因為傳遞前後 lidt 的 id() 相同。但是,如果我們在函式內部修改列表,它的全域性表示也會反映出更改。

這裡我們傳遞一個列表,新增一個新專案,然後檢視原始列表物件的內容,我們會發現它已經改變了。

def testfunction(arg):
   print ("Inside function:",arg)
   print ("ID inside the function:", id(arg))
   arg=arg.append(100)
   
var=[10, 20, 30, 40]
print ("ID before passing:", id(var))
testfunction(var)
print ("list after function call", var)

它將產生以下**輸出**:

ID before passing: 2716006372544
Inside function: [10, 20, 30, 40]
ID inside the function: 2716006372544
list after function call [10, 20, 30, 40, 100]

函式引數

函式的過程通常取決於呼叫它時提供給它的某些資料。在定義函式時,必須列出收集傳遞給它的資料的變數。括號中的變數稱為形式引數。

呼叫函式時,必須為每個形式引數提供值。這些稱為實際引數。

function arguments

示例

讓我們修改 greetings 函式並新增一個名為 name 的引數。呼叫時傳遞給它的字串在函式內部成為 name 變數。

def greetings(name):
   "This is docstring of greetings function"
   print ("Hello {}".format(name))
   return
   
greetings("Samay")
greetings("Pratima")
greetings("Steven")

它將產生以下**輸出**:

Hello Samay
Hello Pratima
Hello Steven

帶返回值的函式

return 關鍵字作為函式定義中的最後一條語句表示函式塊的結束,程式流程返回到呼叫函式。儘管塊中最後一條語句後的縮排減少也暗示了返回,但使用顯式 return 是一個好習慣。

除了流程控制之外,函式還可以將表示式的值返回給呼叫函式。返回表示式的值可以儲存在一個變數中以供進一步處理。

示例

讓我們定義 add() 函式。它將傳遞給它的兩個值相加並返回總和。返回的值儲存在一個名為 result 的變數中。

def add(x,y):
   z=x+y
   return z

a=10
b=20
result = add(a,b)
print ("a = {} b = {} a+b = {}".format(a, b, result))

它將產生以下輸出:

a = 10 b = 20 a+b = 30

函式引數的型別

根據在定義 Python 函式時引數的宣告方式,它們被分為以下幾類:

  • 位置引數或必填引數

  • 關鍵字引數

  • 預設引數

  • 僅限位置引數

  • 僅限關鍵字引數

  • 任意引數或變長引數

在接下來的幾章中,我們將詳細討論這些函式引數。

引數順序

函式可以具有上述任何型別的引數。但是,引數必須按以下順序宣告:

  • 引數列表以僅限位置引數開頭,後跟斜槓 (/) 符號。

  • 其後是常規位置引數,這些引數可以也可以不作為關鍵字引數呼叫。

  • 然後可能存在一個或多個具有預設值的引數。

  • 接下來是任意位置引數,由以單個星號為字首的變量表示,該變數被視為元組。這是下一個。

  • 如果函式有任何僅限關鍵字引數,請在其名稱開始之前放置一個星號。一些僅限關鍵字引數可能具有預設值。

  • 括號中的最後一個引數使用兩個星號 ** 來接受任意數量的關鍵字引數。

下圖顯示了形式引數的順序:

Order Of Formal Arguments

Python - 預設引數

您可以定義一個函式,為一個或多個形式引數分配預設值。如果未向其傳遞值,Python 將使用此類引數的預設值。如果傳遞任何值,則預設值將被覆蓋。

示例

# Function definition is here
def printinfo( name, age = 35 ):
   "This prints a passed info into this function"
   print ("Name: ", name)
   print ("Age ", age)
   return
# Now you can call printinfo function
printinfo( age=50, name="miki" )
printinfo( name="miki" )

它將產生以下**輸出**:

Name: miki
Age 50
Name: miki
Age 35

在上面的示例中,對函式的第二次呼叫沒有向 age 引數傳遞值,因此使用其預設值 35。

讓我們來看另一個為函式引數賦值預設值的例子。percent() 函式定義如下:

def percent(phy, maths, maxmarks=200):
   val = (phy+maths)*100/maxmarks
   return val

假設每門科目的分數為 100 分,則 maxmarks 引數設定為 200。因此,呼叫 percent() 函式時可以省略第三個引數的值。

phy = 60
maths = 70
result = percent(phy,maths)

但是,如果每門科目的最高分數不是 100,則呼叫 percent() 函式時需要填寫第三個引數。

phy = 40
maths = 46
result = percent(phy,maths, 100)

示例

這是一個完整的示例:

def percent(phy, maths, maxmarks=200):
   val = (phy+maths)*100/maxmarks
   return val

phy = 60
maths = 70
result = percent(phy,maths)
print ("percentage:", result)

phy = 40
maths = 46
result = percent(phy,maths, 100)
print ("percentage:", result)

它將產生以下**輸出**:

percentage: 65.0
percentage: 86.0

Python - 關鍵字引數

關鍵字引數也稱為命名引數。函式定義中的變數用作關鍵字。呼叫函式時,您可以明確提及名稱及其值。

示例

# Function definition is here
def printinfo( name, age ):
   "This prints a passed info into this function"
   print ("Name: ", name)
   print ("Age ", age)
   return

# Now you can call printinfo function
# by positional arguments
printinfo ("Naveen", 29)

# by keyword arguments
printinfo(name="miki", age = 30)

預設情況下,函式按出現順序為引數賦值。在第二次函式呼叫中,我們為特定引數分配了值

它將產生以下**輸出**:

Name: Naveen
Age 29
Name: miki
Age 30

讓我們藉助以下函式定義來更深入地瞭解關鍵字引數:

def division(num, den):
   quotient = num/den
   print ("num:{} den:{} quotient:{}".format(num, den, quotient))

division(10,5)
division(5,10)

由於值是根據位置分配的,因此輸出如下:

num:10 den:5 quotient:2.0
num:5 den:10 quotient:0.5

讓我們不要使用位置引數傳遞值,而是使用關鍵字引數呼叫函式:

division(num=10, den=5)
division(den=5, num=10)

它將產生以下**輸出**:

num:10 den:5 quotient:2.0
num:10 den:5 quotient:2.0

使用關鍵字引數時,不必遵循函式定義中形式引數的順序。

使用關鍵字引數是可選的。您可以使用混合呼叫。您可以不使用關鍵字為某些引數傳遞值,而為其他引數使用關鍵字。

division(10, den=5)

但是,在使用混合呼叫時,位置引數必須位於關鍵字引數之前。

嘗試使用以下語句呼叫 division() 函式。

division(num=5, 10)

由於位置引數不能出現在關鍵字引數之後,因此 Python 會引發以下錯誤訊息:

    division(num=5, 10)
                      ^
SyntaxError: positional argument follows keyword argument

Python - 僅關鍵字引數

您可以使用形式引數列表中的變數作為關鍵字來傳遞值。使用關鍵字引數是可選的。但是,您可以強制函式僅透過關鍵字提供引數。您應該在僅限關鍵字引數列表之前放置一個星號 (*)。

假設我們有一個具有三個引數的函式,其中我們希望第二個和第三個引數為僅限關鍵字引數。為此,請在第一個引數之後放置 *。

內建的 print() 函式是僅限關鍵字引數的一個示例。您可以將要列印的表示式列表放在括號中。預設情況下,列印的值用空格分隔。您可以使用 sep 引數指定任何其他分隔符。

print ("Hello", "World", sep="-")

它將列印:

Hello-World

sep 引數是僅限關鍵字的。嘗試將其用作非關鍵字引數。

print ("Hello", "World", "-")

您將獲得不同的輸出——並非預期的那樣。

Hello World -

示例

在以下具有兩個引數 amt 和 rate 的使用者定義函式 intr() 中。為了使rate 引數僅限關鍵字,請在其前面放置 "*"。

def intr(amt,*, rate):
   val = amt*rate/100
   return val

要呼叫此函式,必須透過關鍵字傳遞rate 的值。

interest = intr(1000, rate=10)

但是,如果您嘗試使用預設位置呼叫函式的方式,則會收到錯誤。

interest = intr(1000, 10)
               ^^^^^^^^^^^^^^
TypeError: intr() takes 1 positional argument but 2 were given

Python - 位置引數

在定義函式時括號中宣告的變數列表是形式引數。函式可以定義任意數量的形式引數。

呼叫函式時:

  • 所有引數都是必需的

  • 實際引數的數量必須等於形式引數的數量。

  • 形式引數是位置引數。它們按定義順序獲取值。

  • 引數的型別必須匹配。

  • 形式引數和實際引數的名稱不必相同。

示例

def add(x,y):
   z=x+y
   print ("x={} y={} x+y={}".format(x,y,z))

a=10
b=20
add(a,b)

它將產生以下**輸出**:

x=10 y=20 x+y=30

這裡,add() 函式有兩個形式引數,兩者都是數值型。當整數 10 和 20 傳遞給它時。變數 a 獲取 10,b 獲取 20,按宣告順序。add() 函式顯示總和。

當引數數量不匹配時,Python 也會引發錯誤。只給出一個引數並檢查結果。

add(b)
TypeError: add() missing 1 required positional argument: 'y'

傳遞超過形式引數數量的引數並檢查結果:

add(10, 20, 30)
TypeError: add() takes 2 positional arguments but 3 were given

相應實際引數和形式引數的資料型別必須匹配。將 a 更改為字串值並檢視結果。

a="Hello"
b=20
add(a,b)

它將產生以下**輸出**:

z=x+y
     ~^~
TypeError: can only concatenate str (not "int") to str

Python - 僅位置引數

可以定義一個函式,其中一個或多個引數不能接受其關鍵字值。此類引數可以稱為僅限位置引數。

Python 的內建 input() 函式是僅限位置引數的一個示例。input 函式的語法是:

input(prompt = "")

Prompt 是一個解釋性字串,供使用者參考。例如:

name = input("enter your name ")

但是,您不能在括號內使用 prompt 關鍵字。

   name = input (prompt="Enter your name ")
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: input() takes no keyword arguments

要使引數僅限位置,請使用 "/" 符號。此符號之前的全部引數將被視為僅限位置引數。

示例

我們透過在 `intr()` 函式末尾新增“/”,將其兩個引數都設定為僅位置引數。

def intr(amt, rate, /):
   val = amt*rate/100
   return val

如果嘗試將引數用作關鍵字引數,Python 會引發以下錯誤訊息:

   interest = intr(amt=1000, rate=10)
              ^^^^^^^^^^^^^^^^^^^^^^^
TypeError: intr() got some positional-only arguments passed as keyword arguments: 'amt, rate'

函式可以這樣定義:它既有一些僅關鍵字引數,也有一些僅位置引數。

def myfunction(x, /, y, *, z):
   print (x, y, z)

在這個函式中,x 是必需的僅位置引數,y 是常規的位置引數(如果需要,可以用作關鍵字引數),而 z 是僅關鍵字引數。

以下函式呼叫是有效的:

myfunction(10, y=20, z=30)
myfunction(10, 20, z=30)

但是,這些呼叫會引發錯誤:

   myfunction(x=10, y=20, z=30)
TypeError: myfunction() got some positional-only arguments passed as keyword arguments: 'x'

   myfunction(10, 20, 30)
TypeError: myfunction() takes 2 positional arguments but 3 were given

Python - 可變引數

您可能希望定義一個能夠接受任意數量或可變數量引數的函式。此外,任意數量的引數可能是位置引數或關鍵字引數。

  • 用單個星號 * 字首的引數表示任意數量的位置引數。

  • 用兩個星號 ** 字首的引數表示任意數量的關鍵字引數。

示例

下面是一個任意或可變長度位置引數的示例:

# sum of numbers
def add(*args):
   s=0
   for x in args:
      s=s+x
   return s
result = add(10,20,30,40)
print (result)

result = add(1,2,3)
print (result)

用“*”字首的 args 變數儲存傳遞給它的所有值。這裡,args 變成一個元組。我們可以迴圈遍歷它的專案來新增數字。

它將產生以下**輸出**:

100
6

也可以在可變數量的值序列之前,擁有一個函式,該函式具有一些必需的引數。

示例

下面的示例包含 avg() 函式。假設學生可以參加任意數量的考試。第一次考試是必須的。他可以參加儘可能多的考試來提高他的分數。該函式計算第一次考試的平均成績和他其餘考試中的最高分數。

該函式有兩個引數,第一個是必需引數,第二個用於儲存任意數量的值。

#avg of first test and best of following tests
def avg(first, *rest):
   second=max(rest)
   return (first+second)/2
   
result=avg(40,30,50,25)
print (result)

對 avg() 函式的以下呼叫將第一個值傳遞給必需引數 first,其餘值傳遞給名為 rest 的元組。然後我們找到最大值並用它來計算平均值。

它將產生以下**輸出**:

45.0

如果引數列表中的變數前面有兩個星號,則函式可以接受任意數量的關鍵字引數。該變數將成為關鍵字:值對的字典。

示例

以下程式碼是具有任意關鍵字引數的函式的示例。addr() 函式有一個引數 **kwargs,它能夠接受任意數量的地址元素,例如姓名、城市、電話號碼、郵政編碼等。在函式中,使用 items() 方法遍歷 kw:value 對的 kwargs 字典。

def addr(**kwargs):
   for k,v in kwargs.items():
      print ("{}:{}".format(k,v))

print ("pass two keyword args")
addr(Name="John", City="Mumbai")
print ("pass four keyword args")

# pass four keyword args
addr(Name="Raam", City="Mumbai", ph_no="9123134567", PIN="400001")

它將產生以下**輸出**:

pass two keyword args
Name:John
City:Mumbai
pass four keyword args
Name:Raam
City:Mumbai
ph_no:9123134567
PIN:400001

如果函式使用混合型別的引數,則任意關鍵字引數應該在位置引數、關鍵字引數和任意位置引數之後出現在引數列表中。

示例

想象一下,科學和數學是必修科目,此外學生可以選擇任意數量的選修科目。

以下程式碼定義了一個 percent() 函式,其中科學和數學的成績儲存在必需引數中,而可變數量的選修科目的成績儲存在 **可選引數中。

def percent(math, sci, **optional):
   print ("maths:", math)
   print ("sci:", sci)
   s=math+sci
   for k,v in optional.items():
      print ("{}:{}".format(k,v))
      s=s+v
   return s/(len(optional)+2)

result=percent(math=80, sci=75, Eng=70, Hist=65, Geo=72)
print ("percentage:", result)

它將產生以下**輸出**:

maths: 80
sci: 75
Eng:70
Hist:65
Geo:72
percentage: 72.4

Python - 變數作用域

Python 中的變數是計算機記憶體中物件的符號名稱。Python 基於名稱空間的概念來定義各種識別符號(如函式、變數等)的上下文。名稱空間是當前上下文中定義的符號名稱的集合。

Python 提供以下型別的名稱空間:

  • 內建名稱空間包含內建函式和內建異常。它們在 Python 直譯器載入到記憶體後立即載入,並一直保留到直譯器執行結束。

  • 全域性名稱空間包含主程式中定義的任何名稱。這些名稱保留在記憶體中,直到程式執行結束。

  • 區域性名稱空間包含函式內部定義的名稱。它們在函式執行期間可用。

這些名稱空間彼此巢狀。下圖顯示了名稱空間之間的關係。

Types Of Namespace

某個變數的生命週期僅限於其定義所在的名稱空間。因此,無法從任何外部名稱空間訪問內部名稱空間中存在的變數。

globals() 函式

Python 的標準庫包含一個內建函式 globals()。它返回當前在全域性名稱空間中可用的符號的字典。

直接從 Python 提示符執行 globals() 函式。

>>> globals()
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>}

可以看出,包含所有內建函式和內建異常定義的 builtins 模組已載入。

儲存以下包含少量變數和一個函式(其中包含更多變數)的程式碼。

name = 'TutorialsPoint'
marks = 50
result = True
def myfunction():
   a = 10
   b = 20
   return a+b
   
print (globals())

從這個指令碼內部呼叫 globals() 返回以下字典物件:

{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x00000263E7255250>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'C:\\Users\\user\\examples\\main.py', '__cached__': None, 'name': 'TutorialsPoint', 'marks': 50, 'result': True, 'myfunction': <function myfunction at 0x00000263E72004A0>}

全域性名稱空間現在包含程式中的變數及其值以及其中的函式物件(而不是函式中的變數)。

locals() 函式

Python 的標準庫包含一個內建函式 locals()。它返回函式名稱空間中當前可用符號的字典。

修改上述指令碼,以從函式內部列印全域性和區域性名稱空間的字典。

name = 'TutorialsPoint'
marks = 50
result = True
def myfunction():
   a = 10
   b = 20
   c = a+b
   print ("globals():", globals())
   print ("locals():", locals())
   return c
myfunction()

輸出顯示 locals() 返回一個字典,其中包含函式中當前可用的變數及其值。

globals(): {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x00000169AE265250>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'C:\\Users\\mlath\\examples\\main.py', '__cached__': None, 'name': 'TutorialsPoint', 'marks': 50, 'result': True, 'myfunction': <function myfunction at 0x00000169AE2104A0>}
locals(): {'a': 10, 'b': 20, 'c': 30}

由於 globals() 和 locals() 函式都返回字典,因此您可以使用字典的 get() 方法或索引運算子訪問相應名稱空間中變數的值。

print (globals()['name']) #displays TutorialsPoint
   print (locals().get('a')) #displays 10

名稱空間衝突

如果全域性和區域性作用域中都存在同名變數,則 Python 直譯器優先考慮區域性名稱空間中的變數。

marks = 50 # this is a global variable
def myfunction():
   marks = 70 # this is a local variable
   print (marks)
   
myfunction()
print (marks) # prints global value

它將產生以下**輸出**:

70
50

如果嘗試從函式內部操作全域性變數的值,Python 會引發 UnboundLocalError

marks = 50 # this is a global variable
def myfunction():
   marks = marks + 20
   print (marks)

myfunction()
print (marks) # prints global value

它將產生以下**輸出**:

   marks = marks + 20
           ^^^^^
UnboundLocalError: cannot access local variable 'marks' where it is not associated with a value

要修改全域性變數,您可以使用字典語法更新它,或者在修改之前使用 global 關鍵字引用它。

var1 = 50 # this is a global variable
var2 = 60 # this is a global variable
def myfunction():
   "Change values of global variables"
   globals()['var1'] = globals()['var1']+10
   global var2
   var2 = var2 + 20

myfunction()
print ("var1:",var1, "var2:",var2) #shows global variables with changed values

它將產生以下**輸出**:

var1: 60 var2: 80

最後,如果嘗試在全域性作用域中訪問區域性變數,Python 會引發 NameError,因為區域性作用域中的變數無法在區域性作用域之外訪問。

var1 = 50 # this is a global variable
var2 = 60 # this is a global variable
def myfunction(x, y):
   total = x+y
   print ("Total is a local variable: ", total)

myfunction(var1, var2)
print (total) # This gives NameError

它將產生以下輸出:

Total is a local variable: 110
Traceback (most recent call last):
   File "C:\Users\user\examples\main.py", line 9, in <module>
   print (total) # This gives NameError
          ^^^^^
NameError: name 'total' is not defined

Python - 函式註解

Python 的函式註解功能使您可以新增有關函式定義中宣告的引數以及返回資料型別的附加解釋性元資料。

雖然您可以使用 Python 的文件字串功能來記錄函式,但如果對函式的原型進行了某些更改,它可能會過時。因此,PEP 3107 引入了註解功能。

Python 直譯器在執行函式時不會考慮註解。它們主要用於 Python IDE,為程式設計師提供詳細的文件。

註解是新增到引數或返回資料型別的任何有效的 Python 表示式。註解最簡單的例子是規定引數的資料型別。註解是在引數前面加上冒號後作為表示式提到的。

def myfunction(a: int, b: int):
   c = a+b
   return c

請記住,Python 是一種動態型別語言,不會在執行時強制執行任何型別檢查。因此,使用資料型別作為註解在呼叫函式時沒有任何效果。即使給出非整數引數,Python 也不會檢測到任何錯誤。

def myfunction(a: int, b: int):
   c = a+b
   return c
   
print (myfunction(10,20))
print (myfunction("Hello ", "Python"))

它將產生以下**輸出**:

30
Hello Python

註解在執行時被忽略,但對於 IDE 和靜態型別檢查器庫(如 mypy)很有用。

您也可以為返回資料型別添加註解。在括號之後和冒號符號之前,加上箭頭 (->),然後加上註解。例如:

def myfunction(a: int, b: int) -> int:
   c = a+b
   return c

由於在執行時忽略使用資料型別作為註解,因此您可以使用任何充當引數元資料的表示式。因此,函式可以具有任何任意表達式作為註解,如下例所示:

def total(x : 'marks in Physics', y: 'marks in chemistry'):
   return x+y

如果要同時指定預設引數和註解,則需要將預設引數放在註解表示式之後。預設引數必須出現在引數列表中必需引數之後。

def myfunction(a: "physics", b:"Maths" = 20) -> int:
   c = a+b
   return c
print (myfunction(10))

Python 中的函式也是一個物件,它的一個屬性是 __annotations__。您可以使用 dir() 函式進行檢查。

print (dir(myfunction))

這將列印 myfunction 物件的列表,其中包含 __annotations__ 作為其中一個屬性。

['__annotations__', '__builtins__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__getstate__', '__globals__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']

__annotations__ 屬性本身是一個字典,其中引數是鍵,註解是值。

def myfunction(a: "physics", b:"Maths" = 20) -> int:
   c = a+b
   return c
print (myfunction.__annotations__)

它將產生以下**輸出**:

{'a': 'physics', 'b': 'Maths', 'return': <class 'int'>}

函式可以具有任意位置引數和/或任意關鍵字引數。也可以為它們提供註解。

def myfunction(*args: "arbitrary args", **kwargs: "arbitrary keyword args") -> int:
   pass
print (myfunction.__annotations__)

它將產生以下**輸出**:

{'args': 'arbitrary args', 'kwargs': 'arbitrary keyword args', 'return': <class 'int'>}

如果您需要為函式引數提供多個註解表示式,請以字典物件的格式在引數本身前面提供它。

def division(num: dict(type=float, msg='numerator'), den: dict(type=float, msg='denominator')) -> float:
   return num/den
print (division.__annotations__)

它將產生以下**輸出**:

{'num': {'type': <class 'float'>, 'msg': 'numerator'}, 'den': {'type': <class 'float'>, 'msg': 'denominator'}, 'return': <class 'float'>}

Python - 模組

函式是一塊組織良好的、可重用的程式碼,用於執行單個相關的操作。函式為您的應用程式提供了更好的模組化和高度的程式碼重用。

Python 中的模組概念進一步增強了模組化。您可以將多個相關的函式一起定義並載入所需的函式。模組是一個檔案,其中包含函式、類、變數、常量或任何其他 Python 物件的定義。此檔案的內容可以提供給任何其他程式。Python 有一個 import 關鍵字用於此目的。

示例

import math
print ("Square root of 100:", math.sqrt(100))

它將產生以下**輸出**:

Square root of 100: 10.0

內建模組

Python 的標準庫捆綁了大量的模組。它們被稱為內建模組。大多數這些內建模組都是用 C 編寫的(因為 Python 的參考實現是用 C 編寫的),並預編譯到庫中。這些模組打包了有用的功能,例如特定於系統的作業系統管理、磁碟 I/O、網路等。

這是一個精選的內建模組列表:

序號 名稱和簡要說明

1

os

此模組為許多作業系統函式提供了一個統一的介面。

2

string

此模組包含許多用於字串處理的函式

3

re

此模組提供了一套強大的正則表示式功能。正則表示式 (RegEx) 允許對字串中的模式進行強大的字串搜尋和匹配

4

math

此模組實現了許多浮點數的數學運算。這些函式通常是圍繞平臺 C 庫函式的薄包裝器。

5

cmath

此模組包含許多複數的數學運算。

6

datetime

此模組提供處理日期和一天中的時間的函式。它包裝了 C 執行時庫。

7

gc

此模組提供與內建垃圾收集器的介面。

8

asyncio

此模組定義了非同步處理所需的功能

9

Collections

此模組提供高階容器資料型別。

10

Functools

此模組具有高階函式和對可呼叫物件的運算。在函數語言程式設計中很有用

11

operator

對應於標準運算子的函式。

12

pickle

將 Python 物件轉換為位元組流並返回。

13

socket

低階網路介面。

14

sqlite3

使用 SQLite 3.x 的 DB-API 2.0 實現。

15

statistics

數學統計函式

16

typing

對型別提示的支援

17

venv

建立虛擬環境。

18

json

編碼和解碼 JSON 格式。

19

wsgiref

WSGI 實用程式和參考實現。

20

unittest

Python 的單元測試框架。

21

random

生成偽隨機數

使用者定義模組

任何副檔名為 .py 且包含 Python 程式碼的文字檔案基本上都是一個模組。它可以包含一個或多個函式、變數、常量的定義,以及類的定義。可以透過 import 語句將模組中的任何 Python 物件提供給直譯器會話或另一個 Python 指令碼。模組還可以包含可執行的程式碼。

建立模組

建立模組只不過是使用任何編輯器儲存 Python 程式碼。讓我們將以下程式碼儲存為 **mymodule.py**

def SayHello(name):
   print ("Hi {}! How are you?".format(name))
   return

您現在可以在當前 Python 終端匯入 mymodule。

>>> import mymodule
>>> mymodule.SayHello("Harish")
Hi Harish! How are you?

您也可以在一個 Python 指令碼中匯入另一個模組。將以下程式碼儲存為 example.py

import mymodule
mymodule.SayHello("Harish")

從命令終端執行此指令碼

C:\Users\user\examples> python example.py
Hi Harish! How are you?

import 語句

在 Python 中,提供 **import** 關鍵字用於從一個模組載入 Python 物件。該物件可以是函式、類、變數等。如果模組包含多個定義,則所有定義都將載入到名稱空間中。

讓我們將包含三個函式的以下程式碼儲存為 **mymodule.py**。

def sum(x,y):
   return x+y

def average(x,y):
   return (x+y)/2

def power(x,y):
   return x**y

**import mymodule** 語句將此模組中的所有函式載入到當前名稱空間中。匯入模組中的每個函式都是此模組物件的屬性。

>>> dir(mymodule)
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'average', 'power', 'sum']

要呼叫任何函式,請使用模組物件的引用。例如,mymodule.sum()。

import mymodule
print ("sum:",mymodule.sum(10,20))
print ("average:",mymodule.average(10,20))
print ("power:",mymodule.power(10, 2))

它將產生以下**輸出**:

sum:30
average:15.0
power:100

from ... import 語句

import 語句會將模組的所有資源載入到當前名稱空間中。可以使用此語法從模組匯入特定物件。例如:

在 **mymodule** 中的三個函式中,只有兩個匯入到以下可執行指令碼 **example.py** 中

from mymodule import sum, average
print ("sum:",sum(10,20))
print ("average:",average(10,20))

它將產生以下輸出:

sum: 30
average: 15.0

請注意,無需在函式名前加模組名稱來呼叫函式。

from...import * 語句

還可以使用以下 import 語句將模組中的所有名稱匯入到當前名稱空間中:

from modname import *

這提供了一種簡單的方法,可以將模組中的所有項匯入到當前名稱空間中;但是,應謹慎使用此語句。

import ... as 語句

您可以為匯入的模組分配一個別名。

from modulename as alias

呼叫函式時,應在函式名前加上 **別名**。

請看下面的**示例**:

import mymodule as x
print ("sum:",x.sum(10,20))
print ("average:", x.average(10,20))
print ("power:", x.power(10, 2))

模組屬性

在 Python 中,模組是模組類的物件,因此它具有屬性。

以下是模組屬性:

  • __file__ 返回模組的物理名稱。

  • __package__ 返回模組所屬的包。

  • __doc__ 返回模組頂部的文件字串(如果存在)。

  • __dict__ 返回模組的整個作用域。

  • __name__ 返回模組的名稱。

示例

假設以下程式碼儲存為 **mymodule.py**

"The docstring of mymodule"
def sum(x,y):
   return x+y

def average(x,y):
   return (x+y)/2
   
def power(x,y):
   return x**y

讓我們透過在以下指令碼中匯入它來檢查 mymodule 的屬性:

import mymodule

print ("__file__ attribute:", mymodule.__file__)
print ("__doc__ attribute:", mymodule.__doc__)
print ("__name__ attribute:", mymodule.__name__)

它將產生以下**輸出**:

__file__ attribute: C:\Users\mlath\examples\mymodule.py
__doc__ attribute: The docstring of mymodule
__name__ attribute: mymodule

__name__ 屬性

Python 模組的 __name__ 屬性具有重要意義。讓我們更詳細地探討一下。

在互動式 shell 中,__name__ 屬性返回 '__main__'。

>>> __name__
'__main__'

如果在直譯器會話中匯入任何模組,它將返回該模組的名稱作為該模組的 __name__ 屬性。

>>> import math
>>> math.__name__
'math'

從 Python 指令碼內部,__name__ 屬性返回 '__main__'。

#example.py
print ("__name__ attribute within a script:", __name__)

在命令終端執行此命令:

__name__ attribute within a script: __main__

此屬性允許 Python 指令碼用作可執行檔案或模組。與 C++、Java、C# 等不同,在 Python 中,沒有 main() 函式的概念。副檔名為 .py 的 Python 程式指令碼可以包含函式定義以及可執行語句。

儲存 **mymodule.py**,程式碼如下:

"The docstring of mymodule"
def sum(x,y):
   return x+y
   
print ("sum:",sum(10,20))

您可以看到 sum() 函式在其定義的同一指令碼中被呼叫。

C:\Users\user\examples> python mymodule.py
sum: 30

現在讓我們在另一個指令碼 **example.py** 中匯入此函式。

import mymodule
print ("sum:",mymodule.sum(10,20))

它將產生以下**輸出**:

C:\Users\user\examples> python example.py
sum: 30
sum: 30

輸出 "sum:30" 出現兩次。一次是在匯入 mymodule 模組時。匯入模組中的可執行語句也會執行。第二個輸出來自呼叫指令碼,即 **example.py** 程式。

我們想要的結果是,當匯入模組時,只匯入函式,而不執行其可執行語句。這可以透過檢查 __name__ 的值來實現。如果它是 __main__,則表示它正在執行而不是被匯入。有條件地包含可執行語句,例如函式呼叫。

在 **mymodule.py** 中新增 **if** 語句,如下所示:

"The docstring of mymodule"
def sum(x,y):
   return x+y

if __name__ == "__main__":
   print ("sum:",sum(10,20))

現在,如果執行 **example.py** 程式,您會發現 sum:30 輸出只出現一次。

C:\Users\user\examples> python example.py
sum: 30

reload() 函式

有時您可能需要重新載入模組,尤其是在使用 Python 的互動式直譯器會話時。

假設我們有一個包含以下函式的測試模組 (test.py):

def SayHello(name):
   print ("Hi {}! How are you?".format(name))
   return

我們可以從 Python 提示符匯入模組並呼叫其函式,如下所示:

>>> import test
>>> test.SayHello("Deepak")
Hi Deepak! How are you?

但是,假設您需要修改 SayHello() 函式,例如:

def SayHello(name, course):
   print ("Hi {}! How are you?".format(name))
   print ("Welcome to {} Tutorial by TutorialsPoint".format(course))
   return

即使您編輯 test.py 檔案並儲存它,載入到記憶體中的函式也不會更新。您需要使用 imp 模組中的 reload() 函式重新載入它。

>>> import imp
>>> imp.reload(test)
>>> test.SayHello("Deepak", "Python")
Hi Deepak! How are you?
Welcome to Python Tutorial by TutorialsPoint

Python - 內建函式

截至 Python 3.11.2 版本,Python 中有 71 個內建函式。以下是內建函式的列表:

序號 函式和說明

1

abs()

返回數字的絕對值

2

aiter()

為非同步可迭代物件返回非同步迭代器

3

all()

當可迭代物件中的所有元素都為真時返回真

4

anext()

返回給定非同步迭代器的下一個專案

5

any()

檢查可迭代物件的任何元素是否為真

6

ascii()

返回包含可打印表示形式的字串

7

bin()

將整數轉換為二進位制字串

8

bool()

將值轉換為布林值

9

breakpoint()

此函式會在呼叫站點將您放入偵錯程式中,並呼叫 sys.breakpointhook()

10

bytearray()

返回給定位元組大小的陣列

11

bytes()

返回不可變的 bytes 物件

12

callable()

檢查物件是否可呼叫

13

chr()

從整數返回字元(字串)

14

classmethod()

為給定函式返回類方法

15

compile()

返回程式碼物件

16

complex()

建立一個複數

17

delattr()

從物件中刪除屬性

18

dict()

建立一個字典

19

dir()

嘗試返回物件的屬性

20

divmod()

返回商和餘數的元組

21

enumerate()

返回一個列舉物件

22

eval()

在程式中執行程式碼

23

exec()

執行動態建立的程式

24

filter()

從為真的元素構造迭代器

25

float()

從數字、字串返回浮點數

26

format()

返回值的格式化表示形式

27

frozenset()

返回不可變的 frozenset 物件

28

getattr()

返回物件的命名屬性的值

29

globals()

返回當前全域性符號表的字典

30

hasattr()

返回物件是否具有命名屬性

31

hash()

返回物件的雜湊值

32

help()

呼叫內建幫助系統

33

hex()

將整數轉換為十六進位制

34

id()

返回物件的標識

35

input()

讀取並返回一行字串

36

int()

從數字或字串返回整數

37

isinstance()

檢查物件是否是類的例項

38

issubclass()

檢查類是否是另一個類的子類

39

iter()

返回迭代器

40

len()

返回物件的長度

41

list()

在 Python 中建立一個列表

42

locals()

返回當前區域性符號表的字典

43

map()

應用函式並返回列表

44

max()

返回最大的專案

45

memoryview()

返回引數的記憶體檢視

46

min()

返回最小值

47

next()

從迭代器檢索下一個專案

48

object()

建立一個無特徵的物件

49

oct()

返回整數的八進位制表示形式

50

open()

返回檔案物件

51

ord()

返回 Unicode 字元的整數

52

pow()

返回數字的冪

53

print()

列印給定的物件

54

property()

返回屬性屬性

55

range()

返回整數序列

56

repr()

返回物件的打印表示形式

57

reversed()

返回序列的反向迭代器

58

round()

將數字四捨五入到指定的十進位制數

59

set()

構造並返回一個集合

60

setattr()

設定物件的屬性的值

61

slice()

返回切片物件

62

sorted()

從給定的可迭代物件返回排序列表

63

staticmethod()

將方法轉換為靜態方法

64

str()

返回物件的字串版本

65

sum()

新增可迭代物件的專案

66

super()

返回基類的代理物件

67

tuple()

返回一個元組

68

type()

返回物件的型別

69

vars()

返回 __dict__ 屬性

70

zip()

返回元組的迭代器

71

__import__()

import 語句呼叫的函式

內建數學函式

以下數學函式內置於 Python 直譯器中,因此您無需從任何模組匯入它們。

序號 函式和說明

1

abs() 函式

abs() 函式返回 x 的絕對值,即 x 和零之間的正距離。

2

max() 函式

max() 函式返回其引數中最大的一個,或可迭代物件(列表或元組)中的最大數字。

3

min() 函式

min() 函式返回其引數中最小的一個,即最接近負無窮大的值,或可迭代物件(列表或元組)中的最小數字。

4

pow() 函式

pow() 函式返回 x 的 y 次冪。它等效於 x**y。該函式具有第三個可選引數 mod。如果給出,它將返回 (x**y) % mod 值。

5

round() 函式

round() 是 Python 的內建函式。它返回 x 四捨五入到小數點後 n 位的結果。

6

sum() 函式

sum() 函式返回任何可迭代物件(列表或元組)中所有數字項的總和。可選的 start 引數預設為 0。如果給出 start 引數,則列表中的數字將新增到 start 值。

Python - 字串

在 Python 中,字串是不可變的 Unicode 字元序列。根據 Unicode 標準,每個字元都有一個唯一的數值。但是,整個序列本身沒有任何數值,即使所有字元都是數字。為了區分字串與數字和其他識別符號,字元序列在其字面表示中包含在單引號、雙引號或三引號中。因此,1234 是一個數字(整數),而 '1234' 是一個字串。

只要字元序列相同,單引號、雙引號或三引號都沒有關係。因此,以下字串表示是等效的。

>>> 'Welcome To TutorialsPoint'
'Welcome To TutorialsPoint'
>>> "Welcome To TutorialsPoint"
'Welcome To TutorialsPoint'
>>> '''Welcome To TutorialsPoint'''
'Welcome To TutorialsPoint'
>>> """Welcome To TutorialsPoint"""
'Welcome To TutorialsPoint'

從上面的語句可以看出,Python 內部將字串儲存為用單引號括起來的。

Python 中的字串是 str 類的物件。可以使用 type() 函式驗證。

var = "Welcome To TutorialsPoint"
print (type(var))

它將產生以下**輸出**:

<class 'str'>

如果要將一些用雙引號括起來的文字嵌入到字串中,則字串本身應該用單引號括起來。要嵌入用單引號括起來的文字,字串應該用雙引號括起來。

var = 'Welcome to "Python Tutorial" from TutorialsPoint'
print ("var:", var)

var = "Welcome to 'Python Tutorial' from TutorialsPoint"
print ("var:", var)

要使用三引號形成字串,可以使用三個單引號或三個雙引號——這兩個版本相似。

var = '''Welcome to TutorialsPoint'''
print ("var:", var)

var = """Welcome to TutorialsPoint"""
print ("var:", var)

三引號字串可用於構成多行字串。

var = '''
Welcome To
Python Tutorial
from TutorialsPoint
'''
print ("var:", var)

它將產生以下**輸出**:

var:
Welcome To
Python Tutorial
from TutorialsPoint

字串是一種非數值資料型別。顯然,我們不能將算術運算子與字串運算元一起使用。在這種情況下,Python 會引發 TypeError。

>>> "Hello"-"World"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for -: 'str' and 'str'

Python 字串切片

在 Python 中,字串是有序的 Unicode 字元序列。字串中的每個字元在序列中都有一個唯一的索引。索引從 0 開始。字串中的第一個字元的索引為 0。索引向字串結尾遞增。

如果字串變數宣告為 var="HELLO PYTHON",則字串中每個字元的索引如下:

string_variable

Python 允許您透過其索引訪問字串中的任何單個字元。在這種情況下,0 是下界,11 是字串的上界。因此,var[0] 返回 H,var[6] 返回 P。如果方括號中的索引超過上界,Python 將引發 IndexError。

>>> var="HELLO PYTHON"
>>> var[0]
'H'
>>> var[7]
'Y'
>>> var[11]
'N'
>>> var[12]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: string index out of range

Python 序列型別(因此也是字串物件)的獨特功能之一是它也具有負索引方案。在上面的示例中,使用了正索引方案,其中索引從左到右遞增。在負索引的情況下,末尾的字元索引為 -1,索引從右到左遞減,因此第一個字元 H 的索引為 -12。

negative indexing

讓我們使用負索引來獲取 N、Y 和 H 字元。

>>> var[-1]
'N'
>>> var[-5]
'Y'
>>> var[-12]
'H'
>>> var[-13]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: string index out of range

再次強調,如果索引超出範圍,則會遇到 IndexError。

因此,我們可以使用正索引或負索引從字串中檢索字元。

>>> var[0], var[-12]
('H', 'H')
>>> var[7], var[-5]
('Y', 'Y')
>>> var[11], var[-1]
('N', 'N')

在 Python 中,字串是不可變物件。如果物件一旦儲存在某個記憶體位置後就不能就地修改,則該物件是不可變的。您可以藉助索引檢索字串中的任何字元,但不能將其替換為另一個字元。在我們的示例中,字元 Y 在 HELLO PYTHON 中的索引為 7。嘗試將 Y 替換為 y 並看看會發生什麼。

var="HELLO PYTHON"
var[7]="y"
print (var)

它將產生以下**輸出**:

Traceback (most recent call last):
 File "C:\Users\users\example.py", line 2, in <module>
  var[7]="y"
  ~~~^^^
TypeError: 'str' object does not support item assignment

出現 TypeError 是因為字串是不可變的。

Python 將 ":" 定義為字串切片運算子。它從原始字串返回子字串。其一般用法為:

substr=var[x:y]

":" 運算子需要兩個整數運算元(這兩個運算元都可以省略,我們將在後續示例中看到)。第一個運算元 x 是所需切片的第一個字元的索引。第二個運算元 y 是所需字串中最後一個字元下一個字元的索引。因此,var[x:y] 從原始字串中分離從第 x 個位置到第 (y-1) 個位置的字元。

var="HELLO PYTHON"

print ("var:",var)
print ("var[3:8]:", var[3:8])

它將產生以下**輸出**:

var: HELLO PYTHON
var[3:8]: LO PY

負索引也可以用於切片。

var="HELLO PYTHON"
print ("var:",var)
print ("var[3:8]:", var[3:8])
print ("var[-9:-4]:", var[-9:-4])

它將產生以下**輸出**:

var: HELLO PYTHON
var[3:8]: LO PY
var[-9:-4]: LO PY

Python 的切片運算子的兩個運算元都是可選的。第一個運算元預設為零,這意味著如果我們不提供第一個運算元,則切片從索引為 0 的字元開始,即第一個字元。它將最左邊的子字串切片到“y-1”個字元。

var="HELLO PYTHON"
print ("var:",var)
print ("var[0:5]:", var[0:5])
print ("var[:5]:", var[:5])

它將產生以下**輸出**:

var: HELLO PYTHON
var[0:5]: HELLO
var[:5]: HELLO

同樣,y 運算元也是可選的。預設情況下,它是“-1”,這意味著字串將從第 x 個位置切片到字串的末尾。

var="HELLO PYTHON"
print ("var:",var)
print ("var[6:12]:", var[6:12])
print ("var[6:]:", var[6:])

它將產生以下輸出:

var: HELLO PYTHON
var[6:12]: PYTHON
var[6:]: PYTHON

自然地,如果兩個運算元都沒有使用,則切片將等於原始字串。這是因為“x”為 0,“y”預設為最後一個索引+1(或 -1)。

var="HELLO PYTHON"
print ("var:",var)
print ("var[0:12]:", var[0:12])
print ("var[:]:", var[:])

它將產生以下**輸出**:

var: HELLO PYTHON
var[0:12]: HELLO PYTHON
var[:]: HELLO PYTHON

為了獲得原始字串的子字串,左運算元必須小於右運算元。如果左運算元較大,Python 不會引發任何錯誤,而是返回空字串。

var="HELLO PYTHON"
print ("var:",var)
print ("var[-1:7]:", var[-1:7])
print ("var[7:0]:", var[7:0])

它將產生以下**輸出**:

var: HELLO PYTHON
var[-1:7]:
var[7:0]:

切片返回一個新字串。您可以很好地對切片字串執行字串操作,如連線或切片。

var="HELLO PYTHON"

print ("var:",var)
print ("var[:6][:2]:", var[:6][:2])

var1=var[:6]
print ("slice:", var1)
print ("var1[:2]:", var1[:2])

它將產生以下**輸出**:

var: HELLO PYTHON
var[:6][:2]: HE
slice: HELLO
var1[:2]: HE

Python - 修改字串

在 Python 中,字串(str 類的物件)是不可變型別的。不可變物件是在記憶體中建立的物件,不能就地修改。因此,與列表不同,序列中的任何字元都不能被覆蓋,我們也不能向其中插入或追加字元,除非我們使用返回新字串物件的某些字串方法。

但是,我們可以使用以下技巧之一作為解決方法來修改字串。

將字串轉換為列表

由於字串和列表物件都是序列,因此它們是可相互轉換的。因此,如果我們將字串物件轉換為列表,透過 insert()、append() 或 remove() 方法修改列表,並將列表轉換回字串,則可以獲得修改後的版本。

我們有一個字串變數 s1,其值為 WORD。使用 list() 內建函式,讓我們將其轉換為 l1 列表物件,並在索引 3 處插入字元 L。然後,我們使用 str 類中的 join() 方法連線所有字元。

s1="WORD"
print ("original string:", s1)
l1=list(s1)

l1.insert(3,"L")

print (l1)

s1=''.join(l1)
print ("Modified string:", s1)

它將產生以下**輸出**:

original string: WORD
['W', 'O', 'R', 'L', 'D']
Modified string: WORLD

使用 Array 模組

要修改字串,請構造一個數組物件。Python 標準庫包含 array 模組。我們可以從字串變數中獲得 Unicode 型別的陣列。

import array as ar
s1="WORD"
sar=ar.array('u', s1)

陣列中的專案具有基於零的索引。因此,我們可以執行諸如 append、insert、remove 等陣列操作。讓我們在字元 D 之前插入 L

sar.insert(3,"L")

現在,藉助 tounicode() 方法,取回修改後的字串

import array as ar

s1="WORD"
print ("original string:", s1)

sar=ar.array('u', s1)
sar.insert(3,"L")
s1=sar.tounicode()

print ("Modified string:", s1)

它將產生以下**輸出**:

original string: WORD
Modified string: WORLD

使用 StringIO 類

Python 的 io 模組定義了用於處理流的類。StringIO 類使用記憶體文字緩衝區表示文字流。從字串獲得的 StringIO 物件的行為類似於 File 物件。因此,我們可以對其執行讀/寫操作。StringIO 類的 getvalue() 方法返回一個字串。

讓我們在以下程式中使用此原理來修改字串。

import io

s1="WORD"
print ("original string:", s1)

sio=io.StringIO(s1)
sio.seek(3)
sio.write("LD")
s1=sio.getvalue()

print ("Modified string:", s1)

它將產生以下**輸出**:

original string: WORD
Modified string: WORLD

Python - 字串連線

“+”運算子眾所周知的是加法運算子,返回兩個數字的和。但是,“+”符號在 Python 中充當字串連線運算子。它與兩個字串運算元一起工作,並導致兩個字串的連線。

加號符號右側字串的字元將附加到其左側的字串。連線的結果是一個新字串。

str1="Hello"
str2="World"
print ("String 1:",str1)
print ("String 2:",str2)
str3=str1+str2
print("String 3:",str3)

它將產生以下**輸出**:

String 1: Hello
String 2: World
String 3: HelloWorld

要在兩者之間插入空格,請使用第三個空字串。

str1="Hello"
str2="World"
blank=" "
print ("String 1:",str1)
print ("String 2:",str2)
str3=str1+blank+str2
print("String 3:",str3)

它將產生以下**輸出**:

String 1: Hello
String 2: World
String 3: Hello World

另一個符號 *,我們通常將其用於兩個數字的乘法,也可以與字串運算元一起使用。在這裡,* 在 Python 中充當重複運算子。其中一個運算元必須是整數,另一個運算元必須是字串。運算子連線字串的多個副本。例如:

>>> "Hello"*3
'HelloHelloHello'

整數運算元是要連線的字串運算元的副本數。

字串運算子(*)重複運算子和(+)連線運算子都可以用在一個表示式中。“*”運算子的優先順序高於“+”運算子。

str1="Hello"
str2="World"
print ("String 1:",str1)
print ("String 2:",str2)
str3=str1+str2*3
print("String 3:",str3)
str4=(str1+str2)*3
print ("String 4:", str4)

要形成str3 字串,Python 首先連線 World 的 3 個副本,然後將其結果附加到 Hello

String 3: HelloWorldWorldWorld

在第二種情況下,字串 str1 和 str2 在括號內,因此它們的連線首先發生。然後將其結果複製三次。

String 4: HelloWorldHelloWorldHelloWorld

除了 + 和 * 之外,任何其他算術運算子符號都不能與字串運算元一起使用。

Python - 字串格式化

字串格式化是透過將數字表達式的值插入到現有字串中來動態構建字串表示的過程。Python 的字串連線運算子不接受非字串運算元。因此,Python 提供以下字串格式化技術:

Python - 跳脫字元

在 Python 中,如果字串在引號符號之前以“r”或“R”為字首,則它將成為原始字串。因此,'Hello' 是普通字串,而 r'Hello' 是原始字串。

>>> normal="Hello"
>>> print (normal)
Hello
>>> raw=r"Hello"
>>> print (raw)
Hello

在正常情況下,兩者之間沒有區別。但是,當跳脫字元嵌入到字串中時,普通字串實際上會解釋轉義序列,而原始字串不會處理跳脫字元。

>>> normal="Hello\nWorld"
>>> print (normal)
Hello
World
>>> raw=r"Hello\nWorld"
>>> print (raw)
Hello\nWorld

在上面的示例中,當列印普通字串時,跳脫字元 '\n' 將被處理以引入換行符。但是,由於原始字串運算子 'r',跳脫字元的效果不會根據其含義進行轉換。

換行符 \n 是 Python 識別的轉義序列之一。轉義序列呼叫對“\”的替代實現字元子序列。在 Python 中,“\”用作跳脫字元。下表顯示轉義序列列表。

除非存在“r”或“R”字首,否則字串和位元組文字中的轉義序列將根據與 Standard C 使用的規則類似的規則進行解釋。識別的轉義序列為:

序號 轉義序列和含義
1

\<newline>

反斜槓和換行符被忽略

2

\\

反斜槓 (\)

3

\'

單引號 (')

4

\"

雙引號 (")

5

\a

ASCII 響鈴 (BEL)

6

\b

ASCII 退格 (BS)

7

\f

ASCII 換頁 (FF)

8

\n

ASCII 換行 (LF)

9

\r

ASCII 回車 (CR)

10

\t

ASCII 水平製表符 (TAB)

11

\v

ASCII 垂直製表符 (VT)

12

\ooo

具有八進位制值 ooo 的字元

13

\xhh

具有十六進位制值 hh 的字元

示例

以下程式碼顯示了上表中列出的轉義序列的用法:

# ignore \
s = 'This string will not include \
backslashes or newline characters.'
print (s)

# escape backslash
s=s = 'The \\character is called backslash'
print (s)

# escape single quote
s='Hello \'Python\''
print (s)

# escape double quote
s="Hello \"Python\""
print (s)

# escape \b to generate ASCII backspace
s='Hel\blo'
print (s)

# ASCII Bell character
s='Hello\a'
print (s)

# newline
s='Hello\nPython'
print (s)

# Horizontal tab
s='Hello\tPython'
print (s)

# form feed
s= "hello\fworld"
print (s)

# Octal notation
s="\101"
print(s)

# Hexadecimal notation
s="\x41"
print (s)

它將產生以下**輸出**:

This string will not include backslashes or newline characters.
The \character is called backslash
Hello 'Python'
Hello "Python"
Helo
Hello
Hello
Python
Hello Python
hello
world
A
A

Python - 字串方法

Python 的內建str 類定義了不同的方法。它們有助於操作字串。由於字串是不可變物件,因此這些方法返回原始字串的副本,並在其上執行相應的處理。

字串方法可以分為以下幾類:

Python - 字串練習

示例1

Python 程式,用於查詢給定字串中母音的個數。

mystr = "All animals are equal. Some are more equal"
vowels = "aeiou"
count=0
for x in mystr:
   if x.lower() in vowels: count+=1
print ("Number of Vowels:", count)

它將產生以下**輸出**:

Number of Vowels: 18

示例2

Python 程式,用於將包含二進位制數字的字串轉換為整數。

mystr = '10101'

def strtoint(mystr):
   for x in mystr:
      if x not in '01': return "Error. String with non-binary characters"
   num = int(mystr, 2)
   return num
print ("binary:{} integer: {}".format(mystr,strtoint(mystr)))

它將產生以下**輸出**:

binary:10101 integer: 21

mystr更改為 '10, 101'

binary:10,101 integer: Error. String with non-binary characters

示例3

Python 程式,用於從字串中刪除所有數字。

digits = [str(x) for x in range(10)]
mystr = 'He12llo, Py00th55on!'
chars = []
for x in mystr:
   if x not in digits:
      chars.append(x)
newstr = ''.join(chars)
print (newstr)

它將產生以下**輸出**:

Hello, Python!

練習程式

  • Python 程式,用於對字串中的字元進行排序

  • Python 程式,用於從字串中刪除重複字元

  • Python 程式,用於列出字串中唯一字元及其計數

  • Python 程式,用於查詢字串中單詞的個數

  • Python 程式,用於從字串中刪除所有非字母字元

Python - 列表

列表是 Python 中的內建資料型別之一。Python 列表是由逗號分隔的專案序列,用方括號 [] 括起來。Python 列表中的專案不必是相同的資料型別。

以下是 Python 列表的一些示例:

list1 = ["Rohan", "Physics", 21, 69.75]
list2 = [1, 2, 3, 4, 5]
list3 = ["a", "b", "c", "d"]
list4 = [25.50, True, -55, 1+2j]

在 Python 中,列表是一種序列資料型別。它是專案的排序集合。列表中的每個專案都有一個唯一的索引位置,從 0 開始。

Python 列表類似於 C、C++ 或 Java 中的陣列。但是,主要區別在於 C/C++/Java 中,陣列元素必須是相同型別。另一方面,Python 列表可以包含不同資料型別的物件。

Python 列表是可變的。可以使用索引訪問列表中的任何專案,並且可以修改。可以從列表中刪除或新增一個或多個物件。列表可以在多個索引位置具有相同的專案。

Python 列表操作

在 Python 中,列表是一個序列。因此,我們可以使用“+”運算子連線兩個列表,並使用“*”運算子連線列表的多個副本。成員運算子“in”和“not in”適用於列表物件。

Python 表示式 結果 描述
[1, 2, 3] + [4, 5, 6] [1, 2, 3, 4, 5, 6] 連線
['Hi!'] * 4 ['Hi!', 'Hi!', 'Hi!', 'Hi!'] 重複
3 in [1, 2, 3] True 成員關係

Python - 訪問列表元素

在 Python 中,列表是一個序列。列表中的每個物件都可以透過其索引訪問。索引從 0 開始。列表中最後一個專案的索引是“長度-1”。要訪問列表中的值,請使用方括號進行切片,並使用索引或索引來獲取該索引處的值。

切片運算子從列表中獲取一個或多個專案。在方括號中放入索引以檢索其位置處的專案。

obj = list1[i]

示例1

請看下面的例子:

list1 = ["Rohan", "Physics", 21, 69.75]
list2 = [1, 2, 3, 4, 5]

print ("Item at 0th index in list1: ", list1[0])
print ("Item at index 2 in list2: ", list2[2])

它將產生以下**輸出**:

Item at 0th index in list1: Rohan
Item at index 2 in list2: 3

Python 允許將負索引與任何序列型別一起使用。“-1”索引指的是列表中的最後一個專案。

示例2

讓我們看另一個例子:

list1 = ["a", "b", "c", "d"]
list2 = [25.50, True, -55, 1+2j]

print ("Item at 0th index in list1: ", list1[-1])
print ("Item at index 2 in list2: ", list2[-3])

它將產生以下**輸出**:

Item at 0th index in list1: d
Item at index 2 in list2: True

切片運算子從原始列表中提取子列表。

Sublist = list1[i:j]

引數

  • i − 子列表中第一個專案的索引

  • j − 子列表中最後一個專案下一個專案的索引

這將返回從list1 的第 i 個到第 (j-1) 個專案 的切片。

示例3

切片時,“i”和“j”兩個運算元都是可選的。如果未使用,“i”為 0,“j”為列表中的最後一個專案。負索引可用於切片。請看下面的例子:

list1 = ["a", "b", "c", "d"]
list2 = [25.50, True, -55, 1+2j]

print ("Items from index 1 to 2 in list1: ", list1[1:3])
print ("Items from index 0 to 1 in list2: ", list2[0:2])

它將產生以下**輸出**:

Items from index 1 to 2 in list1: ['b', 'c']
Items from index 0 to 1 in list2: [25.5, True]

示例 4

list1 = ["a", "b", "c", "d"]
list2 = [25.50, True, -55, 1+2j]
list4 = ["Rohan", "Physics", 21, 69.75]
list3 = [1, 2, 3, 4, 5]

print ("Items from index 1 to last in list1: ", list1[1:])
print ("Items from index 0 to 1 in list2: ", list2[:2])
print ("Items from index 2 to last in list3", list3[2:-1])
print ("Items from index 0 to index last in list4", list4[:])

它將產生以下**輸出**:

Items from index 1 to last in list1: ['b', 'c', 'd']
Items from index 0 to 1 in list2: [25.5, True]
Items from index 2 to last in list3 [3, 4]
Items from index 0 to index last in list4 ['Rohan', 'Physics', 21, 69.75]

Python - 修改列表元素

列表是 Python 中一種可變資料型別。這意味著,在物件儲存在記憶體中之後,可以就地修改列表的內容。您可以在列表中給定索引位置分配新值。

語法

list1[i] = newvalue

示例1

在下面的程式碼中,我們更改了給定列表中索引 2 的值。

list3 = [1, 2, 3, 4, 5]
print ("Original list ", list3)
list3[2] = 10
print ("List after changing value at index 2: ", list3)

它將產生以下**輸出**:

Original list [1, 2, 3, 4, 5]
List after changing value at index 2: [1, 2, 10, 4, 5]

您可以用另一個子列表替換列表中更多連續的專案。

示例2

在下面的程式碼中,索引 1 和 2 處的專案被另一個子列表中的專案替換。

list1 = ["a", "b", "c", "d"]

print ("Original list: ", list1)

list2 = ['Y', 'Z']
list1[1:3] = list2

print ("List after changing with sublist: ", list1)

它將產生以下**輸出**:

Original list: ['a', 'b', 'c', 'd']
List after changing with sublist: ['a', 'Y', 'Z', 'd']

示例3

如果源子列表的專案多於要替換的切片,則將插入源中的額外專案。請看下面的程式碼:

list1 = ["a", "b", "c", "d"]
print ("Original list: ", list1)
list2 = ['X','Y', 'Z']
list1[1:3] = list2
print ("List after changing with sublist: ", list1)

它將產生以下**輸出**:

Original list: ['a', 'b', 'c', 'd']
List after changing with sublist: ['a', 'X', 'Y', 'Z', 'd']

示例 4

如果用於替換原始列表切片的子列表的專案較少,則將替換匹配的專案,並將原始列表中的其餘專案刪除。

在下面的程式碼中,我們嘗試用“Z”(比要替換的專案少一個專案)替換“b”和“c”。結果是 Z 替換了 b,c 被刪除。

list1 = ["a", "b", "c", "d"]
print ("Original list: ", list1)
list2 = ['Z']
list1[1:3] = list2
print ("List after changing with sublist: ", list1)

它將產生以下**輸出**:

Original list: ['a', 'b', 'c', 'd']
List after changing with sublist: ['a', 'Z', 'd']

Python - 新增列表元素

list 類有兩個方法,append() 和 insert(),用於向現有列表中新增專案。

示例1

append() 方法將專案新增到現有列表的末尾。

list1 = ["a", "b", "c", "d"]
print ("Original list: ", list1)
list1.append('e')
print ("List after appending: ", list1)

輸出

Original list: ['a', 'b', 'c', 'd']
List after appending: ['a', 'b', 'c', 'd', 'e']

示例2

insert() 方法在列表的指定索引處插入專案。

list1 = ["Rohan", "Physics", 21, 69.75]
print ("Original list ", list1)

list1.insert(2, 'Chemistry')
print ("List after appending: ", list1)

list1.insert(-1, 'Pass')
print ("List after appending: ", list1)

輸出

Original list ['Rohan', 'Physics', 21, 69.75]
List after appending: ['Rohan', 'Physics', 'Chemistry', 21, 69.75]
List after appending: ['Rohan', 'Physics', 'Chemistry', 21, 'Pass', 69.75]

我們知道“-1”索引指向列表中的最後一個專案。但是,請注意,原始列表中索引“-1”處的專案是 69.75。在附加“chemistry”後,不會重新整理此索引。因此,“Pass”不是插入到更新後的索引“-1”處,而是插入到之前的索引“-1”處。

Python - 刪除列表元素

list 類的 remove() 和 pop() 方法都可以從列表中刪除專案。它們之間的區別在於 remove() 刪除作為引數給出的物件,而 pop() 刪除給定索引處的專案。

使用 remove() 方法

以下示例顯示瞭如何使用 remove() 方法刪除列表項:

list1 = ["Rohan", "Physics", 21, 69.75]
print ("Original list: ", list1)

list1.remove("Physics")
print ("List after removing: ", list1)

它將產生以下**輸出**:

Original list: ['Rohan', 'Physics', 21, 69.75]
List after removing: ['Rohan', 21, 69.75]

使用 pop() 方法

以下示例顯示瞭如何使用 pop() 方法刪除列表項:

list2 = [25.50, True, -55, 1+2j]
print ("Original list: ", list2)
list2.pop(2)
print ("List after popping: ", list2)

它將產生以下**輸出**:

Original list: [25.5, True, -55, (1+2j)]
List after popping: [25.5, True, (1+2j)]

使用“del”關鍵字

Python 具有“del”關鍵字,用於從記憶體中刪除任何 Python 物件。

示例

我們可以使用“del”從列表中刪除專案。請看下面的例子:

list1 = ["a", "b", "c", "d"]
print ("Original list: ", list1)
del list1[2]
print ("List after deleting: ", list1)

它將產生以下**輸出**:

Original list: ['a', 'b', 'c', 'd']
List after deleting: ['a', 'b', 'd']

示例

您可以使用切片運算子從列表中刪除一系列連續的專案。請看下面的例子:

list2 = [25.50, True, -55, 1+2j]
print ("List before deleting: ", list2)
del list2[0:2]
print ("List after deleting: ", list2)

它將產生以下**輸出**:

List before deleting: [25.5, True, -55, (1+2j)]
List after deleting: [-55, (1+2j)]

Python - 遍歷列表

您可以使用 Python 的for 迴圈結構遍歷列表中的專案。可以使用列表作為迭代器或藉助索引來完成遍歷。

語法

Python 列表提供一個迭代器物件。要迭代列表,請按如下方式使用 for 語句:

for obj in list:
   . . .
   . . .

示例1

請看下面的例子:

lst = [25, 12, 10, -21, 10, 100]
for num in lst:
   print (num, end = ' ')

輸出

25 12 10 -21 10 100

示例2

要遍歷列表中的專案,請獲取整數“0”到“len-1”的範圍物件。請看下面的例子:

lst = [25, 12, 10, -21, 10, 100]
indices = range(len(lst))
for i in indices:
   print ("lst[{}]: ".format(i), lst[i])

輸出

lst[0]: 25
lst[1]: 12
lst[2]: 10
lst[3]: -21
lst[4]: 10
lst[5]: 100

Python - 列表推導式

列表推導是一種非常強大的程式設計工具。它類似於數學中的集合構造器符號。這是一種簡潔的方法,可以透過對現有列表中的每個專案執行某種過程來建立新列表。列表推導比使用for 迴圈處理列表要快得多。

示例1

假設我們想分離字串中的每個字母並將所有非母音字母放在列表物件中。我們可以透過如下所示的for 迴圈來實現:

chars=[]
for ch in 'TutorialsPoint':
   if ch not in 'aeiou':
      chars.append(ch)
print (chars)

chars 列表物件顯示如下:

['T', 't', 'r', 'l', 's', 'P', 'n', 't']

列表推導技術

我們可以透過列表推導技術輕鬆獲得相同的結果。列表推導的一般用法如下:

listObj = [x for x in iterable]

應用此方法,可以使用以下語句構造 chars 列表:

chars = [ char for char in 'TutorialsPoint' if char not in 'aeiou']
print (chars)

chars 列表將如前所示顯示:

['T', 't', 'r', 'l', 's', 'P', 'n', 't']

示例2

以下示例使用列表推導來構建一個包含 1 到 10 之間的數字平方的列表

squares = [x*x for x in range(1,11)]
print (squares)

squares 列表物件為:

[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

列表推導中的巢狀迴圈

在下面的示例中,兩個列表中專案的組合以元組的形式新增到第三個列表物件中。

示例3

list1=[1,2,3]
list2=[4,5,6]
CombLst=[(x,y) for x in list1 for y in list2]
print (CombLst)

它將產生以下**輸出**:

[(1, 4), (1, 5), (1, 6), (2, 4), (2, 5), (2, 6), (3, 4), (3, 5), (3, 6)]

列表推導中的條件

以下語句將建立一個包含 1 到 20 之間所有偶數的列表。

示例 4

list1=[x for x in range(1,21) if x%2==0]
print (list1)

它將產生以下**輸出**:

[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]

Python - 列表排序

list 類的 sort() 方法使用詞典排序機制按升序或降序重新排列專案。排序是就地進行的,這意味著重新排列發生在同一列表物件中,並且它不返回新物件。

語法

list1.sort(key, reverse)

引數

  • Key − 應用於列表中每個專案的函式。返回值用於執行排序。可選

  • reverse − 布林值。如果設定為 True,則排序按降序進行。可選

返回值

此方法返回 None。

示例1

現在讓我們看一些例子來了解如何在 Python 中排序列表:

list1 = ['physics', 'Biology', 'chemistry', 'maths']
print ("list before sort", list1)
list1.sort()
print ("list after sort : ", list1)

print ("Descending sort")

list2 = [10,16, 9, 24, 5]
print ("list before sort", list2)
list2.sort()
print ("list after sort : ", list2)

它將產生以下**輸出**:

list before sort ['physics', 'Biology', 'chemistry', 'maths']
list after sort: ['Biology', 'chemistry', 'maths', 'physics']
Descending sort
list before sort [10, 16, 9, 24, 5]
list after sort : [5, 9, 10, 16, 24]

示例2

在此示例中,str.lower() 方法用作 sort() 方法中的 key 引數。

list1 = ['Physics', 'biology', 'Biomechanics', 'psychology']
print ("list before sort", list1)
list1.sort(key=str.lower)
print ("list after sort : ", list1)

它將產生以下**輸出**:

list before sort ['Physics', 'biology', 'Biomechanics', 'psychology']
list after sort : ['biology', 'Biomechanics', 'Physics', 'psychology']

示例3

讓我們使用使用者定義的函式作為 sort() 方法中的 key 引數。myfunction() 使用 % 運算子返回餘數,根據該餘數進行排序。

def myfunction(x):
   return x%10
list1 = [17, 23, 46, 51, 90]
print ("list before sort", list1)
list1.sort(key=myfunction)
print ("list after sort : ", list1)

它將產生以下**輸出**:

list before sort [17, 23, 46, 51, 90]
list after sort: [90, 51, 23, 46, 17]

Python - 複製列表

在 Python 中,變數只是記憶體中物件的標籤或引用。因此,賦值“lst1 = lst”指的是記憶體中同一個列表物件。請看下面的例子:

lst = [10, 20]
print ("lst:", lst, "id(lst):",id(lst))
lst1 = lst
print ("lst1:", lst1, "id(lst1):",id(lst1))

它將產生以下**輸出**:

lst: [10, 20] id(lst): 1677677188288
lst1: [10, 20] id(lst1): 1677677188288

因此,如果我們更新“lst”,它將自動反映在“lst1”中。將 lst[0] 更改為 100

lst[0]=100
print ("lst:", lst, "id(lst):",id(lst))
print ("lst1:", lst1, "id(lst1):",id(lst1))

它將產生以下**輸出**:

lst: [100, 20] id(lst): 1677677188288
lst1: [100, 20] id(lst1): 1677677188288

因此,我們可以說“lst1”不是“lst”的物理副本。

使用 List 類的 Copy 方法

Python 的 list 類具有一個 copy() 方法,用於建立列表物件的新的物理副本。

語法

lst1 = lst.copy()

新的列表物件將具有不同的 id() 值。以下示例演示了這一點:

lst = [10, 20]
lst1 = lst.copy()
print ("lst:", lst, "id(lst):",id(lst))
print ("lst1:", lst1, "id(lst1):",id(lst1))

它將產生以下**輸出**:

lst: [10, 20] id(lst): 1677678705472
lst1: [10, 20] id(lst1): 1677678706304

即使兩個列表具有相同的資料,它們也具有不同的 id() 值,因此它們是兩個不同的物件,“lst1”是“lst”的副本。

如果我們嘗試修改“lst”,它將不會反映在“lst1”中。請看下面的例子:

lst[0]=100
print ("lst:", lst, "id(lst):",id(lst))
print ("lst1:", lst1, "id(lst1):",id(lst1))

它將產生以下**輸出**:

lst: [100, 20] id(lst): 1677678705472
lst1: [10, 20] id(lst1): 1677678706304

Python - 合併列表

在 Python 中,列表被分類為序列型別物件。它是專案的集合,這些專案可能屬於不同的資料型別,每個專案都有一個從 0 開始的位置索引。您可以使用不同的方法來連線兩個 Python 列表。

所有序列型別物件都支援連線運算子,可以使用它來連線兩個列表。

L1 = [10,20,30,40]
L2 = ['one', 'two', 'three', 'four']
L3 = L1+L2
print ("Joined list:", L3)

它將產生以下**輸出**:

Joined list: [10, 20, 30, 40, 'one', 'two', 'three', 'four']

您還可以使用帶“+=”符號的增強連線運算子將 L2 附加到 L1

L1 = [10,20,30,40]
L2 = ['one', 'two', 'three', 'four']
L1+=L2
print ("Joined list:", L1)

可以使用 extend() 方法獲得相同的結果。在這裡,我們需要擴充套件 L1 以便在其內新增來自 L2 的元素。

L1 = [10,20,30,40]
L2 = ['one', 'two', 'three', 'four']
L1.extend(L2)
print ("Joined list:", L1)

要將專案從一個列表新增到另一個列表,經典的迭代解決方案也有效。使用 for 迴圈遍歷第二個列表的專案,並將每個專案附加到第一個列表中。

L1 = [10,20,30,40]
L2 = ['one', 'two', 'three', 'four']

for x in L2:
   L1.append(x)
   
print ("Joined list:", L1)

合併兩個列表的一種稍微複雜的方法是使用列表推導,如下面的程式碼所示:

L1 = [10,20,30,40]
L2 = ['one', 'two', 'three', 'four']
L3 = [y for x in [L1, L2] for y in x]
print ("Joined list:", L3)

Python - 列表方法

Python 的list 類包含以下方法,您可以使用這些方法來新增、更新和刪除列表項:

序號 方法和描述

1

list.append(obj)

將物件 obj 附加到列表

2

list.clear()

清除列表的內容

3

list.copy()

返回列表物件的副本

4

list.count(obj)

返回 obj 在列表中出現的次數

5

list.extend(seq)

將 seq 的內容附加到列表

6

list.index(obj)

返回列表中 obj 出現的最低索引

7

list.insert(index, obj)

在偏移量索引處將物件 obj 插入列表

8

list.pop(obj=list[-1])

刪除並返回列表中的最後一個物件或 obj

9

list.remove(obj)

從列表中刪除物件 obj

10

list.reverse()

就地反轉列表的物件

11

list.sort([func])

對列表的物件進行排序,如果給出,則使用比較函式 func

Python - 列表練習

示例1

Python 程式用於查詢給定列表中唯一的數字。

L1 = [1, 9, 1, 6, 3, 4, 5, 1, 1, 2, 5, 6, 7, 8, 9, 2]
L2 = []
for x in L1:
   if x not in L2:
      L2.append(x)
print (L2)

它將產生以下**輸出**:

[1, 9, 6, 3, 4, 5, 2, 7, 8]

示例2

Python 程式用於查詢列表中所有數字的總和。

L1 = [1, 9, 1, 6, 3, 4]
ttl = 0
for x in L1:
   ttl+=x
print ("Sum of all numbers Using loop:", ttl)
ttl = sum(L1)
print ("Sum of all numbers sum() function:", ttl)

它將產生以下**輸出**:

Sum of all numbers Using loop: 24
Sum of all numbers sum() function: 24

示例3

Python 程式用於建立一個包含 5 個隨機整數的列表。

import random
L1 = []
for i in range(5):
   x = random.randint(0, 100)
   L1.append(x)
print (L1)

它將產生以下**輸出**:

[77, 3, 20, 91, 85]

練習程式

  • Python 程式用於從列表中刪除所有奇數。

  • Python 程式用於根據每個單詞中的字母數量對字串列表進行排序。

  • Python 程式將列表中的非數字項放在單獨的列表中。

  • Python 程式用於建立一個整數列表,表示字串中的每個字元。

  • Python 程式用於查詢兩個列表中共同的數字。

Python - 元組

元組是 Python 中的內建資料型別之一。Python 元組是由逗號分隔的專案組成的序列,用括號 () 括起來。Python 元組中的專案不必是相同的資料型別。

以下是 Python 元組的一些示例:

tup1 = ("Rohan", "Physics", 21, 69.75)
tup2 = (1, 2, 3, 4, 5)
tup3 = ("a", "b", "c", "d")
tup4 = (25.50, True, -55, 1+2j)

在 Python 中,元組是一種序列資料型別。它是專案的排序集合。元組中的每個專案都有一個唯一的位 置索引,從 0 開始。

在C/C++/Java陣列中,陣列元素必須是相同型別。另一方面,Python元組可以包含不同資料型別的物件。

Python元組和列表都是序列。兩者之間的一個主要區別是,Python列表是可變的,而元組是不可變的。雖然可以使用索引訪問元組中的任何專案,但不能修改、刪除或新增。

Python元組操作

在Python中,元組是一個序列。因此,我們可以使用+運算子連線兩個元組,使用*運算子連線元組的多個副本。“in”和“not in”成員運算子適用於元組物件。

Python 表示式 結果 描述
(1, 2, 3) + (4, 5, 6) (1, 2, 3, 4, 5, 6) 連線
('Hi!',) * 4 ('Hi!', 'Hi!', 'Hi!', 'Hi!') 重複
3 in (1, 2, 3) True 成員關係

請注意,即使元組中只有一個物件,也必須在其後新增逗號。否則,它將被視為字串。

Python - 訪問元組元素

在Python中,元組是一個序列。列表中的每個物件都可以透過其索引訪問。索引從“0”開始。元組中最後一項的索引是“長度-1”。要訪問元組中的值,請使用方括號進行切片,並使用索引或索引來獲取該索引處的值。

切片運算子從元組中獲取一個或多個專案。

obj = tup1(i)

示例1

將索引放在方括號內以檢索其位置的專案。

tup1 = ("Rohan", "Physics", 21, 69.75)
tup2 = (1, 2, 3, 4, 5)

print ("Item at 0th index in tup1tup2: ", tup1[0])
print ("Item at index 2 in list2: ", tup2[2])

它將產生以下**輸出**:

Item at 0th index in tup1: Rohan
Item at index 2 in tup2: 3

示例2

Python允許對任何序列型別使用負索引。“-1”索引指的是元組中的最後一項。

tup1 = ("a", "b", "c", "d")
tup2 = (25.50, True, -55, 1+2j)
print ("Item at 0th index in tup1: ", tup1[-1])
print ("Item at index 2 in tup2: ", tup2[-3])

它將產生以下**輸出**:

Item at 0th index in tup1: d
Item at index 2 in tup2: True

從元組中提取子元組

切片運算子從原始元組中提取子元組。

Subtup = tup1[i:j]

引數

  • i − 子元組中第一項的索引

  • j − 子元組中最後一項的下一個專案的索引

這將返回從tup1的第i個到第(j-1)個專案之間的切片。

示例3

請看下面的例子:

tup1 = ("a", "b", "c", "d")
tup2 = (25.50, True, -55, 1+2j)

print ("Items from index 1 to 2 in tup1: ", tup1[1:3])
print ("Items from index 0 to 1 in tup2: ", tup2[0:2])

它將產生以下**輸出**:

Items from index 1 to 2 in tup1: ('b', 'c')
Items from index 0 to 1 in tup2: (25.5, True)

示例 4

在切片時,“i”和“j”兩個運算元都是可選的。如果未使用,“i”為0,“j”為元組中的最後一項。切片中可以使用負索引。請參見以下示例:

tup1 = ("a", "b", "c", "d")
tup2 = (25.50, True, -55, 1+2j)
tup4 = ("Rohan", "Physics", 21, 69.75)
tup3 = (1, 2, 3, 4, 5)

print ("Items from index 1 to last in tup1: ", tup1[1:])
print ("Items from index 0 to 1 in tup2: ", tup2[:2])
print ("Items from index 2 to last in tup3", tup3[2:-1])
print ("Items from index 0 to index last in tup4", tup4[:])

它將產生以下**輸出**:

Items from index 1 to last in tup1: ('b', 'c', 'd')
Items from index 0 to 1 in tup2: (25.5, True)
Items from index 2 to last in tup3: (3, 4)
Items from index 0 to index last in tup4: ('Rohan', 'Physics', 21, 69.75)

Python - 更新元組

在Python中,元組是一種不可變的資料型別。一旦不可變物件在記憶體中建立,就不能修改它。

示例1

如果我們嘗試使用切片運算子為元組項賦值,Python將引發TypeError異常。請參見以下示例:

tup1 = ("a", "b", "c", "d")
tup1[2] = 'Z'
print ("tup1: ", tup1)

它將產生以下**輸出**:

Traceback (most recent call last):
 File "C:\Users\mlath\examples\main.py", line 2, in <module>
  tup1[2] = 'Z'
  ~~~~^^^
TypeError: 'tuple' object does not support item assignment

因此,無法更新元組。因此,元組類不提供用於新增、插入、刪除、排序元組物件中專案的的方法,就像列表類一樣。

如何更新Python元組?

您可以使用變通方法來更新元組。使用list()函式將元組轉換為列表,執行所需的追加/插入/刪除操作,然後將列表解析回元組物件。

示例2

在這裡,我們將元組轉換為列表,更新現有專案,追加新專案並對列表進行排序。然後將列表轉換回元組。

tup1 = ("a", "b", "c", "d")
print ("Tuple before update", tup1, "id(): ", id(tup1))

list1 = list(tup1)
list1[2]='F'
list1.append('Z')
list1.sort()
print ("updated list", list1)

tup1 = tuple(list1)
print ("Tuple after update", tup1, "id(): ", id(tup1))

它將產生以下**輸出**:

Tuple before update ('a', 'b', 'c', 'd') id(): 2295023084192
updated list ['F', 'Z', 'a', 'b', 'd']
Tuple after update ('F', 'Z', 'a', 'b', 'd') id(): 2295021518128

但是,請注意,更新前和更新後的tup1的id()是不同的。這意味著建立了一個新的元組物件,並且沒有就地修改原始元組物件。

Python - 解包元組專案

術語“解包”是指將元組專案解析到各個變數的過程。在Python中,圓括號是序列物件文字表示的預設分隔符。

以下宣告元組的語句是相同的。

>>> t1 = (x,y)
>>> t1 = x,y
>>> type (t1)
<class 'tuple'>

示例1

要將元組專案儲存到各個變數中,請在賦值運算子的左側使用多個變數,如下例所示:

tup1 = (10,20,30)
x, y, z = tup1
print ("x: ", x, "y: ", "z: ",z)

它將產生以下**輸出**:

x: 10 y: 20 z: 30

這就是元組如何解包到各個變數中的。

使用解包元組

在上面的示例中,賦值運算子左側的變數數量等於元組中的專案數量。如果數量不相等怎麼辦?

示例2

如果變數的數量多於或少於元組的長度,Python將引發ValueError異常。

tup1 = (10,20,30)
x, y = tup1
x, y, p, q = tup1

它將產生以下**輸出**:

  x, y = tup1
  ^^^^
ValueError: too many values to unpack (expected 2)
  x, y, p, q = tup1
  ^^^^^^^^^^
ValueError: not enough values to unpack (expected 4, got 3)

在這種情況下,使用“*”符號進行解包。在“y”前面加上“*”,如下所示:

tup1 = (10,20,30)
x, *y = tup1
print ("x: ", "y: ", y)

它將產生以下**輸出**:

x: y: [20, 30]

元組中的第一個值被賦值給“x”,其餘專案被賦值給“y”,它將成為一個列表。

示例3

在這個例子中,元組包含6個值,要解包的變數為3個。我們在第二個變數前加“*”。

tup1 = (10,20,30, 40, 50, 60)
x, *y, z = tup1
print ("x: ",x, "y: ", y, "z: ", z)

它將產生以下**輸出**:

x: 10 y: [20, 30, 40, 50] z: 60

這裡,值首先解包到“x”和“z”,然後其餘值被賦值給“y”作為列表。

示例 4

如果我們在第一個變數前面新增“*”會怎樣?

tup1 = (10,20,30, 40, 50, 60)
*x, y, z = tup1
print ("x: ",x, "y: ", y, "z: ", z)

它將產生以下**輸出**:

x: [10, 20, 30, 40] y: 50 z: 60

同樣,元組的解包方式是各個變數首先獲取值,其餘值留給列表“x”。

Python - 遍歷元組

您可以使用Python的for迴圈結構遍歷元組中的專案。可以使用元組作為迭代器或藉助索引來進行遍歷。

語法

Python元組提供一個迭代器物件。要迭代元組,請使用for語句,如下所示:

for obj in tuple:
   . . .
   . . .

示例1

以下示例顯示了一個簡單的Pythonfor迴圈結構:

tup1 = (25, 12, 10, -21, 10, 100)
for num in tup1:
   print (num, end = ' ')

它將產生以下**輸出**:

25 12 10 -21 10 100

示例2

要迭代元組中的專案,請獲取從“0”到“len-1”的整數範圍物件。

tup1 = (25, 12, 10, -21, 10, 100)
indices = range(len(tup1))
for i in indices:
   print ("tup1[{}]: ".format(i), tup1[i])

它將產生以下**輸出**:

tup1[0]: 25
tup1 [1]: 12
tup1 [2]: 10
tup1 [3]: -21
tup1 [4]: 10
tup1 [5]: 100

Python - 合併元組

在Python中,元組被分類為序列型別物件。它是一組專案,這些專案可能屬於不同的資料型別,每個專案都有一個從0開始的位置索引。雖然此定義也適用於列表,但列表和元組有兩個主要區別。首先,在列表的情況下,專案用方括號括起來(例如:[10,20,30,40]),而元組是透過將專案放在圓括號中形成的(例如:(10,20,30,40))。

在Python中,元組是一個不可變物件。因此,一旦元組在記憶體中形成,就不可能修改其內容。

但是,您可以使用不同的方法來連線兩個Python元組。

示例1

所有序列型別物件都支援連線運算子,可以使用它來連線兩個列表。

T1 = (10,20,30,40)
T2 = ('one', 'two', 'three', 'four')
T3 = T1+T2
print ("Joined Tuple:", T3)

它將產生以下**輸出**:

Joined Tuple: (10, 20, 30, 40, 'one', 'two', 'three', 'four')

示例2

您還可以使用增強連線運算子"+="符號將T2附加到T1

T1 = (10,20,30,40)
T2 = ('one', 'two', 'three', 'four')
T1+=T2
print ("Joined Tuple:", T1)

示例3

可以使用extend()方法獲得相同的結果。在這裡,我們需要將兩個元組物件轉換為列表,擴充套件以便將一個列表中的元素新增到另一個列表中,並將連線的列表轉換回元組。

T1 = (10,20,30,40)
T2 = ('one', 'two', 'three', 'four')
L1 = list(T1)
L2 = list(T2)
L1.extend(L2)
T1 = tuple(L1)
print ("Joined Tuple:", T1)

示例 4

Python的內建sum()函式也有助於連線元組。我們使用表示式

sum((t1, t2), ())

首先將第一個元組的元素附加到一個空元組,然後附加第二個元組的元素,並返回一個新的元組,該元組是兩個元組的連線。

T1 = (10,20,30,40)
T2 = ('one', 'two', 'three', 'four')
T3 = sum((T1, T2), ())
print ("Joined Tuple:", T3)

示例5

合併兩個元組的一種稍微複雜的方法是使用列表推導式,如下程式碼所示:

T1 = (10,20,30,40)
T2 = ('one', 'two', 'three', 'four')
L1, L2 = list(T1), list(T2)
L3 = [y for x in [L1, L2] for y in x]
T3 = tuple(L3)
print ("Joined Tuple:", T3)

示例6

您可以在第二個迴圈中的專案上執行for迴圈,將每個專案轉換為單個專案元組,並使用"+="運算子將其連線到第一個元組

T1 = (10,20,30,40)
T2 = ('one', 'two', 'three', 'four')
for t in T2:
   T1+=(t,)
print (T1)

Python - 元組方法

由於Python中的元組是不可變的,因此元組類沒有定義用於新增或刪除專案的方法。元組類只定義了兩種方法。

序號 方法和描述
1

tuple.count(obj)

返回obj在元組中出現的次數

2 tuple.index(obj)

返回obj在元組中第一次出現的最低索引

查詢元組項的索引

元組類的index()方法返回給定項第一次出現的索引。

語法

tuple.index(obj)

返回值

index()方法返回一個整數,表示“obj”第一次出現的索引。

示例

請看下面的例子:

tup1 = (25, 12, 10, -21, 10, 100)
print ("Tup1:", tup1)
x = tup1.index(10)
print ("First index of 10:", x)

它將產生以下**輸出**:

Tup1: (25, 12, 10, -21, 10, 100)
First index of 10: 2

計數元組專案

元組類中的count()方法返回給定物件在元組中出現的次數。

語法

tuple.count(obj)

返回值

物件的出現次數。count()方法返回一個整數。

示例

tup1 = (10, 20, 45, 10, 30, 10, 55)
print ("Tup1:", tup1)
c = tup1.count(10)
print ("count of 10:", c)

它將產生以下**輸出**:

Tup1: (10, 20, 45, 10, 30, 10, 55)
count of 10: 3

示例

即使元組中的專案包含表示式,它們也會被計算以獲得計數。

Tup1 = (10, 20/80, 0.25, 10/40, 30, 10, 55)
print ("Tup1:", tup1)
c = tup1.count(0.25)
print ("count of 10:", c)

它將產生以下**輸出**:

Tup1: (10, 0.25, 0.25, 0.25, 30, 10, 55)
count of 10: 3

Python元組練習

示例1

Python程式用於查詢給定元組中唯一的數字:

T1 = (1, 9, 1, 6, 3, 4, 5, 1, 1, 2, 5, 6, 7, 8, 9, 2)
T2 = ()
for x in T1:
   if x not in T2:
      T2+=(x,)
print ("original tuple:", T1)
print ("Unique numbers:", T2)

它將產生以下**輸出**:

original tuple: (1, 9, 1, 6, 3, 4, 5, 1, 1, 2, 5, 6, 7, 8, 9, 2)
Unique numbers: (1, 9, 6, 3, 4, 5, 2, 7, 8)

示例2

Python程式用於查詢元組中所有數字的總和:

T1 = (1, 9, 1, 6, 3, 4)
ttl = 0
for x in T1:
   ttl+=x
   
print ("Sum of all numbers Using loop:", ttl)

ttl = sum(T1)
print ("Sum of all numbers sum() function:", ttl)

它將產生以下**輸出**:

Sum of all numbers Using loop: 24
Sum of all numbers sum() function: 24

示例3

Python程式用於建立一個包含5個隨機整數的元組:

import random
t1 = ()
for i in range(5):
   x = random.randint(0, 100)
   t1+=(x,)
print (t1)

它將產生以下**輸出**:

(64, 21, 68, 6, 12)

練習程式

  • Python程式用於從列表中刪除所有重複的數字。

  • Python程式用於根據每個單詞中的字母數量對字串元組進行排序。

  • Python程式用於從給定元組中準備一個非數字專案的元組。

  • Python程式用於建立一個整數元組,表示字串中的每個字元

  • Python程式用於查詢兩個元組中共同的數字。

Python - 集合

集合是Python中內建資料型別之一。在數學中,集合是不同物件的集合。集合資料型別是Python對集合的實現。集合中的物件可以是任何資料型別。

Python中的集合也是一種集合資料型別,例如列表或元組。但是,它不是有序集合,即集合中的專案無法透過其位置索引訪問。集合物件是由花括號{}括起來的至少一個不可變物件的集合。

示例1

下面給出一些集合物件的示例:

s1 = {"Rohan", "Physics", 21, 69.75}
s2 = {1, 2, 3, 4, 5}
s3 = {"a", "b", "c", "d"}
s4 = {25.50, True, -55, 1+2j}
print (s1)
print (s2)
print (s3)
print (s4)

它將產生以下**輸出**:

{'Physics', 21, 'Rohan', 69.75}
{1, 2, 3, 4, 5}
{'a', 'd', 'c', 'b'}
{25.5, -55, True, (1+2j)}

以上結果表明,賦值中物件的順序不一定保留在集合物件中。這是因為Python優化了集合的結構以進行集合操作。

除了集合的文字表示(將專案放在花括號內),Python的內建set()函式也構造集合物件。

set() 函式

set()是內建函式之一。它將任何序列物件(列表、元組或字串)作為引數,並返回一個集合物件

語法

Obj = set(sequence)

引數

  • sequence − 列表、元組或str型別的物件

返回值

set()函式從序列返回一個集合物件,並丟棄其中的重複元素。

示例2

L1 = ["Rohan", "Physics", 21, 69.75]
s1 = set(L1)
T1 = (1, 2, 3, 4, 5)
s2 = set(T1)
string = "TutorialsPoint"
s3 = set(string)

print (s1)
print (s2)
print (s3)

它將產生以下**輸出**:

{'Rohan', 69.75, 21, 'Physics'}
{1, 2, 3, 4, 5}
{'u', 'a', 'o', 'n', 'r', 's', 'T', 'P', 'i', 't', 'l'}

示例3

集合是不同物件的集合。即使您在集合中重複一個物件,也只保留一個副本。

s2 = {1, 2, 3, 4, 5, 3,0, 1, 9}
s3 = {"a", "b", "c", "d", "b", "e", "a"}
print (s2)
print (s3)

它將產生以下**輸出**:

{0, 1, 2, 3, 4, 5, 9}
{'a', 'b', 'd', 'c', 'e'}

示例 4

只有不可變物件才能用於構成集合物件。允許使用任何數字型別、字串和元組,但不能在集合中放置列表或字典。

s1 = {1, 2, [3, 4, 5], 3,0, 1, 9}
print (s1)
s2 = {"Rohan", {"phy":50}}
print (s2)

它將產生以下**輸出**:

   s1 = {1, 2, [3, 4, 5], 3,0, 1, 9}
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: unhashable type: 'list'
   s2 = {"Rohan", {"phy":50}}
        ^^^^^^^^^^^^^^^^^^^^^
TypeError: unhashable type: 'dict'

Python引發TypeError異常,並顯示訊息“unhashable types 'list' or 'dict'”。雜湊為不可變專案生成一個唯一數字,這使得能夠在計算機記憶體中快速搜尋。Python具有內建的hash()函式。列表或字典不支援此函式。

即使集合中不儲存可變物件,集合本身也是一個可變物件。Python有特殊的運算子來處理集合,並且集合類中有多種方法來對集合物件的元素執行新增、刪除、更新操作。

Python - 訪問集合元素

由於集合不是序列資料型別,因此不能像列表或元組那樣單獨訪問其專案,因為它們沒有位置索引。集合專案也沒有鍵(如字典)來訪問。您只能使用for迴圈遍歷集合專案。

示例1

langs = {"C", "C++", "Java", "Python"}
for lang in langs:
   print (lang)

它將產生以下**輸出**:

Python
C
C++
Java

示例2

Python的成員運算子允許您檢查集合中是否存在某個專案。請看下面的例子:

langs = {"C", "C++", "Java", "Python"}
print ("PHP" in langs)
print ("Java" in langs)

它將產生以下**輸出**:

False
True

Python - 新增集合元素

即使集合只包含不可變物件,集合本身也是可變的。我們可以透過以下幾種方式新增新元素:

add() 方法

集合類中的 add() 方法新增一個新元素。如果元素已存在於集合中,則集合不變。

語法

set.add(obj)

引數

  • obj − 任何不可變型別的物件。

示例

請看下面的例子:

lang1 = {"C", "C++", "Java", "Python"}
lang1.add("Golang")
print (lang1)

它將產生以下**輸出**:

{'Python', 'C', 'Golang', 'C++', 'Java'}

update() 方法

集合類的 update() 方法包含作為引數給出的集合的元素。如果另一個集合中的元素已經存在一個或多個,則不會包含它們。

語法

set.update(obj)

引數

  • obj − 集合或序列物件(列表、元組、字串)

示例

以下示例演示了 update() 方法的工作方式:

lang1 = {"C", "C++", "Java", "Python"}
lang2 = {"PHP", "C#", "Perl"}
lang1.update(lang2)
print (lang1)

它將產生以下**輸出**:

{'Python', 'Java', 'C', 'C#', 'PHP', 'Perl', 'C++'}

示例

update() 方法也接受任何序列物件作為引數。這裡,元組是 update() 方法的引數。

lang1 = {"C", "C++", "Java", "Python"}
lang2 = ("PHP", "C#", "Perl")
lang1.update(lang2)
print (lang1)

它將產生以下**輸出**:

{'Java', 'Perl', 'Python', 'C++', 'C#', 'C', 'PHP'}

示例

在這個例子中,一個集合是由一個字串構造的,另一個字串用作 update() 方法的引數。

set1 = set("Hello")
set1.update("World")
print (set1)

它將產生以下**輸出**:

{'H', 'r', 'o', 'd', 'W', 'l', 'e'}

union() 方法

集合類的 union() 方法也組合來自兩個集合的唯一元素,但它返回一個新的集合物件。

語法

set.union(obj)

引數

  • obj − 集合或序列物件(列表、元組、字串)

返回值

union() 方法返回一個集合物件。

示例

以下示例演示了 union() 方法的工作方式:

lang1 = {"C", "C++", "Java", "Python"}
lang2 = {"PHP", "C#", "Perl"}
lang3 = lang1.union(lang2)
print (lang3)

它將產生以下**輸出**:

{'C#', 'Java', 'Perl', 'C++', 'PHP', 'Python', 'C'}

示例

如果將序列物件作為引數傳遞給 union() 方法,Python 會自動先將其轉換為集合,然後執行聯合操作。

lang1 = {"C", "C++", "Java", "Python"}
lang2 = ["PHP", "C#", "Perl"]
lang3 = lang1.union(lang2)
print (lang3)

它將產生以下**輸出**:

{'PHP', 'C#', 'Python', 'C', 'Java', 'C++', 'Perl'}

示例

在這個例子中,一個集合是由一個字串構造的,另一個字串用作 union() 方法的引數。

set1 = set("Hello")
set2 = set1.union("World")
print (set2)

它將產生以下**輸出**:

{'e', 'H', 'r', 'd', 'W', 'o', 'l'}

Python - 刪除集合元素

Python 的集合類提供不同的方法來從集合物件中刪除一個或多個元素。

remove() 方法

remove() 方法刪除集合中給定的元素(如果存在)。但是,如果它不存在,則會引發 KeyError。

語法

set.remove(obj)

引數

  • obj − 一個不可變物件

示例

lang1 = {"C", "C++", "Java", "Python"}
print ("Set before removing: ", lang1)
lang1.remove("Java")
print ("Set after removing: ", lang1)
lang1.remove("PHP")

它將產生以下**輸出**:

Set before removing: {'C', 'C++', 'Python', 'Java'}
Set after removing: {'C', 'C++', 'Python'}
   lang1.remove("PHP")
KeyError: 'PHP'

discard() 方法

集合類中的 discard() 方法類似於 remove() 方法。唯一的區別是,即使要刪除的物件不存在於集合中,它也不會引發錯誤。

語法

set.discard(obj)

引數

  • obj − 一個不可變物件

示例

lang1 = {"C", "C++", "Java", "Python"}
print ("Set before discarding C++: ", lang1)
lang1.discard("C++")
print ("Set after discarding C++: ", lang1)
print ("Set before discarding PHP: ", lang1)
lang1.discard("PHP")
print ("Set after discarding PHP: ", lang1)

它將產生以下**輸出**:

Set before discarding C++: {'Java', 'C++', 'Python', 'C'}
Set after discarding C++: {'Java', 'Python', 'C'}
Set before discarding PHP: {'Java', 'Python', 'C'}
Set after discarding PHP: {'Java', 'Python', 'C'}

pop() 方法

集合類中的 pop() 方法從集合中刪除一個任意元素。該方法返回被刪除的元素。從空集合中彈出元素會導致 KeyError。

語法

obj = set.pop()

返回值

pop() 方法返回從集合中刪除的物件。

示例

lang1 = {"C", "C++"}
print ("Set before popping: ", lang1)
obj = lang1.pop()
print ("object popped: ", obj)
print ("Set after popping: ", lang1)
obj = lang1.pop()
obj = lang1.pop()

它將產生以下**輸出**:

Set before popping: {'C++', 'C'}
object popped: C++
Set after popping: {'C'}
Traceback (most recent call last):
   obj = lang1.pop()
         ^^^^^^^^^^^
KeyError: 'pop from an empty set'

在第三次呼叫 pop() 時,集合為空,因此引發 KeyError。

clear() 方法

集合類中的 clear() 方法刪除集合物件中的所有元素,留下一個空集合。

語法

set.clear()

示例

lang1 = {"C", "C++", "Java", "Python"}
print (lang1)
print ("After clear() method")
lang1.clear()
print (lang1)

它將產生以下**輸出**:

{'Java', 'C++', 'Python', 'C'}
After clear() method
set()

difference_update() 方法

集合類中的 difference_update() 方法透過刪除自身與作為引數給出的另一個集合之間共同的元素來更新集合。

語法

set.difference_update(obj)

引數

  • obj − 一個集合物件

示例

s1 = {1,2,3,4,5}
s2 = {4,5,6,7,8}
print ("s1 before running difference_update: ", s1)
s1.difference_update(s2)
print ("s1 after running difference_update: ", s1)

它將產生以下**輸出**:

s1 before running difference_update: {1, 2, 3, 4, 5}
s1 after running difference_update: {1, 2, 3}
set()

difference() 方法

difference() 方法類似於 difference_update() 方法,不同之處在於它返回一個包含兩個現有集合差的新集合物件。

語法

set.difference(obj)

引數

  • obj − 一個集合物件

返回值

difference() 方法返回一個新的集合,其中包含在刪除 obj 中的元素後剩餘的元素。

示例

s1 = {1,2,3,4,5}
s2 = {4,5,6,7,8}
print ("s1: ", s1, "s2: ", s2)
s3 = s1.difference(s2)
print ("s3 = s1-s2: ", s3)

它將產生以下**輸出**:

s1: {1, 2, 3, 4, 5} s2: {4, 5, 6, 7, 8}
s3 = s1-s2: {1, 2, 3}

intersection_update() 方法

intersection_update() 方法的結果是,集合物件只保留自身與作為引數給出的另一個集合物件中共同的元素。

語法

set.intersection_update(obj)

引數

  • obj − 一個集合物件

返回值

intersection_update() 方法刪除不常見的元素,只保留自身和 obj 中共同的元素。

示例

s1 = {1,2,3,4,5}
s2 = {4,5,6,7,8}
print ("s1: ", s1, "s2: ", s2)
s1.intersection_update(s2)
print ("a1 after intersection: ", s1)

它將產生以下**輸出**:

s1: {1, 2, 3, 4, 5} s2: {4, 5, 6, 7, 8}
s1 after intersection: {4, 5}

intersection() 方法

集合類中的 intersection() 方法類似於其 intersection_update() 方法,不同之處在於它返回一個由現有集合中共同元素組成的新集合物件。

語法

set.intersection(obj)

引數

  • obj − 一個集合物件

返回值

intersection() 方法返回一個集合物件,只保留自身和 obj 中共同的元素。

示例

s1 = {1,2,3,4,5}
s2 = {4,5,6,7,8}
print ("s1: ", s1, "s2: ", s2)
s3 = s1.intersection(s2)
print ("s3 = s1 & s2: ", s3)

它將產生以下**輸出**:

s1: {1, 2, 3, 4, 5} s2: {4, 5, 6, 7, 8}
s3 = s1 & s2: {4, 5}

symmetric_difference_update() 方法

兩個集合的對稱差是所有不常見元素的集合,拒絕共同元素。symmetric_difference_update() 方法使用自身與作為引數給出的集合之間的對稱差來更新集合。

語法

set.symmetric_difference_update(obj)

引數

  • obj − 一個集合物件

示例

s1 = {1,2,3,4,5}
s2 = {4,5,6,7,8}
print ("s1: ", s1, "s2: ", s2)
s1.symmetric_difference_update(s2)
print ("s1 after running symmetric difference ", s1)

它將產生以下**輸出**:

s1: {1, 2, 3, 4, 5} s2: {4, 5, 6, 7, 8}
s1 after running symmetric difference {1, 2, 3, 6, 7, 8}

symmetric_difference() 方法

集合類中的 symmetric_difference() 方法類似於 symmetric_difference_update() 方法,不同之處在於它返回一個新的集合物件,該物件包含來自兩個集合的所有元素,減去共同元素。

語法

set.symmetric_difference(obj)

引數

  • obj − 一個集合物件

返回值

symmetric_difference() 方法返回一個新集合,其中只包含兩個集合物件之間不常見的元素。

示例

s1 = {1,2,3,4,5}
s2 = {4,5,6,7,8}
print ("s1: ", s1, "s2: ", s2)
s3 = s1.symmetric_difference(s2)
print ("s1 = s1^s2 ", s3)

它將產生以下**輸出**:

s1: {1, 2, 3, 4, 5} s2: {4, 5, 6, 7, 8}
s1 = s1^s2 {1, 2, 3, 6, 7, 8}

Python - 遍歷集合

Python 中的集合既不是序列,也不是對映型別類。因此,集合中的物件不能用索引或鍵來遍歷。但是,您可以使用for迴圈遍歷集合中的每個元素。

示例1

以下示例演示瞭如何使用for迴圈遍歷集合:

langs = {"C", "C++", "Java", "Python"}
for lang in langs:
   print (lang)

它將產生以下**輸出**:

C
Python
C++
Java

示例2

以下示例演示瞭如何在一個集合的元素上執行for迴圈,並使用集合類的add()方法新增到另一個集合中。

s1={1,2,3,4,5}
s2={4,5,6,7,8}
for x in s2:
   s1.add(x)
print (s1)

它將產生以下**輸出**:

{1, 2, 3, 4, 5, 6, 7, 8}

Python - 合併集合

在 Python 中,集合是有序的專案集合。專案可能屬於不同型別。但是,集合中的專案必須是不可變物件。這意味著我們只能在集合中包含數字、字串和元組,而不能包含列表。Python 的集合類有不同的規定來連線集合物件。

使用 "|" 運算子

"|" 符號(管道)定義為並集運算子。它執行 A∪B 操作,並返回 A、B 或兩者中都存在的元素的集合。集合不允許重複元素。

s1={1,2,3,4,5}
s2={4,5,6,7,8}
s3 = s1|s2
print (s3)

它將產生以下**輸出**:

{1, 2, 3, 4, 5, 6, 7, 8}

使用 union() 方法

集合類具有 union() 方法,該方法執行與 | 運算子相同的操作。它返回一個包含兩個集合中所有元素的集合物件,並丟棄重複項。

s1={1,2,3,4,5}
s2={4,5,6,7,8}
s3 = s1.union(s2)
print (s3)

使用 update() 方法

update() 方法也連線兩個集合,如同 union() 方法。但是它不返回新的集合物件。而是將第二個集合的元素新增到第一個集合中,不允許重複。

s1={1,2,3,4,5}
s2={4,5,6,7,8}
s1.update(s2)
print (s1)

使用解包運算子

在 Python 中,"*" 符號用作解包運算子。解包運算子在內部將集合中的每個元素分配給一個單獨的變數。

s1={1,2,3,4,5}
s2={4,5,6,7,8}
s3 = {*s1, *s2}
print (s3)

Python - 複製集合

集合類中的 copy() 方法建立集合物件的淺複製。

語法

set.copy()

返回值

copy() 方法返回一個新的集合,它是現有集合的淺複製。

示例

lang1 = {"C", "C++", "Java", "Python"}
print ("lang1: ", lang1, "id(lang1): ", id(lang1))
lang2 = lang1.copy()
print ("lang2: ", lang2, "id(lang2): ", id(lang2))
lang1.add("PHP")
print ("After updating lang1")
print ("lang1: ", lang1, "id(lang1): ", id(lang1))
print ("lang2: ", lang2, "id(lang2): ", id(lang2))

輸出

lang1: {'Python', 'Java', 'C', 'C++'} id(lang1): 2451578196864
lang2: {'Python', 'Java', 'C', 'C++'} id(lang2): 2451578197312
After updating lang1
lang1: {'Python', 'C', 'C++', 'PHP', 'Java'} id(lang1): 2451578196864
lang2: {'Python', 'Java', 'C', 'C++'} id(lang2): 2451578197312

Python - 集合運算子

在數學的集合論中,定義了並集、交集、差集和對稱差集運算。Python 使用以下運算子實現它們:

並集運算子 (|)

兩個集合的並集是一個包含存在於 A 或 B 或兩者中的所有元素的集合。例如:

{1,2}∪{2,3}={1,2,3}

下圖說明了兩個集合的並集。

Union Of Two Sets

Python 使用 "|" 符號作為並集運算子。以下示例使用 "|" 運算子並返回兩個集合的並集。

示例

s1 = {1,2,3,4,5}
s2 = {4,5,6,7,8}
s3 = s1 | s2
print ("Union of s1 and s2: ", s3)

它將產生以下**輸出**:

Union of s1 and s2: {1, 2, 3, 4, 5, 6, 7, 8}

交集運算子 (&)

兩個集合 AA 和 BB 的交集,用 A∩B 表示,由 A 和 B 中都存在的元素組成。例如:

{1,2}∩{2,3}={2}

下圖說明了兩個集合的交集。

Intersection Operator

Python 使用 "&" 符號作為交集運算子。以下示例使用 & 運算子並返回兩個集合的交集。

s1 = {1,2,3,4,5}
s2 = {4,5,6,7,8}
s3 = s1 & s2
print ("Intersection of s1 and s2: ", s3)

它將產生以下**輸出**:

Intersection of s1 and s2: {4, 5}

差集運算子 (-)

差集(減法)定義如下。集合 A−B 由存在於 A 但不存在於 B 中的元素組成。例如:

If A={1,2,3} and B={3,5}, then A−B={1,2}

下圖說明了兩個集合的差集:

difference_operator

Python 使用 "-" 符號作為差集運算子。

示例

以下示例使用 "-" 運算子並返回兩個集合的差集。

s1 = {1,2,3,4,5}
s2 = {4,5,6,7,8}
s3 = s1 - s2
print ("Difference of s1 - s2: ", s3)
s3 = s2 - s1
print ("Difference of s2 - s1: ", s3)

它將產生以下**輸出**:

Difference of s1 - s2: {1, 2, 3}
Difference of s2 - s1: {8, 6, 7}

請注意,“s1-s2”與“s2-s1”不同。

對稱差集運算子

A 和 B 的對稱差用“A Δ B”表示,定義為:

A Δ B = (A − B) ⋃ (B − A)

如果 A = {1, 2, 3, 4, 5, 6, 7, 8} 且 B = {1, 3, 5, 6, 7, 8, 9},則 A Δ B = {2, 4, 9}。

下圖說明了兩個集合之間的對稱差:

Symmetric Difference

Python 使用 "^" 符號作為對稱差運算子。

示例

以下示例使用 "^" 運算子並返回兩個集合的對稱差。

s1 = {1,2,3,4,5}
s2 = {4,5,6,7,8}
s3 = s1 - s2
print ("Difference of s1 - s2: ", s3)
s3 = s2 - s1
print ("Difference of s2 - s1: ", s3)
s3 = s1 ^ s2
print ("Symmetric Difference in s1 and s2: ", s3)

它將產生以下**輸出**:

Difference of s1 - s2: {1, 2, 3}
Difference of s2 - s1: {8, 6, 7}
Symmetric Difference in s1 and s2: {1, 2, 3, 6, 7, 8}

Python - 集合方法

Python 的集合類中定義了以下方法:

序號 方法和描述
1

add()

向集合中新增元素。

2

clear()

刪除集合中的所有元素。

3

copy()

返回集合的淺複製。

4

difference()

將兩個或多個集合的差集作為新集合返回。

5

difference_update()

從集合中刪除另一個集合的所有元素。

6

discard()

如果元素是集合的成員,則將其從集合中刪除。

7

intersection()

將兩個集合的交集作為新集合返回。

8

intersection_update()

使用自身與另一個集合的交集更新集合。

9

isdisjoint()

如果兩個集合的交集為空,則返回 True。

10

issubset()

如果另一個集合包含此集合,則返回 True。

11

issuperset()

如果此集合包含另一個集合,則返回 True。

12

pop()

刪除並返回集合中的任意元素。

13

remove()

從集合中刪除元素;它必須是成員。

14

symmetric_difference()

將兩個集合的對稱差集作為新集合返回。

15

symmetric_difference_update()

使用自身與另一個集合的對稱差集更新集合。

16

union()

將集合的並集作為新集合返回。

17

update()

使用自身與其他集合的並集更新集合。

Python - 集合練習

示例1

Python 程式,用於藉助集合運算查詢兩個列表中的公共元素:

l1=[1,2,3,4,5]
l2=[4,5,6,7,8]
s1=set(l1)
s2=set(l2)
commons = s1&s2 # or s1.intersection(s2)
commonlist = list(commons)
print (commonlist)

它將產生以下**輸出**:

[4, 5]

示例2

Python 程式,用於檢查集合是否為另一個集合的子集:

s1={1,2,3,4,5}
s2={4,5}
if s2.issubset(s1):
   print ("s2 is a subset of s1")
else:
   print ("s2 is not a subset of s1")

它將產生以下**輸出**:

s2 is a subset of s1

示例3

Python 程式,用於獲取列表中唯一元素的列表:

T1 = (1, 9, 1, 6, 3, 4, 5, 1, 1, 2, 5, 6, 7, 8, 9, 2)
s1 = set(T1)
print (s1)

它將產生以下**輸出**:

{1, 2, 3, 4, 5, 6, 7, 8, 9}

練習程式

  • Python 程式,用於查詢集合物件的尺寸。

  • Python 程式,用於基於奇數/偶數將集合分成兩部分。

  • Python 程式,用於從集合中刪除所有負數。

  • Python 程式,用於使用集合中每個數字的絕對值構建另一個集合。

  • Python 程式,用於從包含不同型別元素的集合中刪除所有字串。

Python - 字典

字典是 Python 中的內建資料型別之一。Python 的字典是對映型別的示例。對映物件將一個物件的 value 與另一個物件對映。

在語言字典中,我們有單詞和相應含義的配對。配對的兩個部分是鍵(單詞)和值(含義)。類似地,Python 字典也是鍵值對的集合。這些對用逗號分隔,並放在花括號 {} 中。

為了建立鍵和值之間的對映,冒號 ":" 符號放在兩者之間。

以下是一些 Python 字典物件的示例:

capitals = {"Maharashtra":"Mumbai", "Gujarat":"Gandhinagar", "Telangana":"Hyderabad", "Karnataka":"Bengaluru"}
numbers = {10:"Ten", 20:"Twenty", 30:"Thirty",40:"Forty"}
marks = {"Savita":67, "Imtiaz":88, "Laxman":91, "David":49}

示例1

只有數字、字串或元組可以用作鍵。它們都是不可變的。您可以使用任何型別的物件作為值。因此,以下字典定義也是有效的:

d1 = {"Fruit":["Mango","Banana"], "Flower":["Rose", "Lotus"]}
d2 = {('India, USA'):'Countries', ('New Delhi', 'New York'):'Capitals'}
print (d1)
print (d2)

它將產生以下**輸出**:

{'Fruit': ['Mango', 'Banana'], 'Flower': ['Rose', 'Lotus']}
{'India, USA': 'Countries', ('New Delhi', 'New York'): 'Capitals'}

示例2

Python 不接受列表之類的可變物件作為鍵,並引發 TypeError。

d1 = {["Mango","Banana"]:"Fruit", "Flower":["Rose", "Lotus"]}
print (d1)

這將引發 TypeError:

Traceback (most recent call last):
   File "C:\Users\Sairam\PycharmProjects\pythonProject\main.py", line 8, in <module>
d1 = {["Mango","Banana"]:"Fruit", "Flower":["Rose", "Lotus"]}
     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: unhashable type: 'list'

示例3

您可以為字典中的多個鍵賦值,但鍵在一個字典中不能出現多次。

d1 = {"Banana":"Fruit", "Rose":"Flower", "Lotus":"Flower", "Mango":"Fruit"}
d2 = {"Fruit":"Banana","Flower":"Rose", "Fruit":"Mango", "Flower":"Lotus"}
print (d1)
print (d2)

它將產生以下**輸出**:

{'Banana': 'Fruit', 'Rose': 'Flower', 'Lotus': 'Flower', 'Mango': 'Fruit'}
{'Fruit': 'Mango', 'Flower': 'Lotus'}

Python 字典運算子

在 Python 中,定義了以下運算子與字典運算元一起使用。在示例中,使用了以下字典物件。

d1 = {'a': 2, 'b': 4, 'c': 30}
d2 = {'a1': 20, 'b1': 40, 'c1': 60}
運算子 描述 示例
dict[key] 提取/分配與鍵對映的值 print (d1['b']) 檢索 4

d1['b'] = 'Z' 為鍵 'b' 分配新值

dict1|dict2 兩個字典物件的並集,返回新物件 d3=d1|d2 ; print (d3)

{'a': 2, 'b': 4, 'c': 30, 'a1': 20, 'b1': 40, 'c1': 60}

dict1|=dict2 增強的字典並集運算子 d1|=d2; print (d1)

{'a': 2, 'b': 4, 'c': 30, 'a1': 20, 'b1': 40, 'c1': 60}

Python - 訪問字典元素

使用 "[ ]" 運算子

Python中的字典不是序列,因為字典中的元素沒有索引。但是,您仍然可以使用方括號“[ ]”運算子來獲取與字典物件中某個鍵關聯的值。

示例1

capitals = {"Maharashtra":"Mumbai", "Gujarat":"Gandhinagar", "Telangana":"Hyderabad", "Karnataka":"Bengaluru"}
print ("Capital of Gujarat is : ", capitals['Gujarat'])
print ("Capital of Karnataka is : ", capitals['Karnataka'])

它將產生以下**輸出**:

Capital of Gujarat is: Gandhinagar
Capital of Karnataka is: Bengaluru

示例2

如果方括號內給出的鍵不存在於字典物件中,Python會引發KeyError。

capitals = {"Maharashtra":"Mumbai", "Gujarat":"Gandhinagar", "Telangana":"Hyderabad", "Karnataka":"Bengaluru"}
print ("Captial of Haryana is : ", capitals['Haryana'])

它將產生以下**輸出**:

   print ("Captial of Haryana is : ", capitals['Haryana'])
                                      ~~~~~~~~^^^^^^^^^^^
KeyError: 'Haryana'

使用get()方法

Python的dict類中的get()方法返回對映到給定鍵的值。

語法

Val = dict.get("key")

引數

  • − 用作字典物件中鍵的不可變物件

返回值

get()方法返回使用給定鍵對映的物件。

示例3

capitals = {"Maharashtra":"Mumbai", "Gujarat":"Gandhinagar", "Telangana":"Hyderabad", "Karnataka":"Bengaluru"}
print ("Capital of Gujarat is: ", capitals.get('Gujarat'))
print ("Capital of Karnataka is: ", capitals.get('Karnataka'))

它將產生以下**輸出**:

Capital of Gujarat is: Gandhinagar
Capital of Karnataka is: Bengaluru

示例 4

與“[ ]”運算子不同,如果找不到鍵,get()方法不會引發錯誤;它返回None。

capitals = {"Maharashtra":"Mumbai", "Gujarat":"Gandhinagar", "Telangana":"Hyderabad", "Karnataka":"Bengaluru"}
print ("Capital of Haryana is : ", capitals.get('Haryana'))

它將產生以下**輸出**:

Capital of Haryana is : None

示例5

get()方法接受一個可選的字串引數。如果給出該引數,並且找不到鍵,則該字串將成為返回值。

capitals = {"Maharashtra":"Mumbai", "Gujarat":"Gandhinagar", "Telangana":"Hyderabad", "Karnataka":"Bengaluru"}
print ("Capital of Haryana is : ", capitals.get('Haryana', 'Not found'))

它將產生以下**輸出**:

Capital of Haryana is: Not found

Python - 修改字典元素

除了字典的字面表示法(我們將逗號分隔的鍵:值對放在花括號中),我們還可以使用內建的dict()函式建立字典物件。

空字典

在不帶任何引數的情況下使用dict()函式會建立一個空字典物件。這等同於在花括號之間不放置任何內容。

示例

d1 = dict()
d2 = {}
print ('d1: ', d1)
print ('d2: ', d2)

它將產生以下**輸出**:

d1: {}
d2: {}

來自元組列表的字典

dict()函式從由兩項元組組成的列表或元組構造字典。元組中的第一項被視為鍵,第二項被視為其值。

示例

d1=dict([('a', 100), ('b', 200)])
d2 = dict((('a', 'one'), ('b', 'two')))
print ('d1: ', d1)
print ('d2: ', d2)

它將產生以下**輸出**:

d1: {'a': 100, 'b': 200}
d2: {'a': 'one', 'b': 'two'}

來自關鍵字引數的字典

dict()函式可以接受任意數量的鍵值對形式的關鍵字引數。它返回一個字典物件,其中名稱作為鍵,並將其關聯到值。

示例

d1=dict(a= 100, b=200)
d2 = dict(a='one', b='two')
print ('d1: ', d1)
print ('d2: ', d2)

它將產生以下**輸出**:

d1: {'a': 100, 'b': 200}
d2: {'a': 'one', 'b': 'two'}

Python - 新增字典元素

使用運算子

“[ ]”運算子(用於訪問對映到字典鍵的值)用於更新現有鍵值對以及新增新鍵值對。

語法

dict["key"] = val

如果鍵已存在於字典物件中,則其值將更新為val。如果鍵不存在於字典中,則會新增一個新的鍵值對。

示例

在此示例中,“Laxman”的分數更新為95。

marks = {"Savita":67, "Imtiaz":88, "Laxman":91, "David":49}
print ("marks dictionary before update: ", marks)
marks['Laxman'] = 95
print ("marks dictionary after update: ", marks)

它將產生以下**輸出**:

marks dictionary before update: {'Savita': 67, 'Imtiaz': 88, 'Laxman': 91, 'David': 49}
marks dictionary after update: {'Savita': 67, 'Imtiaz': 88, 'Laxman': 95, 'David': 49}

示例

但是,字典中沒有以'Krishnan'作為鍵的項,因此添加了一個新的鍵值對。

marks = {"Savita":67, "Imtiaz":88, "Laxman":91, "David":49}
print ("marks dictionary before update: ", marks)
marks['Krishan'] = 74
print ("marks dictionary after update: ", marks)

它將產生以下**輸出**:

marks dictionary before update: {'Savita': 67, 'Imtiaz': 88, 'Laxman': 91, 'David': 49}
marks dictionary after update: {'Savita': 67, 'Imtiaz': 88, 'Laxman': 91, 'David': 49, 'Krishan': 74}

使用 update() 方法

您可以透過三種不同的方式使用dict類中的update()方法

使用另一個字典更新

在這種情況下,update()方法的引數是另一個字典。兩個字典中共有鍵的值將被更新。對於新鍵,將在現有字典中新增鍵值對。

語法

d1.update(d2)

返回值

現有字典已更新,並向其中添加了新的鍵值對。

示例

marks = {"Savita":67, "Imtiaz":88, "Laxman":91, "David":49}
print ("marks dictionary before update: \n", marks)
marks1 = {"Sharad": 51, "Mushtaq": 61, "Laxman": 89}
marks.update(marks1)
print ("marks dictionary after update: \n", marks)

它將產生以下**輸出**:

marks dictionary before update:
{'Savita': 67, 'Imtiaz': 88, 'Laxman': 91, 'David': 49}
marks dictionary after update:
{'Savita': 67, 'Imtiaz': 88, 'Laxman': 89, 'David': 49, 'Sharad': 51, 'Mushtaq': 61}

使用可迭代物件更新

如果update()方法的引數是由兩項元組組成的列表或元組,則會為現有字典中的每一項新增一項,如果鍵已存在則更新。

語法

d1.update([(k1, v1), (k2, v2)])

返回值

現有字典已更新,並添加了新的鍵。

示例

marks = {"Savita":67, "Imtiaz":88, "Laxman":91, "David":49}
print ("marks dictionary before update: \n", marks)
marks1 = [("Sharad", 51), ("Mushtaq", 61), ("Laxman", 89)]
marks.update(marks1)
print ("marks dictionary after update: \n", marks)

它將產生以下**輸出**:

marks dictionary before update:
 {'Savita': 67, 'Imtiaz': 88, 'Laxman': 91, 'David': 49}
marks dictionary after update:
 {'Savita': 67, 'Imtiaz': 88, 'Laxman': 89, 'David': 49, 'Sharad': 51, 'Mushtaq': 61}

使用關鍵字引數更新

update()方法的第三個版本接受name=value格式的關鍵字引數列表。將新增新的鍵值對,或更新現有鍵的值。

語法

d1.update(k1=v1, k2=v2)

返回值

現有字典已更新,並添加了新的鍵值對。

示例

marks = {"Savita":67, "Imtiaz":88, "Laxman":91, "David":49}
print ("marks dictionary before update: \n", marks)
marks.update(Sharad = 51, Mushtaq = 61, Laxman = 89)
print ("marks dictionary after update: \n", marks)

它將產生以下**輸出**:

marks dictionary before update:
 {'Savita': 67, 'Imtiaz': 88, 'Laxman': 91, 'David': 49}
marks dictionary after update:
 {'Savita': 67, 'Imtiaz': 88, 'Laxman': 89, 'David': 49, 'Sharad': 51, 'Mushtaq': 61}

使用解包運算子

字典物件字首的“**”符號將其解包成一個元組列表,每個元組包含鍵和值。兩個dict物件被解包併合並在一起,得到一個新的字典。

語法

d3 = {**d1, **d2}

返回值

兩個字典合併,並返回一個新的物件。

示例

marks = {"Savita":67, "Imtiaz":88, "Laxman":91, "David":49}
print ("marks dictionary before update: \n", marks)
marks1 = {"Sharad": 51, "Mushtaq": 61, "Laxman": 89}
newmarks = {**marks, **marks1}
print ("marks dictionary after update: \n", newmarks)

它將產生以下**輸出**:

marks dictionary before update:
 {'Savita': 67, 'Imtiaz': 88, 'Laxman': 91, 'David': 49}
marks dictionary after update:
 {'Savita': 67, 'Imtiaz': 88, 'Laxman': 89, 'David': 49, 'Sharad': 51, 'Mushtaq': 61}

使用並集運算子 (|)

Python 引入 "|" (管道符號)作為字典運算元的並集運算子。它更新左側 dict 物件中現有的鍵,並新增新的鍵值對以返回一個新的 dict 物件。

語法

d3 = d1 | d2

返回值

並集運算子在合併兩個 dict 運算元後返回一個新的 dict 物件

示例

marks = {"Savita":67, "Imtiaz":88, "Laxman":91, "David":49}
print ("marks dictionary before update: \n", marks)
marks1 = {"Sharad": 51, "Mushtaq": 61, "Laxman": 89}
newmarks = marks | marks1
print ("marks dictionary after update: \n", newmarks)

它將產生以下**輸出**:

marks dictionary before update:
 {'Savita': 67, 'Imtiaz': 88, 'Laxman': 91, 'David': 49}
marks dictionary after update:
 {'Savita': 67, 'Imtiaz': 88, 'Laxman': 89, 'David': 49, 'Sharad': 51, 'Mushtaq': 61}

使用 "|=" 運算子

"|=" 運算子是增強的並集運算子。它透過在右側運算元中新增新鍵並更新現有鍵來對左側的字典運算元進行就地更新。

語法

d1 |= d2

示例

marks = {"Savita":67, "Imtiaz":88, "Laxman":91, "David":49}
print ("marks dictionary before update: \n", marks)
marks1 = {"Sharad": 51, "Mushtaq": 61, "Laxman": 89}
marks |= marks1
print ("marks dictionary after update: \n", marks)

它將產生以下**輸出**:

marks dictionary before update:
 {'Savita': 67, 'Imtiaz': 88, 'Laxman': 91, 'David': 49}
marks dictionary after update:
 {'Savita': 67, 'Imtiaz': 88, 'Laxman': 89, 'David': 49, 'Sharad': 51, 'Mushtaq': 61}

Python - 刪除字典元素

使用del關鍵字

Python 的del關鍵字從記憶體中刪除任何物件。在這裡,我們使用它來刪除字典中的鍵值對。

語法

del dict['key']

示例

numbers = {10:"Ten", 20:"Twenty", 30:"Thirty",40:"Forty"}
print ("numbers dictionary before delete operation: \n", numbers)
del numbers[20]
print ("numbers dictionary before delete operation: \n", numbers)

它將產生以下**輸出**:

numbers dictionary before delete operation:
 {10: 'Ten', 20: 'Twenty', 30: 'Thirty', 40: 'Forty'}
numbers dictionary before delete operation:
 {10: 'Ten', 30: 'Thirty', 40: 'Forty'}

示例

使用dict物件本身的del關鍵字將其從記憶體中刪除。

numbers = {10:"Ten", 20:"Twenty", 30:"Thirty",40:"Forty"}
print ("numbers dictionary before delete operation: \n", numbers)
del numbers
print ("numbers dictionary before delete operation: \n", numbers)

它將產生以下**輸出**:

numbers dictionary before delete operation:
 {10: 'Ten', 20: 'Twenty', 30: 'Thirty', 40: 'Forty'}
Traceback (most recent call last):
 File "C:\Users\mlath\examples\main.py", line 5, in <module>
  print ("numbers dictionary before delete operation: \n", numbers)
                                                           ^^^^^^^
NameError: name 'numbers' is not defined

使用pop()方法

dict類的pop()方法導致從字典中刪除具有指定鍵的元素。

語法

val = dict.pop(key)

返回值

pop()方法在刪除鍵值對後返回指定鍵的值。

示例

numbers = {10:"Ten", 20:"Twenty", 30:"Thirty",40:"Forty"}
print ("numbers dictionary before pop operation: \n", numbers)
val = numbers.pop(20)
print ("nubvers dictionary after pop operation: \n", numbers)
print ("Value popped: ", val)

它將產生以下**輸出**:

numbers dictionary before pop operation: 
 {10: 'Ten', 20: 'Twenty', 30: 'Thirty', 40: 'Forty'}
nubvers dictionary after pop operation: 
 {10: 'Ten', 30: 'Thirty', 40: 'Forty'}
Value popped:  Twenty

使用popitem()方法

dict()類中的popitem()方法不接受任何引數。它彈出最後插入的鍵值對,並將其作為元組返回。

語法

val = dict.popitem()

返回值

popitem()方法返回一個包含從字典中刪除的項的鍵和值的元組。

示例

numbers = {10:"Ten", 20:"Twenty", 30:"Thirty",40:"Forty"}
print ("numbers dictionary before pop operation: \n", numbers)
val = numbers.popitem()
print ("numbers dictionary after pop operation: \n", numbers)
print ("Value popped: ", val)

它將產生以下**輸出**:

numbers dictionary before pop operation: 
 {10: 'Ten', 20: 'Twenty', 30: 'Thirty', 40: 'Forty'}
numbers dictionary after pop operation: 
 {10: 'Ten', 20: 'Twenty', 30: 'Thirty'}
Value popped:  (40, 'Forty')

使用clear()方法

dict類中的clear()方法刪除字典物件中的所有元素,並返回一個空物件。

語法

dict.clear()

示例

numbers = {10:"Ten", 20:"Twenty", 30:"Thirty",40:"Forty"}
print ("numbers dictionary before clear method: \n", numbers)
numbers.clear()
print ("numbers dictionary after clear method: \n", numbers)

它將產生以下**輸出**:

numbers dictionary before clear method: 
 {10: 'Ten', 20: 'Twenty', 30: 'Thirty', 40: 'Forty'}
numbers dictionary after clear method: 
 {}

Python - 字典檢視物件

dict類的items()、keys()和values()方法返回檢視物件。每當其源字典物件的內容發生任何更改時,這些檢視都會動態重新整理。

items()方法

items()方法返回一個dict_items檢視物件。它包含一個元組列表,每個元組由相應的鍵值對組成。

語法

Obj = dict.items()

返回值

items()方法返回dict_items物件,它是(鍵,值)元組的動態檢視。

示例

在下面的示例中,我們首先使用items()方法獲得dict_items()物件,並在更新字典物件時檢查它是如何動態更新的。

numbers = {10:"Ten", 20:"Twenty", 30:"Thirty",40:"Forty"}
obj = numbers.items()
print ('type of obj: ', type(obj))
print (obj)
print ("update numbers dictionary")
numbers.update({50:"Fifty"})
print ("View automatically updated")
print (obj)

它將產生以下**輸出**:

type of obj: <class 'dict_items'>
dict_items([(10, 'Ten'), (20, 'Twenty'), (30, 'Thirty'), (40, 'Forty')])
update numbers dictionary
View automatically updated
dict_items([(10, 'Ten'), (20, 'Twenty'), (30, 'Thirty'), (40, 'Forty'), (50, 'Fifty')])

keys()方法

dict類的keys()方法返回dict_keys物件,它是在字典中定義的所有鍵的列表。它是一個檢視物件,因為每當對字典物件執行任何更新操作時,它都會自動更新。

語法

Obj = dict.keys()

返回值

keys()方法返回dict_keys物件,它是字典中鍵的檢視。

示例

numbers = {10:"Ten", 20:"Twenty", 30:"Thirty",40:"Forty"}
obj = numbers.keys()
print ('type of obj: ', type(obj))
print (obj)
print ("update numbers dictionary")
numbers.update({50:"Fifty"})
print ("View automatically updated")
print (obj)

它將產生以下**輸出**:

type of obj: <class 'dict_keys'>
dict_keys([10, 20, 30, 40])
update numbers dictionary
View automatically updated
dict_keys([10, 20, 30, 40, 50])

values()方法

values()方法返回字典中所有值的檢視。該物件是dict_value型別,會自動更新。

語法

Obj = dict.values()

返回值

values()方法返回字典中所有值的dict_values檢視。

示例

numbers = {10:"Ten", 20:"Twenty", 30:"Thirty",40:"Forty"}
obj = numbers.values()
print ('type of obj: ', type(obj))
print (obj)
print ("update numbers dictionary")
numbers.update({50:"Fifty"})
print ("View automatically updated")
print (obj)

它將產生以下**輸出**:

type of obj: <class 'dict_values'>
dict_values(['Ten', 'Twenty', 'Thirty', 'Forty'])
update numbers dictionary
View automatically updated
dict_values(['Ten', 'Twenty', 'Thirty', 'Forty', 'Fifty'])

Python - 遍歷字典

與列表、元組或字串不同,Python 中的字典資料型別不是序列,因為專案沒有位置索引。但是,仍然可以使用不同的技術遍歷字典。

示例1

在字典物件上執行簡單的for 迴圈會遍歷其中使用的鍵。

numbers = {10:"Ten", 20:"Twenty", 30:"Thirty",40:"Forty"}
for x in numbers:
   print (x)

它將產生以下**輸出**:

10
20
30
40

示例2

一旦能夠獲取鍵,就可以使用方括號運算子或get()方法輕鬆訪問其關聯的值。

numbers = {10:"Ten", 20:"Twenty", 30:"Thirty",40:"Forty"}
for x in numbers:
   print (x,":",numbers[x])

它將產生以下**輸出**:

10 : Ten
20 : Twenty
30 : Thirty
40 : Forty

dict 類的 items()、keys() 和 values() 方法分別返回檢視物件 dict_items、dict_keys 和 dict_values。這些物件是迭代器,因此我們可以在其上執行 for 迴圈。

示例3

dict_items物件是鍵值元組的列表,可以對其執行for迴圈,如下所示

numbers = {10:"Ten", 20:"Twenty", 30:"Thirty",40:"Forty"}
for x in numbers.items():
   print (x)

它將產生以下**輸出**:

(10, 'Ten')
(20, 'Twenty')
(30, 'Thirty')
(40, 'Forty')

這裡,“x”是來自dict_items迭代器的元組元素。我們可以進一步將這個元組解包到兩個不同的變數中。

示例 4

numbers = {10:"Ten", 20:"Twenty", 30:"Thirty",40:"Forty"}
for x,y in numbers.items():
   print (x,":", y)

它將產生以下**輸出**:

10 : Ten
20 : Twenty
30 : Thirty
40 : Forty

示例5

類似地,可以迭代dict_keys物件中的鍵集合。

numbers = {10:"Ten", 20:"Twenty", 30:"Thirty",40:"Forty"}
for x in numbers.keys():
   print (x, ":", numbers[x])

dict_keys和dict_values中各自的鍵和值位於相同的索引處。在下面的示例中,我們有一個for迴圈,它從0執行到dict的長度,並將迴圈變數用作索引並列印鍵及其對應的值。

示例6

numbers = {10:"Ten", 20:"Twenty", 30:"Thirty",40:"Forty"}
l = len(numbers)
for x in range(l):
   print (list(numbers.keys())[x], ":", list(numbers.values())[x])

以上兩個程式碼片段產生相同的輸出

10 : Ten
20 : Twenty
30 : Thirty
40 : Forty

Python - 複製字典

由於Python中的變數僅僅是記憶體中物件的標籤或引用,因此簡單的賦值運算子不會建立物件的副本。

示例1

在此示例中,我們有一個字典“d1”,我們將其賦值給另一個變數“d2”。如果更新“d1”,則更改也會反映在“d2”中。

d1 = {"a":11, "b":22, "c":33}
d2 = d1
print ("id:", id(d1), "dict: ",d1)
print ("id:", id(d2), "dict: ",d2)

d1["b"] = 100
print ("id:", id(d1), "dict: ",d1)
print ("id:", id(d2), "dict: ",d2)

輸出

id: 2215278891200 dict: {'a': 11, 'b': 22, 'c': 33}
id: 2215278891200 dict: {'a': 11, 'b': 22, 'c': 33}
id: 2215278891200 dict: {'a': 11, 'b': 100, 'c': 33}
id: 2215278891200 dict: {'a': 11, 'b': 100, 'c': 33}

為避免這種情況,並建立字典的淺複製,請使用copy()方法而不是賦值。

示例2

d1 = {"a":11, "b":22, "c":33}
d2 = d1.copy()
print ("id:", id(d1), "dict: ",d1)
print ("id:", id(d2), "dict: ",d2)
d1["b"] = 100
print ("id:", id(d1), "dict: ",d1)
print ("id:", id(d2), "dict: ",d2)

輸出

當更新“d1”時,“d2”現在不會更改,因為“d2”是字典物件的副本,而不僅僅是引用。

id: 1586671734976 dict: {'a': 11, 'b': 22, 'c': 33}
id: 1586673973632 dict: {'a': 11, 'b': 22, 'c': 33}
id: 1586671734976 dict: {'a': 11, 'b': 100, 'c': 33}
id: 1586673973632 dict: {'a': 11, 'b': 22, 'c': 33}

Python - 巢狀字典

如果一個或多個鍵的值是另一個字典,則稱Python字典具有巢狀結構。巢狀字典通常用於儲存複雜的資料結構。

下面的程式碼片段表示一個巢狀字典

marklist = {
   "Mahesh" : {"Phy" : 60, "maths" : 70},
   "Madhavi" : {"phy" : 75, "maths" : 68},
   "Mitchell" : {"phy" : 67, "maths" : 71}
}

示例1

您還可以構成一個for迴圈來遍歷巢狀字典,就像在上一節中一樣。

marklist = {
   "Mahesh" : {"Phy" : 60, "maths" : 70},
   "Madhavi" : {"phy" : 75, "maths" : 68},
   "Mitchell" : {"phy" : 67, "maths" : 71}
}
for k,v in marklist.items():
   print (k, ":", v)

它將產生以下**輸出**:

Mahesh : {'Phy': 60, 'maths': 70}
Madhavi : {'phy': 75, 'maths': 68}
Mitchell : {'phy': 67, 'maths': 71}

示例2

可以使用[]表示法或get()方法訪問內部字典中的值。

print (marklist.get("Madhavi")['maths'])
obj=marklist['Mahesh']
print (obj.get('Phy'))
print (marklist['Mitchell'].get('maths'))

它將產生以下**輸出**:

68
60
71

Python - 字典方法

Python中的字典是內建dict類的物件,它定義了以下方法 −

序號 方法和描述
1

dict.clear()

刪除字典dict的所有元素。

2

dict.copy()

返回字典dict的淺複製。

3

dict.fromkeys()

使用seq中的鍵建立一個新字典,並將值設定為value。

4

dict.get(key, default=None)

對於鍵key,返回value,如果key不在字典中則返回default。

5

dict.has_key(key)

如果字典中存在給定的鍵,則返回true,否則返回false。

6

dict.items()

返回dict的(鍵,值)元組對列表。

7

dict.keys()

返回字典dict的鍵列表。

8

dict.pop()

從集合中刪除具有指定鍵的元素

9

dict.popitem()

刪除最後插入的鍵值對

10

dict.setdefault(key, default=None)

類似於get(),但如果key不在dict中,則會設定dict[key]=default。

11

dict.update(dict2)

將字典dict2的鍵值對新增到dict中。

12

dict.values()

返回字典dict的值列表。

Python - 字典練習

示例1

Python程式,透過從給定字典中提取鍵來建立一個新字典。

d1 = {"one":11, "two":22, "three":33, "four":44, "five":55}
keys = ['two', 'five']
d2={}
for k in keys:
   d2[k]=d1[k]
print (d2)

它將產生以下**輸出**:

{'two': 22, 'five': 55}

示例2

Python程式,將字典轉換為(k,v)元組列表。

d1 = {"one":11, "two":22, "three":33, "four":44, "five":55}
L1 = list(d1.items())
print (L1)

它將產生以下**輸出**:

[('one', 11), ('two', 22), ('three', 33), ('four', 44), ('five', 55)]

示例3

Python程式,刪除字典中具有相同值的鍵。

d1 = {"one":"eleven", "2":2, "three":3, "11":"eleven", "four":44, "two":2}
vals = list(d1.values())#all values
uvals = [v for v in vals if vals.count(v)==1]#unique values
d2 = {}
for k,v in d1.items():
   if v in uvals:
      d = {k:v}
      d2.update(d)
print ("dict with unique value:",d2)

它將產生以下**輸出**:

dict with unique value: {'three': 3, 'four': 44}

練習程式

  • Python程式,按值對字典列表進行排序

  • Python程式,從給定字典中提取每個鍵都具有非數值值的字典。

  • Python程式,根據兩項(k,v)元組列表構建字典。

  • Python程式,使用解包運算符合並兩個字典物件。

Python - 陣列

Python的標準資料型別list、tuplestring是序列。序列物件是專案的排序集合。每個專案都以從零開始的遞增索引為特徵。此外,序列中的專案不必是相同型別。換句話說,列表或元組可能包含不同資料型別的專案。

此功能不同於C或C++中陣列的概念。在C/C++中,陣列也是專案的索引集合,但專案必須是相似的資料型別。在C/C++中,您有整數、浮點數或字串陣列,但您不能有元素一些為整數型別,一些為不同型別的陣列。因此,C/C++陣列是同質的資料型別集合。

Python的標準庫具有array模組。其中的array類允許您構造三種基本型別的陣列:整數、浮點數和Unicode字元。

語法

建立陣列的語法為:

import array
obj = array.array(typecode[, initializer])

引數

  • typecode − 用於建立陣列的typecode字元。

  • initializer − 從可選值初始化的陣列,該值必須是列表、類似位元組的物件或適當型別元素的可迭代物件。

返回型別

array()建構函式返回array.array類的物件

示例

import array as arr

# creating an array with integer type
a = arr.array('i', [1, 2, 3])
print (type(a), a)

# creating an array with char type
a = arr.array('u', 'BAT')
print (type(a), a)

# creating an array with float type
a = arr.array('d', [1.1, 2.2, 3.3])
print (type(a), a)

它將產生以下**輸出**:

<class 'array.array'> array('i', [1, 2, 3])
<class 'array.array'> array('u', 'BAT')
<class 'array.array'> array('d', [1.1, 2.2, 3.3])

陣列是序列型別,其行為與列表非常相似,只是儲存在其中的物件型別受到限制。

Python陣列型別由單個字元Typecode引數決定。型別程式碼和陣列的預期資料型別如下所示:

typecode Python資料型別 位元組大小
'b' 帶符號整數 1
'B' 無符號整數 1
'u' Unicode字元 2
'h' 帶符號整數 2
'H' 無符號整數 2
'i' 帶符號整數 2
'I' 無符號整數 2
'l' 帶符號整數 4
'L' 無符號整數 4
'q' 帶符號整數 8
‘Q’ 無符號整數 8
‘f’ 浮點數 4
‘d’ 浮點數 8

Python - 訪問陣列元素

由於陣列物件的行為非常類似於序列,因此您可以對其執行索引和切片操作。

示例

import array as arr
a = arr.array('i', [1, 2, 3])
#indexing
print (a[1])
#slicing
print (a[1:])

更改陣列項

您可以為陣列中的項賦值,就像為列表中的項賦值一樣。

示例

import array as arr
a = arr.array('i', [1, 2, 3])
a[1] = 20
print (a[1])

這裡,您將得到輸出“20”。但是,Python不允許賦值任何與建立陣列時使用的 typecode 不同的型別的值。以下賦值將引發 TypeError。

import array as arr
a = arr.array('i', [1, 2, 3])
# assignment
a[1] = 'A'

它將產生以下**輸出**:

TypeError: 'str' object cannot be interpreted as an integer

Python - 新增陣列元素

append() 方法

append() 方法在給定陣列的末尾新增一個新元素。

語法

array.append(v)

引數

  • v - 新值新增到陣列的末尾。新值必須與宣告陣列物件時使用的 datatype 引數型別相同。

示例

import array as arr
a = arr.array('i', [1, 2, 3])
a.append(10)
print (a)

它將產生以下**輸出**:

array('i', [1, 2, 3, 10])

insert() 方法

array 類還定義了 insert() 方法。可以在指定的索引處插入一個新元素。

語法

array.insert(i, v)

引數

  • i - 要插入新值的索引。

  • v - 要插入的值。必須是 arraytype 型別。

示例

import array as arr
a = arr.array('i', [1, 2, 3])
a.insert(1,20)
print (a)

它將產生以下**輸出**:

array('i', [1, 20, 2, 3])

extend() 方法

array 類中的 extend() 方法將來自另一個相同 typecode 的陣列的所有元素附加到當前陣列。

語法

array.extend(x)

引數

  • x - array.array 類的物件

示例

import array as arr
a = arr.array('i', [1, 2, 3, 4, 5])
b = arr.array('i', [6,7,8,9,10])
a.extend(b)
print (a)

它將產生以下**輸出**:

array('i', [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])

Python - 刪除陣列元素

array 類定義了兩種方法,我們可以用它們從陣列中刪除元素。它具有 remove() 和 pop() 方法。

array.remove() 方法

remove() 方法刪除陣列中給定值的第一次出現。

語法

array.remove(v)

引數

  • v - 要從陣列中刪除的值

示例

import array as arr
a = arr.array('i', [1, 2, 1, 4, 2])
a.remove(2)
print (a)

它將產生以下**輸出**:

array('i', [1, 1, 4, 2])

array.pop() 方法

pop() 方法刪除陣列中指定索引處的元素,並返回已刪除的元素。

語法

array.pop(i)

引數

  • i - 要刪除的元素的索引。該方法在刪除後返回第 i 個位置的元素。

示例

import array as arr
a = arr.array('i', [1, 2, 1, 4, 2])
a.pop(2)
print (a)

它將產生以下**輸出**:

array('i', [1, 2, 4, 2])

Python - 遍歷陣列

由於陣列物件的行為類似於序列,因此您可以使用for迴圈或while迴圈遍歷其元素。

使用 "for" 迴圈遍歷陣列

請看下面的例子:

import array as arr
a = arr.array('d', [1, 2, 3])
for x in a:
   print (x)

它將產生以下**輸出**:

1.0
2.0
3.0

使用 "while" 迴圈遍歷陣列

以下示例顯示瞭如何使用while迴圈遍歷陣列:

import array as arr
a = arr.array('d', [1, 2, 3])
l = len(a)
idx =0
while idx<l:
   print (a[idx])
   idx+=1

使用陣列索引的 "for" 迴圈

我們可以使用內建的 len() 函式查詢陣列的長度。使用它來建立一個 range 物件以獲取索引序列,然後在for迴圈中訪問陣列元素。

import array as arr
a = arr.array('d', [1, 2, 3])
l = len(a)
for x in range(l):
   print (a[x])

您將獲得與第一個示例相同的輸出。

Python - 複製陣列

Python 的內建序列型別,即列表、元組和字串,是專案的索引集合。但是,與 C/C++、Java 等中的陣列不同,它們不是同構的,這意味著這些型別集合中的元素可以是不同型別的。Python 的 array 模組幫助您建立類似於 Java 陣列的物件。在本章中,我們將討論如何將一個數組物件複製到另一個物件。

Python 陣列可以是字串、整數或浮點型別。array 類建構函式的使用方法如下:

import array
obj = array.array(typecode[, initializer])

typecode 可以是表示資料型別的字元常量。

我們可以使用賦值運算子將一個數組賦值給另一個數組。

a = arr.array('i', [1, 2, 3, 4, 5])
b=a.copy()

但是,這種賦值不會在記憶體中建立新的陣列。在 Python 中,變數只是一個指向記憶體中物件的標籤或引用。因此,a 是陣列的引用,b 也是。檢查 a 和 b 的 id()。相同的 id 值證實簡單的賦值不會建立副本。

import array as arr
a = arr.array('i', [1, 2, 3, 4, 5])
b=a
print (id(a), id(b))

它將產生以下**輸出**:

2771967068656 2771967068656

因為 "a" 和 "b" 指向同一個陣列物件,所以 "a" 的任何更改都會反映在 "b" 中:

a[2]=10
print (a,b)

它將產生以下**輸出**:

array('i', [1, 2, 10, 4, 5]) array('i', [1, 2, 10, 4, 5])

要建立陣列的另一個物理副本,我們使用 Python 庫中的另一個模組,名為 copy,並使用該模組中的 deepcopy() 函式。深複製構造一個新的複合物件,然後遞迴地將原始物件中找到的物件的副本插入到其中。

import array, copy
a = arr.array('i', [1, 2, 3, 4, 5])
import copy
b = copy.deepcopy(a)

現在檢查 "a" 和 "b" 的 id()。你會發現 id 不同。

print (id(a), id(b))

它將產生以下**輸出**:

2771967069936 2771967068976

這證明建立了一個新的物件 "b",它是 "a" 的實際副本。如果我們更改 "a" 中的元素,它不會反映在 "b" 中。

a[2]=10
print (a,b)

它將產生以下**輸出**:

array('i', [1, 2, 10, 4, 5]) array('i', [1, 2, 3, 4, 5])

Python - 反轉陣列

在本章中,我們將探討以索引的反向順序重新排列給定陣列的不同方法。在 Python 中,陣列不是內建資料型別之一。但是,Python 的標準庫具有 array 模組。array 類幫助我們建立一個同構的字串、整數或浮點數型別集合。

建立陣列使用的語法為:

import array
obj = array.array(typecode[, initializer])

讓我們首先建立一個包含幾個int型別物件的陣列:

import array as arr
a = arr.array('i', [10,5,15,4,6,20,9])

array 類沒有任何內建方法來反轉陣列。因此,我們必須使用另一個數組。一個空的陣列 "b" 宣告如下:

b = arr.array('i')

接下來,我們以相反的順序遍歷陣列 "a" 中的數字,並將每個元素附加到 "b" 陣列:

for i in range(len(a)-1, -1, -1):
b.append(a[i])

陣列 "b" 現在包含來自原始陣列的反向順序的數字。

示例1

以下是 Python 中反轉陣列的完整程式碼

import array as arr
a = arr.array('i', [10,5,15,4,6,20,9])
b = arr.array('i')
for i in range(len(a)-1, -1, -1):
   b.append(a[i])
print (a, b)

它將產生以下**輸出**:

array('i', [10, 5, 15, 4, 6, 20, 9]) array('i', [9, 20, 6, 4, 15, 5, 10])

我們還可以使用 list 類中的 reverse() 方法反轉陣列中數字的順序。List 是 Python 中的內建型別。

我們必須首先使用 array 類的 tolist() 方法將陣列的內容傳輸到列表:

a = arr.array('i', [10,5,15,4,6,20,9])
b = a.tolist()

我們現在可以呼叫 reverse() 方法:

b.reverse()

如果我們現在將列表轉換回陣列,我們將得到一個按反向順序排列的陣列。

a = arr.array('i')
a.fromlist(b)

示例2

以下是完整程式碼

from array import array as arr
a = arr.array('i', [10,5,15,4,6,20,9])
b = a.tolist()
b.reverse()
a = arr.array('i')
a.fromlist(b)
print (a)

它將產生以下**輸出**:

array('i', [10, 5, 15, 4, 6, 20, 9])

Python - 排序陣列

Python 的 array 模組定義了 array 類。array 類的一個物件類似於 Java 或 C/C++ 中的陣列。與 Python 的內建序列不同,陣列是字串、整數或浮點物件的同構集合。

array 類沒有任何函式/方法可以對其元素進行排序。但是,我們可以透過以下方法之一實現它:

  • 使用排序演算法

  • 使用 List 的 sort() 方法

  • 使用內建的 sorted() 函式

讓我們詳細討論每種方法。

使用排序演算法

我們將實現經典的氣泡排序演算法來獲得排序後的陣列。為此,我們使用兩個巢狀迴圈並交換元素以按排序順序重新排列。

使用 Python 程式碼編輯器儲存以下程式碼:

import array as arr
a = arr.array('i', [10,5,15,4,6,20,9])
for i in range(0, len(a)):
   for j in range(i+1, len(a)):
      if(a[i] > a[j]):
         temp = a[i];
         a[i] = a[j];
         a[j] = temp;
print (a)

它將產生以下**輸出**:

array('i', [4, 5, 6, 9, 10, 15, 20])

使用 List 的 sort() 方法

即使 array 沒有sort()方法,Python 的內建 List 類確實有一個 sort 方法。我們將在下一個示例中使用它。

首先,宣告一個數組並使用tolist()方法從中獲取一個列表物件:

a = arr.array('i', [10,5,15,4,6,20,9])
b=a.tolist()

我們可以輕鬆地獲得排序後的列表,如下所示:

b.sort()

我們需要做的就是將此列表轉換回陣列物件:

a.fromlist(b)

以下是完整程式碼

from array import array as arr
a = arr.array('i', [10,5,15,4,6,20,9])
b=a.tolist()
b.sort()
a = arr.array('i')
a.fromlist(b)
print (a)

它將產生以下**輸出**:

array('i', [4, 5, 6, 9, 10, 15, 20])

使用內建的 sorted() 函式

對陣列進行排序的第三種技術是使用 sorted() 函式,這是一個內建函式。

sorted() 函式的語法如下:

sorted(iterable, reverse=False)

該函式返回一個新列表,其中包含來自可迭代物件的所有項,按升序排列。將 reverse 引數設定為 True 以獲取項的降序。

sorted() 函式可以與任何可迭代物件一起使用。Python 陣列是可迭代的,因為它是一個索引集合。因此,陣列可以用作 sorted() 函式的引數。

from array import array as arr
a = arr.array('i', [4, 5, 6, 9, 10, 15, 20])
sorted(a)
print (a)

它將產生以下**輸出**:

array('i', [4, 5, 6, 9, 10, 15, 20])

Python - 合併陣列

在 Python 中,陣列是 Python 內建資料型別(例如字串、整數或浮點物件)的同構集合。但是,陣列本身不是內建型別,而是我們需要使用 Python 內建 array 模組中的 array 類。

第一種方法

要連線兩個陣列,我們可以透過將一個數組中的每個專案附加到另一個數組來實現。

這裡有兩個 Python 陣列:

a = arr.array('i', [10,5,15,4,6,20,9])
b = arr.array('i', [2,7,8,11,3,10])

在陣列 "b" 上執行一個for迴圈。從 "b" 中獲取每個數字,並使用以下迴圈語句將其附加到陣列 "a":

for i in range(len(b)):
   a.append(b[i])

陣列 "a" 現在包含來自 "a" 和 "b" 的元素。

以下是完整程式碼

import array as arr
a = arr.array('i', [10,5,15,4,6,20,9])
b = arr.array('i', [2,7,8,11,3,10])
for i in range(len(b)):
   a.append(b[i])
print (a, b)

它將產生以下**輸出**:

array('i', [10, 5, 15, 4, 6, 20, 9, 2, 7, 8, 11, 3, 10])

第二種方法

使用另一種方法連線兩個陣列,首先將陣列轉換為列表物件:

a = arr.array('i', [10,5,15,4,6,20,9])
b = arr.array('i', [2,7,8,11,3,10])
x=a.tolist()
y=b.tolist()

列表物件可以用 '+' 運算子連線。

z=x+y

如果 "z" 列表轉換回陣列,您將得到一個表示已連線陣列的陣列:

a.fromlist(z)

以下是完整程式碼

from array import array as arr
a = arr.array('i', [10,5,15,4,6,20,9])
b = arr.array('i', [2,7,8,11,3,10])
x=a.tolist()
y=b.tolist()
z=x+y
a=arr.array('i')
a.fromlist(z)
print (a)

第三種方法

我們還可以使用 List 類中的 extend() 方法將一個列表中的元素附加到另一個列表。

首先,將陣列轉換為列表,然後呼叫 extend() 方法合併兩個列表:

from array import array as arr
a = arr.array('i', [10,5,15,4,6,20,9])
b = arr.array('i', [2,7,8,11,3,10])
a.extend(b)
print (a)

它將產生以下**輸出**:

array('i', [10, 5, 15, 4, 6, 20, 9, 2, 7, 8, 11, 3, 10])

Python - 陣列方法

array.reverse() 方法

與序列型別一樣,array 類也支援 reverse() 方法,該方法可以按相反順序重新排列元素。

語法

array.reverse()

引數

此方法沒有引數。

示例

import array as arr
a = arr.array('i', [1, 2, 3, 4, 5])
a.reverse()
print (a)

它將產生以下**輸出**:

array('i', [5, 4, 3, 2, 1])

array 類還定義了以下有用的方法。

array.count() 方法

count() 方法返回給定元素在陣列中出現的次數。

語法

array.count(v)

引數

  • v - 要計算其出現次數的值

返回值

count() 方法返回一個整數,對應於 v 在陣列中出現的次數。

示例

import array as arr
a = arr.array('i', [1, 2, 3, 2, 5, 6, 2, 9])
c = a.count(2)
print ("Count of 2:", c)

它將產生以下**輸出**:

Count of 2: 3

array.index() 方法

array 類中的 index() 方法查詢陣列中給定元素第一次出現的 位置。

語法

array.index(v)

引數

  • v - 要查詢其索引的值

示例

a = arr.array('i', [1, 2, 3, 2, 5, 6, 2, 9])
c = a.index(2)
print ("index of 2:", c)

它將產生以下**輸出**:

index of 2: 1

array.fromlist() 方法

fromlist() 方法將 Python 列表中的項附加到陣列物件。

語法

array.fromlist(l)

引數

  • i - 列表,其項附加到陣列。列表中的所有項必須是相同的 arrtype。

示例

import array as arr
a = arr.array('i', [1, 2, 3, 4, 5])
lst = [6, 7, 8, 9, 10]
c = a.fromlist(lst)
print (a)

它將產生以下**輸出**:

array('i', [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])

array.tofile() 方法

array 類中的 tofile() 方法將陣列中的所有項(作為機器值)寫入檔案物件 f。

語法

array.tofile(f)

引數

  • f - 使用 open() 函式獲得的檔案物件。要以 wb 模式開啟的檔案。

示例

import array as arr
f = open('list.txt','wb')
arr.array("i", [10, 20, 30, 40, 50]).tofile(f)
f.close()

輸出

執行上述程式碼後,將在當前目錄中建立一個名為“list.txt”的檔案。

array.fromfile() 方法

fromfile() 方法讀取二進位制檔案並將指定數量的項附加到陣列物件。

語法

array.fromfile(f, n)

引數

  • f - 指向以 rb 模式開啟的磁碟檔案的 File 物件

  • n - 要附加的專案數

示例

import array as arr
a = arr.array('i', [1, 2, 3, 4, 5])
f = open("list.txt", "rb")
a.fromfile(f, 5)
print (a)

它將產生以下**輸出**:

array('i', [1, 2, 3, 4, 5, 10, 20, 30, 40, 50])

Python - 陣列練習

示例1

查詢 Python 陣列中最大數字的 Python 程式:

import array as arr
a = arr.array('i', [10,5,15,4,6,20,9])
print (a)
largest = a[0]
for i in range(1, len(a)):
   if a[i]>largest:
      largest=a[i]
print ("Largest number:", largest)

它將產生以下**輸出**:

array('i', [10, 5, 15, 4, 6, 20, 9])
Largest number: 20

示例2

將 Python 陣列中的所有偶數儲存到另一個數組的 Python 程式:

import array as arr
a = arr.array('i', [10,5,15,4,6,20,9])
print (a)
b = arr.array('i')
for i in range(len(a)):
   if a[i]%2 == 0:
      b.append(a[i])
print ("Even numbers:", b)

它將產生以下**輸出**:

array('i', [10, 5, 15, 4, 6, 20, 9])
Even numbers: array('i', [10, 4, 6, 20])

示例3

查詢 Python 陣列中所有數字平均值的 Python 程式:

import array as arr
a = arr.array('i', [10,5,15,4,6,20,9])
print (a)
s = 0
for i in range(len(a)):
   s+=a[i]
avg = s/len(a)
print ("Average:", avg)

# Using sum() function
avg = sum(a)/len(a)
print ("Average:", avg)

它將產生以下**輸出**:

array('i', [10, 5, 15, 4, 6, 20, 9])
Average: 9.857142857142858
Average: 9.857142857142858

練習程式

  • Python程式找出陣列中每個數字與所有數字平均值之間的差值

  • Python程式將字串轉換為陣列

  • Python程式將陣列分成兩個,並將偶數儲存在一個數組中,奇數儲存在另一個數組中。

  • Python程式對陣列執行插入排序。

  • Python程式儲存給定陣列中每個字元的Unicode值。

Python - 檔案處理

當我們使用任何計算機應用程式時,需要提供一些資料。資料儲存在計算機的主記憶體(RAM)中,直到應用程式執行。此後,RAM中的記憶體內容將被擦除。

我們希望以一種可以在需要時從永續性介質(如磁碟檔案)中檢索到的方式儲存它。

Python使用內建的input()print()函式執行標準輸入/輸出操作。Python程式透過sys模組中定義的標準流物件stdin和stdout與這些IO裝置互動。

input()函式從標準輸入流裝置(即鍵盤)讀取位元組。因此,以下兩個語句都從使用者處讀取輸入。

name = input()
#is equivalent to
import sys
name = sys.stdin.readline()

另一方面,print()函式將資料傳送到標準輸出流裝置(即顯示器)。它是一個方便的函式,模擬stdout物件的write()方法。

print (name)

#is equivalent to
import sys
sys.stdout.write(name)

任何與輸入和輸出流互動的物件都稱為檔案物件。Python的內建函式open()返回一個檔案物件。

open()函式

此函式建立一個檔案物件,該物件將用於呼叫與其關聯的其他支援方法。

語法

file object = open(file_name [, access_mode][, buffering])

以下是引數詳細資訊:

  • file_name − file_name引數是一個字串值,包含要訪問的檔案的名稱。

  • access_mode − access_mode確定開啟檔案的模式,即讀取、寫入、追加等。下表給出了所有可能值的完整列表。這是一個可選引數,預設檔案訪問模式為讀取 (r)。

  • buffering − 如果將buffering值設定為0,則不進行緩衝。如果buffering值為1,則在訪問檔案時執行行緩衝。如果將buffering值指定為大於1的整數,則以指定的緩衝區大小執行緩衝操作。如果為負數,則緩衝區大小為系統預設值(預設行為)。

檔案開啟模式

以下是檔案開啟模式:

序號 模式及描述
1

r

只讀開啟檔案。檔案指標位於檔案開頭。這是預設模式。

2

rb

以二進位制格式只讀開啟檔案。檔案指標位於檔案開頭。這是預設模式。

3

r+

開啟檔案進行讀取和寫入。檔案指標位於檔案開頭。

4

rb+

以二進位制格式開啟檔案進行讀取和寫入。檔案指標位於檔案開頭。

5

w

只寫開啟檔案。如果檔案存在,則覆蓋檔案。如果檔案不存在,則建立一個新檔案進行寫入。

6

b

以二進位制模式開啟檔案

7

t

以文字模式開啟檔案(預設)

8

+

開啟檔案以進行更新(讀取和寫入)

9

wb

以二進位制格式只寫開啟檔案。如果檔案存在,則覆蓋檔案。如果檔案不存在,則建立一個新檔案進行寫入。

10

w+

開啟檔案進行寫入和讀取。如果檔案存在,則覆蓋現有檔案。如果檔案不存在,則建立一個新檔案進行讀取和寫入。

11

wb+

以二進位制格式開啟檔案進行寫入和讀取。如果檔案存在,則覆蓋現有檔案。如果檔案不存在,則建立一個新檔案進行讀取和寫入。

12

a

開啟檔案進行追加。如果檔案存在,則檔案指標位於檔案末尾。也就是說,檔案處於追加模式。如果檔案不存在,則建立一個新檔案進行寫入。

13

ab

以二進位制格式開啟檔案進行追加。如果檔案存在,則檔案指標位於檔案末尾。也就是說,檔案處於追加模式。如果檔案不存在,則建立一個新檔案進行寫入。

14

a+

開啟檔案進行追加和讀取。如果檔案存在,則檔案指標位於檔案末尾。檔案以追加模式開啟。如果檔案不存在,則建立一個新檔案進行讀取和寫入。

15

ab+

以二進位制格式開啟檔案進行追加和讀取。如果檔案存在,則檔案指標位於檔案末尾。檔案以追加模式開啟。如果檔案不存在,則建立一個新檔案進行讀取和寫入。

16

x

開啟以進行獨佔建立,如果檔案已存在則失敗

開啟檔案並擁有一個檔案物件後,您可以獲取與該檔案相關的各種資訊。

示例

# Open a file
fo = open("foo.txt", "wb")
print ("Name of the file: ", fo.name)
print ("Closed or not: ", fo.closed)
print ("Opening mode: ", fo.mode)
fo.close()

它將產生以下**輸出**:

Name of the file: foo.txt
Closed or not: False
Opening mode: wb

Python - 寫入檔案

要在Python中將資料寫入檔案,需要先開啟檔案。任何與輸入和輸出流互動的物件都稱為檔案物件。Python的內建函式open()返回一個檔案物件。

fileObject = open(file_name [, access_mode][, buffering])

使用open()函式獲得檔案物件後,可以使用write()方法將任何字串寫入檔案物件表示的檔案。需要注意的是,Python字串可以包含二進位制資料,而不僅僅是文字。

write()方法不會在字串末尾新增換行符('\n')。

語法

fileObject.write(string)

這裡,傳遞的引數是要寫入開啟的檔案的內容。

示例

# Open a file
fo = open("foo.txt", "w")
fo.write( "Python is a great language.\nYeah its great!!\n")

# Close opened file
fo.close()

上述方法將建立foo.txt檔案,並將給定內容寫入該檔案,最後關閉該檔案。程式本身沒有顯示任何輸出,但是如果您使用任何文字編輯器應用程式(如記事本)開啟此檔案,它將包含以下內容:

Python is a great language.
Yeah its great!!

以二進位制模式寫入

預設情況下,對檔案物件的讀/寫操作是對文字字串資料執行的。如果我們想處理其他型別的檔案,例如媒體 (mp3)、可執行檔案 (exe)、圖片 (jpg) 等,我們需要在讀/寫模式前新增“b”字首。

以下語句將字串轉換為位元組並寫入檔案。

f=open('test.bin', 'wb')
data=b"Hello World"
f.write(data)
f.close()

也可以使用encode()函式將文字字串轉換為位元組。

data="Hello World".encode('utf-8')

追加到檔案

當以'w'模式開啟任何現有檔案以儲存附加文字時,其早期內容將被擦除。每當以寫許可權開啟檔案時,它都被視為新檔案。要向現有檔案新增資料,請使用'a'表示追加模式。

語法

fileobject = open(file_name,"a")

示例

# Open a file in append mode
fo = open("foo.txt", "a")
text = "TutorialsPoint has a fabulous Python tutorial"
fo.write(text)

# Close opened file
fo.close()

執行上述程式時,不會顯示任何輸出,但會將新行追加到foo.txt。要驗證,請使用文字編輯器開啟。

Python is a great language.
Yeah its great!!
TutorialsPoint has a fabulous Python tutorial

使用w+模式

當開啟檔案進行寫入(使用'w'或'a')時,無法在檔案的任何早期位元組位置執行寫入操作。'w+'模式允許使用write()和read()方法而無需關閉檔案。檔案物件支援seek()函式將流倒回到任何所需的位元組位置。

以下是seek()方法的語法:

fileObject.seek(offset[, whence])

引數

  • offset − 這是檔案中讀/寫指標的位置。

  • whence − 這是可選的,預設為0,這意味著絕對檔案定位,其他值為1,這意味著相對於當前位置查詢,2意味著相對於檔案末尾查詢。

讓我們使用seek()方法來演示如何在檔案中同時進行讀/寫操作。

示例

下面的程式以w+模式(讀寫模式)開啟檔案,新增一些資料。然後它在檔案中查詢特定位置,並用新文字覆蓋其早期內容。

# Open a file in read-write mode
fo=open("foo.txt","w+")
fo.write("This is a rat race")
fo.seek(10,0)
data=fo.read(3)
fo.seek(10,0)
fo.write('cat')
fo.close()

輸出

如果我們以讀取模式開啟檔案(或在w+模式下查詢起始位置),並讀取內容,則顯示:

This is a cat race

Python - 讀取檔案

要使用Python以程式設計方式從檔案讀取資料,必須先開啟它。使用內建的open()函式:

file object = open(file_name [, access_mode][, buffering])

以下是引數詳細資訊:

  • file_name − file_name引數是一個字串值,包含要訪問的檔案的名稱。

  • access_mode − access_mode確定開啟檔案的模式,即讀取、寫入、追加等。這是一個可選引數,預設檔案訪問模式為讀取 (r)。

這兩個語句是相同的:

fo = open("foo.txt", "r")
fo = open("foo.txt")

要從開啟的檔案讀取資料,請使用檔案物件的read()方法。需要注意的是,Python字串除了文字資料外還可以包含二進位制資料。

語法

fileObject.read([count])

引數

  • count − 要讀取的位元組數。

這裡,傳遞的引數是要從開啟的檔案中讀取的位元組數。此方法從檔案開頭開始讀取,如果缺少count,則它嘗試儘可能多地讀取,可能直到檔案末尾。

示例

# Open a file
fo = open("foo.txt", "r")
text = fo.read()
print (text)

# Close the opened file
fo.close()

它將產生以下**輸出**:

Python is a great language.
Yeah its great!!

以二進位制模式讀取

預設情況下,對檔案物件的讀/寫操作是對文字字串資料執行的。如果我們想處理其他型別的檔案,例如媒體 (mp3)、可執行檔案 (exe)、圖片 (jpg) 等,我們需要在讀/寫模式前新增“b”字首。

假設test.bin檔案已經以二進位制模式寫入。

f=open('test.bin', 'wb')
data=b"Hello World"
f.write(data)
f.close()

我們需要使用'rb'模式讀取二進位制檔案。read()方法的返回值在列印之前先解碼。

f=open('test.bin', 'rb')
data=f.read()
print (data.decode(encoding='utf-8'))

它將產生以下**輸出**:

Hello World

從檔案中讀取整數資料

為了將整數資料寫入二進位制檔案,應使用to_bytes()方法將整數物件轉換為位元組。

n=25
n.to_bytes(8,'big')
f=open('test.bin', 'wb')
data=n.to_bytes(8,'big')
f.write(data)

要從二進位制檔案讀回,請使用from_bytes()函式將read()函式的輸出轉換為整數。

f=open('test.bin', 'rb')
data=f.read()
n=int.from_bytes(data, 'big')
print (n)

從檔案中讀取浮點資料

對於浮點資料,我們需要使用Python標準庫中的struct模組。

import struct
x=23.50
data=struct.pack('f',x)
f=open('test.bin', 'wb')
f.write(data)

解包read()函式的字串以從二進位制檔案中檢索浮點資料。

f=open('test.bin', 'rb')
data=f.read()
x=struct.unpack('f', data)
print (x)

使用r+模式

以 'r' 或 'rb' 模式開啟檔案進行讀取時,無法向其中寫入資料。需要先關閉檔案才能執行其他操作。為了同時執行讀取和寫入操作,需要在模式引數中新增 '+' 字元。因此,'w+' 或 'r+' 模式允許在不關閉檔案的情況下使用 write() 和 read() 方法。

File 物件還支援 seek() 函式,可以將流回繞到任何所需的位元組位置進行讀取。

以下是seek()方法的語法:

fileObject.seek(offset[, whence])

引數

  • offset − 這是檔案中讀/寫指標的位置。

  • whence − 這是可選的,預設為0,這意味著絕對檔案定位,其他值為1,這意味著相對於當前位置查詢,2意味著相對於檔案末尾查詢。

讓我們使用 seek() 方法演示如何從特定位元組位置讀取資料。

示例

此程式以 w+ 模式(讀寫模式)開啟檔案,新增一些資料。然後,它在檔案中查詢特定位置,並用新文字覆蓋其之前的內容。

fo=open("foo.txt","r+")
fo.seek(10,0)
data=fo.read(3)
print (data)
fo.close()

它將產生以下**輸出**:

rat

Python 同時讀寫

以 'w' 或 'a' 模式開啟檔案進行寫入時,無法從中讀取資料,反之亦然。這樣做會丟擲 UnSupportedOperation 錯誤。需要先關閉檔案才能執行其他操作。

為了同時執行讀取和寫入操作,需要在模式引數中新增 '+' 字元。因此,'w+' 或 'r+' 模式允許在不關閉檔案的情況下使用 write() 和 read() 方法。File 物件還支援 seek() 函式,可以將流回繞到任何所需的位元組位置。

seek() 方法

seek() 方法將檔案的當前位置設定為 offset。whence 引數是可選的,預設為 0,表示絕對檔案定位;其他值為 1,表示相對於當前位置查詢;2 表示相對於檔案末尾查詢。

此方法沒有返回值。請注意,如果使用 'a' 或 'a+' 以追加模式開啟檔案,則任何 seek() 操作都會在下一次寫入時被撤銷。

如果僅以追加模式('a')開啟檔案進行寫入,則此方法基本上是無操作的,但對於以啟用讀取的追加模式('a+')開啟的檔案,它仍然很有用。

如果使用 't' 在文字模式下開啟檔案,則只有 tell() 返回的偏移量才是合法的。使用其他偏移量會導致未定義的行為。

請注意,並非所有檔案物件都是可查詢的。

語法

以下是seek()方法的語法:

fileObject.seek(offset[, whence])

引數

  • offset − 這是檔案中讀/寫指標的位置。

  • whence − 這是可選的,預設為0,這意味著絕對檔案定位,其他值為1,這意味著相對於當前位置查詢,2意味著相對於檔案末尾查詢。

讓我們使用seek()方法來演示如何在檔案中同時進行讀/寫操作。

下面的程式以w+模式(讀寫模式)開啟檔案,新增一些資料。然後它在檔案中查詢特定位置,並用新文字覆蓋其早期內容。

示例

# Open a file in read-write mode
fo=open("foo.txt","w+")
fo.write("This is a rat race")
fo.seek(10,0)
data=fo.read(3)
fo.seek(10,0)
fo.write('cat')
fo.seek(0,0)
data=fo.read()
print (data)
fo.close()

輸出

This is a cat race

Python - 重新命名和刪除檔案

Python 的 os 模組提供了一些方法,可以幫助你執行檔案處理操作,例如重新命名和刪除檔案。

要使用此模組,需要先匯入它,然後才能呼叫任何相關的函式。

rename() 方法

rename() 方法接受兩個引數:當前檔名和新檔名。

語法

os.rename(current_file_name, new_file_name)

示例

以下是一個將現有檔案 "test1.txt" 重新命名為 "test2.txt" 的示例:

#!/usr/bin/python3
import os
# Rename a file from test1.txt to test2.txt
os.rename( "test1.txt", "test2.txt" )

remove() 方法

可以使用 remove() 方法透過提供要刪除的檔名作為引數來刪除檔案。

語法

os.remove(file_name)

示例

以下是一個刪除現有檔案 "test2.txt" 的示例:

#!/usr/bin/python3
import os
# Delete file test2.txt
os.remove("text2.txt")

Python - 目錄

所有檔案都包含在各種目錄中,Python 也能輕鬆處理這些目錄。os 模組有幾個方法可以幫助你建立、刪除和更改目錄。

mkdir() 方法

可以使用 os 模組的 mkdir() 方法在當前目錄中建立目錄。需要為此方法提供一個引數,其中包含要建立的目錄的名稱。

語法

os.mkdir("newdir")

示例

以下是一個在當前目錄中建立名為 test 的目錄的示例:

#!/usr/bin/python3
import os

# Create a directory "test"
os.mkdir("test")

chdir() 方法

可以使用 chdir() 方法更改當前目錄。chdir() 方法接受一個引數,即要設定為當前目錄的目錄的名稱。

語法

os.chdir("newdir")

示例

以下是一個進入 "/home/newdir" 目錄的示例:

import os

# Changing a directory to "/home/newdir"
os.chdir("/home/newdir")

getcwd() 方法

getcwd() 方法顯示當前工作目錄。

語法

os.getcwd()

示例

以下是一個顯示當前目錄的示例:

#!/usr/bin/python3
import os

# This would give location of the current directory
os.getcwd()

rmdir() 方法

rmdir() 方法刪除作為方法引數傳遞的目錄。

刪除目錄之前,應先刪除其中的所有內容。

語法

os.rmdir('dirname')

示例

以下是一個刪除 "/tmp/test" 目錄的示例。需要提供目錄的完全限定名,否則它會在當前目錄中搜索該目錄。

#!/usr/bin/python3
import os

# This would remove "/tmp/test" directory.
os.rmdir( "/tmp/test" )

Python - 檔案方法

使用 open() 函式建立檔案物件。file 類定義了以下方法,可以使用這些方法執行不同的檔案 I/O 操作。這些方法可用於任何類似檔案的物件,例如位元組流或網路流。

序號 方法和描述
1

file.close()

關閉檔案。關閉的檔案無法再讀取或寫入。

2

file.flush()

重新整理內部緩衝區,類似於 stdio 的 fflush。這在某些類似檔案的物件上可能是無操作的。

3

file_fileno()

返回由底層實現用來向作業系統請求 I/O 操作的整數檔案描述符。

4

file.isatty()

如果檔案連線到 tty(-like) 裝置,則返回 True;否則返回 False。

5

next(file)

每次呼叫時返回檔案中的下一行。

6

file.read([size])

最多從檔案中讀取 size 個位元組(如果在獲得 size 個位元組之前讀取遇到 EOF,則讀取更少的位元組)。

7

file.readline([size])

從檔案中讀取一行。字串中保留尾隨換行符。

8

file.readlines([sizehint])

使用 readline() 讀取直到 EOF,並返回包含這些行的列表。如果存在可選的 sizehint 引數,則不讀取到 EOF,而是讀取總計約 sizehint 位元組的整行(可能在四捨五入到內部緩衝區大小後)。

9

file.seek(offset[, whence])

設定檔案的當前位置

10

file.tell()

返回檔案的當前位置

11

file.truncate([size])

截斷檔案的大小。如果存在可選的 size 引數,則檔案將被截斷到(最多)該大小。

12

file.write(str)

將字串寫入檔案。沒有返回值。

13

file.writelines(sequence)

將一系列字串寫入檔案。該序列可以是任何產生字串的可迭代物件,通常是字串列表。

讓我們簡要了解一下上述方法。

Python - OS 檔案/目錄方法

os 模組提供大量有用的方法來操作檔案。此處列出了大多數有用的方法:

序號 方法及說明

1

os.close(fd)

關閉檔案描述符 fd。

2

os.closerange(fd_low, fd_high)

關閉從 fd_low(包含)到 fd_high(不包含)的所有檔案描述符,忽略錯誤。

3

os.dup(fd)

返回檔案描述符 fd 的副本。

4

os.fdatasync(fd)

強制將檔案描述符 fd 的檔案寫入磁碟。

5

os.fdopen(fd[, mode[, bufsize]])

返回連線到檔案描述符 fd 的開啟檔案物件。

6

os.fsync(fd)

強制將檔案描述符 fd 的檔案寫入磁碟。

7

os.ftruncate(fd, length)

截斷對應於檔案描述符 fd 的檔案,使其大小最多為 length 位元組。

8

os.lseek(fd, pos, how)

將檔案描述符 fd 的當前位置設定為位置 pos,由 how 修改。

9

os.open(file, flags[, mode])

開啟檔案 file 並根據 flags 設定各種標誌,並可能根據 mode 設定其模式。

10

os.read(fd, n)

最多從檔案描述符 fd 讀取 n 個位元組。返回包含讀取的位元組的字串。如果已到達 fd 引用的檔案的末尾,則返回空字串。

11

os.tmpfile()

返回以更新模式 (w+b) 開啟的新檔案物件。

12

os.write(fd, str)

將字串 str 寫入檔案描述符 fd。返回實際寫入的位元組數。

Python - 面向物件概念

Python 自誕生之日起就是一個面向物件的語言。因此,建立和使用類和物件非常容易。本章將幫助你成為 Python 面向物件程式設計支援方面的專家。

如果你以前沒有面向物件 (OO) 程式設計經驗,你可能需要參考一個入門課程或至少是一個教程,以便了解基本概念。但是,這裡簡要介紹一下面向物件程式設計 (OOP),以幫助你。

面向過程方法

50 年代和 60 年代開發的早期程式語言被稱為面向過程(或過程式)語言。

計算機程式透過按邏輯順序編寫一系列指令來描述執行特定任務的過程。更復雜的程式的邏輯被分解成更小但獨立且可重用的語句塊,稱為函式。

每個函式的編寫方式都使其能夠與程式中的其他函式互動。屬於一個函式的資料可以很容易地以引數的形式與其他函式共享,被呼叫的函式可以將其結果返回給呼叫函式。

與面向過程方法相關的主要問題如下:

  • 其自上而下的方法使程式難以維護。

  • 它使用大量的全域性資料項,這是不希望的。過多的全域性資料項會增加記憶體開銷。

  • 它更重視過程,而不考慮同等重要性的資料,並將其視為理所當然,因此它可以在程式中自由移動。

  • 資料在函式間的移動不受限制。在現實生活中,期望函式與其要處理的資料之間存在明確的關聯。

Python - 面向物件概念

在現實世界中,我們處理和處理物件,例如學生、員工、發票、汽車等。物件不僅是資料,也不僅僅是函式,而是兩者的組合。每個現實世界中的物件都具有與其相關的屬性和行為。

oop_concepts

屬性

  • 學生的姓名、班級、科目、分數等

  • 員工的姓名、職稱、部門、工資等

  • 發票號碼、客戶、產品程式碼和名稱、價格和數量等

  • 汽車的註冊號、車主、公司、品牌、馬力、速度等

每個屬性都將具有與其關聯的值。屬性相當於資料。

行為

處理與物件相關的屬性。

  • 計算學生的百分比分數

  • 計算應付給員工的獎勵

  • 對發票價值徵收增值稅

  • 測量汽車的速度

行為相當於函式。在現實生活中,屬性和行為並非相互獨立,而是共存的。

面向物件方法最重要的特徵是將屬性及其功能定義為一個稱為類的單元。它作為所有具有相似屬性和行為的物件的藍圖。

在 OOP 中,類定義了其物件具有的屬性以及其行為方式。另一方面,物件是類的例項。

面向物件程式設計正規化具有以下特點:

principles_of_oop

物件的自定義原型,定義了一組特徵化任何類物件的屬性。屬性是資料成員(類變數和例項變數)和方法,透過點表示法訪問。

物件

某個類的單個物件。例如,屬於 Circle 類的物件 obj 是 Circle 類的例項。由其類定義的資料結構的唯一例項。物件包含資料成員(類變數和例項變數)和方法。

封裝

類的成員資料僅可供類中定義的函式處理。另一方面,類的函式可以從類上下文之外訪問。因此,物件資料對類外部的環境是隱藏的。類函式(也稱為方法)封裝物件資料,以防止對其進行未經授權的訪問。

繼承

OOP 的軟體建模方法能夠擴充套件現有類的功能來構建新類,而不是從頭開始構建。在 OOP 術語中,現有類稱為基類或父類,而新類稱為子類或子類。

子類繼承父類的資料定義和方法。這有助於重用現有功能。子類可以新增更多定義或重新定義基類函式。

多型性

多型性是一個希臘詞,意思是具有多種形式。在 OOP 中,多型性發生在每個子類都提供基類中抽象方法的自身實現時。

Python - 物件和類

Python 是一種高度面向物件的語言。在 Python 中,Python 程式中的每個元素都是某個類的物件。程式中使用的數字、字串、列表、字典等都是相應內建類的物件。

示例

num=20
print (type(num))
num1=55.50
print (type(num1))
s="TutorialsPoint"
print (type(s))
dct={'a':1,'b':2,'c':3}
print (type(dct))
def SayHello():
   print ("Hello World")
   return
print (type(SayHello))

執行這段程式碼後,將產生以下輸出

<class 'int'>
<class 'float'>
<class 'str'>
<class 'dict'>
<class 'function'>

在 Python 中,Object 類是所有類的基類或父類,包括內建類和使用者定義類。

class 關鍵字用於定義新類。類名緊跟在 class 關鍵字之後,後面跟著一個冒號,如下所示:

class ClassName:
   'Optional class documentation string'
   class_suite
  • 類包含一個文件字串,可以透過 ClassName.__doc__ 訪問。

  • class_suite 包含定義類成員、資料屬性和函式的所有元件語句。

示例

class Employee(object):
   'Common base class for all employees'
   pass

Python 中的任何類都是 object 類的子類,因此 object 寫在括號中。但是,更高版本的 Python 不需要在括號中新增 object。

class Employee:
   'Common base class for all employees'
   pass

要定義此類的物件,請使用以下語法:

e1 = Employee()

Python - 類屬性

每個 Python 類都保留以下內建屬性,可以使用點運算子像訪問其他屬性一樣訪問它們:

  • __dict__ − 包含類名稱空間的字典。

  • __doc__ − 類文件字串,如果未定義則為 None。

  • __name__ − 類名。

  • __module__ − 定義類的模組名。在互動模式下,此屬性為“__main__”。

  • __bases__ − 一個可能為空的元組,包含基類,順序與其在基類列表中的出現順序相同。

對於上述類,讓我們嘗試訪問所有這些屬性:

class Employee:
   def __init__(self, name="Bhavana", age=24):
      self.name = name
      self.age = age
   def displayEmployee(self):
      print ("Name : ", self.name, ", age: ", self.age)

print ("Employee.__doc__:", Employee.__doc__)
print ("Employee.__name__:", Employee.__name__)
print ("Employee.__module__:", Employee.__module__)
print ("Employee.__bases__:", Employee.__bases__)
print ("Employee.__dict__:", Employee.__dict__ )

它將產生以下**輸出**:

Employee.__doc__: None
Employee.__name__: Employee
Employee.__module__: __main__
Employee.__bases__: (<class 'object'>,)
Employee.__dict__: {'__module__': '__main__', '__init__': <function Employee.__init__ at 0x0000022F866B8B80>, 'displayEmployee': <function Employee.displayEmployee at 0x0000022F866B9760>, '__dict__': <attribute '__dict__' of 'Employee' objects>, '__weakref__': <attribute '__weakref__' of 'Employee' objects>, '__doc__': None}

類變數

在上例 Employee 類中,name 和 age 是例項變數,因為它們的 value 對於每個物件可能不同。類屬性或變數的值在該類的所有例項之間共享。類屬性表示類所有物件的公共屬性。

類屬性不是在 __init__() 建構函式內初始化的。它們在類中定義,但在任何方法之外。除了物件之外,還可以透過類名訪問它們。換句話說,類屬性可用於類及其物件。

示例

讓我們在 Employee 類中新增一個名為 empCount 的類變數。對於宣告的每個物件,__init__() 方法都會自動呼叫。此方法初始化例項變數,並將 empCount 加 1。

class Employee:
   empCount = 0
   def __init__(self, name, age):
      self.__name = name
      self.__age = age
      Employee.empCount += 1
      print ("Name: ", self.__name, "Age: ", self.__age)
      print ("Employee Number:", Employee.empCount)

e1 = Employee("Bhavana", 24)
e2 = Employee("Rajesh", 26)
e3 = Employee("John", 27)

輸出

我們聲明瞭三個物件。每次 empCount 都加 1。

Name: Bhavana Age: 24
Employee Number: 1
Name: Rajesh Age: 26
Employee Number: 2
Name: John Age: 27
Employee Number: 3

Python - 類方法

例項方法訪問呼叫物件的例項變數,因為它獲取對呼叫物件的引用。但它也可以訪問類變數,因為它對所有物件都是通用的。

Python 有一個內建函式 classmethod(),它將例項方法轉換為類方法,只能透過類引用呼叫,而不是物件。

語法

classmethod(instance_method)

示例

在 Employee 類中,定義一個帶“self”引數(對呼叫物件的引用)的 showcount() 例項方法。它列印 empCount 的值。接下來,將方法轉換為可以透過類引用訪問的類方法 counter()。

class Employee:
   empCount = 0
   def __init__(self, name, age):
      self.__name = name
      self.__age = age
      Employee.empCount += 1
   def showcount(self):
         print (self.empCount)
   counter=classmethod(showcount)

e1 = Employee("Bhavana", 24)
e2 = Employee("Rajesh", 26)
e3 = Employee("John", 27)

e1.showcount()
Employee.counter()

輸出

使用物件呼叫 showcount(),使用類呼叫 count(),兩者都顯示員工計數的值。

3
3

使用 @classmethod() 裝飾器是定義類方法的首選方法,因為它比首先宣告例項方法然後轉換為類方法更方便。

@classmethod
def showcount(cls):
      print (cls.empCount)
      
Employee.showcount()

類方法充當備用建構函式。定義一個帶有構造新物件所需引數的 newemployee() 類方法。它返回構造的物件,這與 __init__() 方法的作用相同。

   @classmethod
   def showcount(cls):
         print (cls.empCount)
         return
   @classmethod
   def newemployee(cls, name, age):
      return cls(name, age)

e1 = Employee("Bhavana", 24)
e2 = Employee("Rajesh", 26)
e3 = Employee("John", 27)
e4 = Employee.newemployee("Anil", 21)

Employee.showcount()

現在有四個 Employee 物件了。

Python - 靜態方法

靜態方法沒有像對物件的引用− self 或對類的引用− cls 這樣的強制引數。Python 的標準庫函式 staticmethod() 返回一個靜態方法。

在下面的 Employee 類中,一個方法被轉換為靜態方法。現在可以透過其物件或類本身的引用來呼叫此靜態方法。

class Employee:
   empCount = 0
   def __init__(self, name, age):
      self.__name = name
      self.__age = age
      Employee.empCount += 1
   
   #@staticmethod
   def showcount():
            print (Employee.empCount)
            return
   counter = staticmethod(showcount)

e1 = Employee("Bhavana", 24)
e2 = Employee("Rajesh", 26)
e3 = Employee("John", 27)

e1.counter()
Employee.counter()

Python 還具有 @staticmethod 裝飾器,它可以方便地返回靜態方法。

@staticmethod
   def showcount():
            print (Employee.empCount)
e1.showcount()
Employee.showcount()

Python - 建構函式

在面向物件程式設計中,類的物件以一個或多個例項變數或屬性為特徵,其值對於每個物件都是唯一的。例如,如果 Employee 類具有 name 作為例項屬性。它的每個物件 e1 和 e2 可能對 name 變數具有不同的值。

建構函式是類中的例項方法,每當宣告類的新的物件時都會自動呼叫。建構函式的作用是在宣告物件後立即為例項變數賦值。

Python 使用一個名為 __init__() 的特殊方法來初始化物件的例項變數,一旦它被宣告。

__init__() 方法充當建構函式。它需要一個強制引數 self,它是對物件的引用。

def __init__(self):
#initialize instance variables

__init__() 方法以及類中的任何例項方法都具有一個強制引數 self。但是,您可以為第一個引數賦予任何名稱,而不一定是 self。

讓我們在 Employee 類中定義建構函式以將 name 和 age 初始化為例項變數。然後我們可以訪問其物件的這些屬性。

示例

class Employee:
   'Common base class for all employees'
   def __init__(self):
      self.name = "Bhavana"
      self.age = 24

e1 = Employee()
print ("Name: {}".format(e1.name))
print ("age: {}".format(e1.age))

它將產生以下**輸出**:

Name: Bhavana
age: 24

引數化建構函式

對於上述 Employee 類,我們宣告的每個物件都將為其例項變數 name 和 age 具有相同的值。要宣告具有不同屬性而不是預設屬性的物件,請為 __init__() 方法定義引數。(方法只不過是在類中定義的函式。)

示例

在此示例中,__init__() 建構函式有兩個形式引數。我們宣告具有不同值的 Employee 物件:

class Employee:
   'Common base class for all employees'
   def __init__(self, name, age):
      self.name = name
      self.age = age

e1 = Employee("Bhavana", 24)
e2 = Employee("Bharat", 25)

print ("Name: {}".format(e1.name))
print ("age: {}".format(e1.age))
print ("Name: {}".format(e2.name))
print ("age: {}".format(e2.age))

它將產生以下**輸出**:

Name: Bhavana
age: 24
Name: Bharat
age: 25

您可以為建構函式中的形式引數分配預設值,以便可以傳遞或不傳遞引數來例項化物件。

class Employee:
   'Common base class for all employees'
   def __init__(self, name="Bhavana", age=24):
      self.name = name
      self.age = age

e1 = Employee()
e2 = Employee("Bharat", 25)

print ("Name: {}".format(e1.name))
print ("age: {}".format(e1.age))
print ("Name: {}".format(e2.name))
print ("age: {}".format(e2.age))

它將產生以下**輸出**:

Name: Bhavana
age: 24
Name: Bharat
age: 25

Python - 例項方法

除了 __init__() 建構函式外,類中還可能定義一個或多個例項方法。具有 self 作為形式引數之一的方法稱為例項方法,因為它是由特定物件呼叫的。

示例

在下面的示例中,已定義 displayEmployee() 方法。它返回呼叫該方法的 Employee 物件的 name 和 age 屬性。

class Employee:
   def __init__(self, name="Bhavana", age=24):
      self.name = name
      self.age = age
   def displayEmployee(self):
      print ("Name : ", self.name, ", age: ", self.age)

e1 = Employee()
e2 = Employee("Bharat", 25)

e1.displayEmployee()
e2.displayEmployee()

它將產生以下**輸出**:

Name : Bhavana , age: 24
Name : Bharat , age: 25

您可以隨時新增、刪除或修改類和物件的屬性:

emp1.salary = 7000 # Add a 'salary' attribute.
emp1.name = 'xyz' # Modify 'name' attribute.
del emp1.salary # Delete 'salary' attribute.

您可以使用以下函式代替使用普通語句訪問屬性:

  • getattr(obj, name[, default]) − 訪問物件的屬性。

  • hasattr(obj,name) − 檢查屬性是否存在。

  • setattr(obj,name,value) − 設定屬性。如果屬性不存在,則會建立它。

  • delattr(obj, name) − 刪除屬性。

print (hasattr(e1, 'salary')) # Returns true if 'salary' attribute exists
print (getattr(e1, 'name')) # Returns value of 'name' attribute
setattr(e1, 'salary', 7000) # Set attribute 'salary' at 8
delattr(e1, 'age') # Delete attribute 'age'

它將產生以下**輸出**:

False
Bhavana

Python - 訪問修飾符

像 C++ 和 Java 這樣的語言使用訪問修飾符來限制對類成員(即變數和方法)的訪問。這些語言具有關鍵字 public、protected 和 private 來指定訪問型別。

如果可以在程式的任何位置訪問類成員,則稱該成員為公共成員。私有成員只能在類內部訪問。

  • 通常,方法定義為公共的,例項變數定義為私有的。這種私有例項變數和公共方法的安排確保了封裝原則的實現。

  • 受保護的成員可以在類內部以及派生自該類的類中訪問。

與這些語言不同,Python 沒有規定可以指定類成員可能具有的訪問型別。預設情況下,類中的所有變數和方法都是公共的。

示例

在這裡,我們有一個帶有例項變數 name 和 age 的 Employee 類。此類的物件具有這兩個屬性。可以直接從類外部訪問它們,因為它們是公共的。

class Employee:
   'Common base class for all employees'
   def __init__(self, name="Bhavana", age=24):
      self.name = name
      self.age = age

e1 = Employee()
e2 = Employee("Bharat", 25)

print ("Name: {}".format(e1.name))
print ("age: {}".format(e1.age))
print ("Name: {}".format(e2.name))
print ("age: {}".format(e2.age))

它將產生以下**輸出**:

Name: Bhavana
age: 24
Name: Bharat
age: 25

Python 不強制執行訪問任何例項變數或方法的限制。但是,Python 規定了一種約定,即在變數/方法名字首單個或雙下劃線來模擬受保護和私有訪問修飾符的行為。

為了指示例項變數是私有的,請在其前面加上雙下劃線(例如“__age”)。為了暗示某個例項變數是受保護的,請在其前面加上單個下劃線(例如“_salary”)。

示例

讓我們修改 Employee 類。新增另一個例項變數 salary。透過分別加前雙下劃線和單下劃線,使 age 私有,salary 受保護。

class Employee:
   def __init__(self, name, age, salary):
      self.name = name # public variable
      self.__age = age # private variable
      self._salary = salary # protected variable
   def displayEmployee(self):
      print ("Name : ", self.name, ", age: ", self.__age, ", salary: ", self._salary)

e1=Employee("Bhavana", 24, 10000)

print (e1.name)
print (e1._salary)
print (e1.__age)

執行此程式碼時,將產生以下**輸出**:

Bhavana
10000
Traceback (most recent call last):
 File "C:\Users\user\example.py", line 14, in <module>
  print (e1.__age)
        ^^^^^^^^
AttributeError: 'Employee' object has no attribute '__age'

Python 顯示 AttributeError,因為 __age 是私有的,並且不能在類外部使用。

名稱改編

Python 不會阻止對私有資料的訪問,它只是留給程式設計師的智慧,不要編寫任何從類外部訪問它的程式碼。您仍然可以透過 Python 的名稱改編技術訪問私有成員。

名稱改編是將具有雙下劃線的成員名稱更改為 object._class__variable 形式的過程。如果需要,仍然可以從類外部訪問它,但應避免這種做法。

在我們的示例中,私有例項變數“__name”透過將其更改為以下格式來進行改編:

obj._class__privatevar

因此,要訪問“e1”物件的“__age”例項變數的值,請將其更改為“e1._Employee__age”。

將上述程式中的 print() 語句更改為:

print (e1._Employee__age)

它現在列印 24,即 e1 的年齡。

Python 屬性物件

Python 的標準庫有一個內建的 property() 函式。它返回一個屬性物件。它充當 Python 類例項變數的介面。

面向物件程式設計的封裝原則要求例項變數應該具有受限的私有訪問許可權。Python 沒有為此目的提供有效的機制。property() 函式提供了一種替代方法。

property() 函式使用在類中定義的 getter、setter 和 delete 方法來為類定義屬性物件。

語法

property(fget=None, fset=None, fdel=None, doc=None)

引數

  • fget − 獲取例項變數值的例項方法。

  • fset − 為例項變數賦值的例項方法。

  • fdel − 刪除例項變數的例項方法

  • fdoc − 屬性的文件字串。

該函式使用 getter 和 setter 方法返回屬性物件。

Getter 和 Setter 方法

getter 方法檢索例項變數的值,通常命名為 get_varname,而 setter 方法為例項變數賦值,命名為 set_varname。

讓我們在 Employee 類中定義 getter 方法 get_name() 和 get_age(),以及 setter 方法 set_name() 和 set_age()。

示例

class Employee:
   def __init__(self, name, age):
      self.__name = name
      self.__age = age

   def get_name(self):
      return self.__name
   def get_age(self):
      return self.__age
   def set_name(self, name):
      self.__name = name
      return
   def set_age(self, age):
      self.__age=age

e1=Employee("Bhavana", 24)
print ("Name:", e1.get_name(), "age:", 

e1.get_age())
e1.set_name("Archana")
e1.set_age(21)
print ("Name:", e1.get_name(), "age:", e1.get_age())

它將產生以下**輸出**:

Name: Bhavana age: 24
Name: Archana age: 21

getter 和 setter 方法可以檢索或為例項變數賦值。property() 函式使用它們將屬性物件新增為類屬性。

name 屬性定義為:

name = property(get_name, set_name, "name")

同樣,您可以新增 age 屬性:

age = property(get_age, set_age, "age")

屬性物件的優點是您可以使用它來檢索其關聯例項變數的值,以及賦值。

例如:

print (e1.name) displays value of e1.__name
e1.name = "Archana" assigns value to e1.__age

示例

包含屬性物件及其用法的完整程式如下所示:

class Employee:
   def __init__(self, name, age):
      self.__name = name
      self.__age = age

   def get_name(self):
      return self.__name
   def get_age(self):
      return self.__age
   def set_name(self, name):
      self.__name = name
      return
   def set_age(self, age):
      self.__age=age
      return
   name = property(get_name, set_name, "name")
   age = property(get_age, set_age, "age")

e1=Employee("Bhavana", 24)
print ("Name:", e1.name, "age:", e1.age)

e1.name = "Archana"
e1.age = 23
print ("Name:", e1.name, "age:", e1.age)

它將產生以下**輸出**:

Name: Bhavana age: 24
Name: Archana age: 23

Python - 繼承

繼承是面向物件程式設計方法論最重要的特性之一。它最常用於使用 Java、PHP、Python 等多種語言的軟體開發過程中。

您可以透過在新的類名後括號中列出父類來建立一個類,而不是從頭開始。

您可以透過在新的類名後括號中列出父類來建立一個類,而不是從頭開始。

如果您必須設計一個新類,其大多數屬性已經在現有類中定義得很好了,那麼為什麼要重新定義它們呢?繼承允許重用現有類的功能,如果需要,可以擴充套件它們來設計新類。

當新類與現有類具有“IS A”關係時,繼承就會出現。汽車是一種交通工具。公共汽車是一種交通工具;腳踏車也是一種交通工具。這裡的交通工具是父類,而汽車、公共汽車和腳踏車是子類。

inheritance

語法

派生類的宣告方式與其父類非常相似;但是,在類名之後給出了要從中繼承的基類列表:

class SubClassName (ParentClass1[, ParentClass2, ...]):
   'Optional class documentation string'
   class_suite

示例

class Parent: # define parent class
   def __init__(self):
      self.attr = 100
      print ("Calling parent constructor")
   def parentMethod(self):
      print ('Calling parent method')
   def set_attr(self, attr):
      self.attr = attr
   
   def get_attr(self):
      print ("Parent attribute :", self.attr)

class Child(Parent): # define child class
   def __init__(self):
      print ("Calling child constructor")

   def childMethod(self):
      print ('Calling child method')

c = Child()      # instance of child
c.childMethod()  # child calls its method
c.parentMethod() # calls parent's method
c.set_attr(200)  # again call parent's method
c.get_attr()     # again call parent's method

輸出

執行此程式碼後,將產生以下輸出:

Calling child constructor
Calling child method
Calling parent method
Parent attribute : 200

Python - 多繼承

Python中的多繼承允許你基於多個父類構建一個類。子類因此繼承所有父類的屬性和方法。子類可以覆蓋從任何父類繼承的方法。

語法

class parent1:
   #statements
   
class parent2:
   #statements
   
class child(parent1, parent2):
   #statements

Python的標準庫有一個內建的`divmod()`函式,它返回一個包含兩個元素的元組。第一個數字是兩個引數的商,第二個是兩個運算元的餘數。

示例

這個例子嘗試模擬`divmod()`函式。我們定義了兩個類`division`和`modulus`,然後有一個`div_mod`類繼承它們。

class division:
   def __init__(self, a,b):
      self.n=a
      self.d=b
   def divide(self):
      return self.n/self.d
class modulus:
   def __init__(self, a,b):
      self.n=a
      self.d=b
   def mod_divide(self):
      return self.n%self.d
      
class div_mod(division,modulus):
   def __init__(self, a,b):
      self.n=a
      self.d=b
   def div_and_mod(self):
      divval=division.divide(self)
      modval=modulus.mod_divide(self)
      return (divval, modval)

子類有一個新的方法`div_and_mod()`,它內部呼叫它繼承的類的`divide()`和`mod_divide()`方法來返回商和餘數。

x=div_mod(10,3)
print ("division:",x.divide())
print ("mod_division:",x.mod_divide())
print ("divmod:",x.div_and_mod())

輸出

division: 3.3333333333333335
mod_division: 1
divmod: (3.3333333333333335, 1)

方法解析順序 (MRO)

術語“方法解析順序”與Python中的多繼承有關。在Python中,繼承可以跨越多個級別。假設A是B的父類,B是C的父類。C類可以覆蓋繼承的方法,或者它的物件可以呼叫在其父類中定義的方法。那麼,Python如何找到要呼叫的合適方法呢?

每個Python類都有一個`mro()`方法,它返回Python用於解析要呼叫的方法的層次順序。解析順序是從繼承順序的底部到頂部。

在我們之前的例子中,`div_mod`類繼承了`division`和`modulus`類。因此,`mro`方法返回的順序如下:

[<class '__main__.div_mod'>, <class '__main__.division'>, <class '__main__.modulus'>, <class 'object'>]

Python - 多型

術語“多型性”是指一個函式或方法在不同上下文中採用不同形式。由於Python是一種動態型別語言,因此Python中的多型性很容易實現。

如果父類中的一個方法在其不同的子類中被覆蓋為不同的業務邏輯,則基類方法就是一個多型方法。

示例

下面給出一個多型性的例子,我們有`shape`類,它是一個抽象類。它被`circle`和`rectangle`兩個類用作父類。這兩個類都以不同的方式覆蓋了父類的`draw()`方法。

from abc import ABC, abstractmethod
class shape(ABC):
   @abstractmethod
   def draw(self):
      "Abstract method"
      return

class circle(shape):
   def draw(self):
      super().draw()
      print ("Draw a circle")
      return

class rectangle(shape):
   def draw(self):
      super().draw()
      print ("Draw a rectangle")
      return

shapes = [circle(), rectangle()]
for shp in shapes:
   shp.draw()

輸出

執行此程式碼後,將產生以下輸出:

Draw a circle
Draw a rectangle

變數`shp`首先引用`circle`物件並呼叫`circle`類的`draw()`方法。在下一次迭代中,它引用`rectangle`物件並呼叫`rectangle`類的`draw()`方法。因此,`shape`類中的`draw()`方法是多型的。

Python - 方法重寫

你總是可以覆蓋父類的方法。覆蓋父類方法的一個原因是你可能希望在子類中實現特殊或不同的功能。

示例

class Parent: # define parent class
   def myMethod(self):
      print ('Calling parent method')

class Child(Parent): # define child class
   def myMethod(self):
      print ('Calling child method')

c = Child() # instance of child
c.myMethod() # child calls overridden method

執行上述程式碼時,它會產生以下輸出

Calling child method

為了理解Python中的繼承,讓我們來看另一個例子。我們使用下面的`Employee`類作為父類:

class Employee:
   def __init__(self,nm, sal):
      self.name=nm
      self.salary=sal
   def getName(self):
      return self.name
   def getSalary(self):
      return self.salary

接下來,我們定義一個`SalesOfficer`類,它使用`Employee`作為父類。它從父類繼承了例項變數`name`和`salary`。此外,子類還有一個例項變數`incentive`。

我們將使用內建函式`super()`,它返回父類的引用,並在子類的建構函式`__init__()`方法中呼叫父類的建構函式。

class SalesOfficer(Employee):
   def __init__(self,nm, sal, inc):
      super().__init__(nm,sal)
      self.incnt=inc
   def getSalary(self):
      return self.salary+self.incnt

`getSalary()`方法被重寫以將獎金新增到薪水中。

示例

宣告父類和子類的物件,看看重寫的影響。完整的程式碼如下:

class Employee:
   def __init__(self,nm, sal):
      self.name=nm
      self.salary=sal
   def getName(self):
      return self.name
   def getSalary(self):
      return self.salary

class SalesOfficer(Employee):
   def __init__(self,nm, sal, inc):
      super().__init__(nm,sal)
      self.incnt=inc
   def getSalary(self):
      return self.salary+self.incnt

e1=Employee("Rajesh", 9000)
print ("Total salary for {} is Rs {}".format(e1.getName(),e1.getSalary()))
s1=SalesOfficer('Kiran', 10000, 1000)
print ("Total salary for {} is Rs {}".format(s1.getName(),s1.getSalary()))

執行這段程式碼後,將產生以下輸出

Total salary for Rajesh is Rs 9000
Total salary for Kiran is Rs 11000

基類可重寫方法

下表列出了`object`類(所有Python類的父類)的一些通用功能。你可以在你自己的類中重寫這些方法:

序號 方法,描述 & 示例呼叫

1

__init__(self [,args...])

建構函式(帶任何可選引數)

示例呼叫:obj = className(args)

2

__del__(self)

解構函式,刪除一個物件

示例呼叫:del obj

3

__repr__(self)

可計算的字串表示

示例呼叫:repr(obj)

4

__str__(self)

可列印的字串表示

示例呼叫:str(obj)

Python - 方法過載

方法過載是面向物件程式設計的一個重要特性。Java、C++、C#語言支援方法過載,但在Python中,無法執行方法過載。

當一個類具有多個同名但引數型別和/或返回型別不同的方法時,就是一個方法過載的情況。Python不支援此機制,如下面的程式碼所示:

示例

class example:
   def add(self, a, b):
      x = a+b
      return x
   def add(self, a, b, c):
      x = a+b+c
      return x

obj = example()

print (obj.add(10,20,30))
print (obj.add(10,20))

輸出

第一次呼叫帶三個引數的`add()`方法是成功的。但是,呼叫類中定義的帶兩個引數的`add()`方法失敗了。

60
Traceback (most recent call last):
 File "C:\Users\user\example.py", line 12, in <module>
  print (obj.add(10,20))
         ^^^^^^^^^^^^^^
TypeError: example.add() missing 1 required positional argument: 'c'

輸出告訴你Python只考慮`add()`方法的最新定義,丟棄之前的定義。

為了模擬方法過載,我們可以使用一種變通方法,為方法引數定義預設值None,這樣它就可以使用一個、兩個或三個引數。

示例

class example:
   def add(self, a = None, b = None, c = None):
      x=0
      if a !=None and b != None and c != None:
         x = a+b+c
      elif a !=None and b != None and c == None:
         x = a+b
      return x

obj = example()

print (obj.add(10,20,30))
print (obj.add(10,20))

它將產生以下**輸出**:

60
30

透過這種變通方法,我們能夠在Python類中加入方法過載。

Python的標準庫沒有其他實現方法過載的規定。但是,我們可以為此目的使用名為`MultipleDispatch`的第三方模組中的`dispatch`函式。

首先,你需要安裝`Multipledispatch`模組。

pip install multipledispatch

這個模組有一個`@dispatch`裝飾器。它接受要傳遞給要過載的方法的引數數量。使用`@dispatch`裝飾器定義`add()`方法的多個副本,如下所示:

示例

from multipledispatch import dispatch
class example:
   @dispatch(int, int)
   def add(self, a, b):
      x = a+b
      return x
   @dispatch(int, int, int)
   def add(self, a, b, c):
      x = a+b+c
      return x

obj = example()

print (obj.add(10,20,30))
print (obj.add(10,20))

輸出

執行此程式碼後,將產生以下輸出:

60
30

Python - 動態繫結

在面向物件程式設計中,動態繫結的概念與多型性密切相關。在Python中,動態繫結是在執行時而不是在編譯時解析方法或屬性的過程。

根據多型性特性,不同的物件對相同的方法呼叫會根據其各自的實現做出不同的響應。這種行為是透過方法重寫實現的,子類在其超類中提供自己對方法的實現。

Python直譯器根據物件的型別或類層次結構在執行時確定要呼叫的適當方法或屬性。這意味著要呼叫的特定方法或屬性是動態確定的,基於物件的實際型別。

示例

下面的例子說明了Python中的動態繫結:

class shape:
   def draw(self):
      print ("draw method")
      return

class circle(shape):
   def draw(self):
      print ("Draw a circle")
      return

class rectangle(shape):
   def draw(self):
      print ("Draw a rectangle")
      return

shapes = [circle(), rectangle()]
for shp in shapes:
   shp.draw()

它將產生以下**輸出**:

Draw a circle
Draw a rectangle

正如你所看到的,`draw()`方法根據物件的型別動態繫結到相應的實現。這就是Python中動態繫結的實現方式。

鴨子型別

另一個與動態繫結密切相關的概念是**鴨子型別**。一個物件是否適合特定用途取決於某些方法或屬性的存在,而不是其型別。這使得Python具有更大的靈活性和程式碼重用性。

鴨子型別是像Python(Perl、Ruby、PHP、Javascript等)這樣的動態型別語言的一個重要特性,它關注的是物件的行為而不是其特定型別。根據“鴨子型別”的概念,“如果它像鴨子一樣行走,像鴨子一樣嘎嘎叫,那麼它一定是一隻鴨子”。

鴨子型別允許不同型別的物件互換使用,只要它們具有所需的方法或屬性。目標是提高靈活性和程式碼重用性。這是一個更廣泛的概念,它強調物件的行為和介面而不是正式型別。

這是一個鴨子型別的例子:

class circle:
   def draw(self):
      print ("Draw a circle")
      return

class rectangle:
   def draw(self):
      print ("Draw a rectangle")
      return

class area:
   def area(self):
      print ("calculate area")
      return

def duck_function(obj):
   obj.draw()

objects = [circle(), rectangle(), area()]
for obj in objects:
   duck_function(obj)

它將產生以下**輸出**:

Draw a circle
Draw a rectangle
Traceback (most recent call last):
 File "C:\Python311\hello.py", line 21, in <module>
  duck_function(obj)
 File "C:\Python311\hello.py", line 17, in duck_function
 obj.draw()
AttributeError: 'area' object has no attribute 'draw'

`duck_function()`最重要的是它不關心接收物件的具體型別。它只需要物件具有`draw()`方法。如果一個物件透過具有必要行為而“像鴨子一樣嘎嘎叫”,則在呼叫`draw()`方法時將其視為“鴨子”。

因此,在鴨子型別中,重點是物件的行為而不是其顯式型別,允許不同型別的物件互換使用,只要它們表現出所需的行為。

Python - 動態型別

Python語言最突出的特點之一是它是一種動態型別語言。基於編譯器的語言C/C++、Java等是靜態型別的。讓我們嘗試理解靜態型別和動態型別之間的區別。

在靜態型別語言中,必須在為變數賦值之前宣告每個變數及其資料型別。任何其他型別的值對於編譯器都是不可接受的,它會引發編譯時錯誤。

讓我們來看一下下面的Java程式片段:

public class MyClass {
   public static void main(String args[]) {
      int var;
      var="Hello";
      
      System.out.println("Value of var = " + var);
   }
}

這裡,`var`被宣告為一個整型變數。當我們嘗試為它賦值一個字串值時,編譯器會給出以下錯誤訊息:

/MyClass.java:4: error: incompatible types: String cannot be converted to int
   x="Hello";
     ^
1 error

Python中的變數只是一個標籤,或者是對儲存在記憶體中的物件的引用,而不是一個命名的記憶體位置。因此,不需要事先宣告型別。因為它只是一個標籤,所以它可以放在另一個物件上,這個物件可以是任何型別。

在Java中,變數的型別決定了它可以儲存什麼,不能儲存什麼。在Python中則相反。在這裡,資料(即物件)的型別決定了變數的型別。首先,讓我們在一個變數中儲存一個字串並檢查其型別。

>>> var="Hello"
>>> print ("id of var is ", id(var))
id of var is 2822590451184
>>> print ("type of var is ", type(var))
type of var is <class 'str'>

所以,`var`是字串型別。但是,它不是永久繫結的。它只是一個標籤;可以賦值給任何其他型別的物件,例如浮點數,它將儲存一個不同的`id()`:

>>> var=25.50
>>> print ("id of var is ", id(var))
id of var is 2822589562256
>>> print ("type of var is ", type(var))
type of var is <class 'float'>

或一個元組。`var`標籤現在位於不同的物件上。

>>> var=(10,20,30)
>>> print ("id of var is ", id(var))
id of var is 2822592028992
>>> print ("type of var is ", type(var))
type of var is <class 'tuple'>

我們可以看到,每次`var`引用一個新物件時,它的型別都會改變。這就是Python是一種動態型別語言的原因。

Python的動態型別特性使其比C/C++和Java更靈活。但是,它容易出現執行時錯誤,因此程式設計師必須小心。

Python - 抽象

抽象是面向物件程式設計的重要原則之一。它指的是一種程式設計方法,透過這種方法,只有關於物件的相關資料才會被暴露,而隱藏所有其他細節。這種方法有助於降低複雜性並提高應用程式開發效率。

抽象有兩種型別。一種是資料抽象,其中原始資料實體透過資料結構隱藏,該資料結構可以在內部處理隱藏的資料實體。另一種型別稱為過程抽象。它指的是隱藏過程的底層實現細節。

在面向物件程式設計術語中,如果一個類不能被例項化,則該類被稱為抽象類,也就是說你不能擁有抽象類的物件。但是,你可以將它用作基類或父類來構建其他類。

要在Python中形成一個抽象類,它必須繼承`abc`模組中定義的`ABC`類。此模組在Python的標準庫中可用。此外,該類必須至少有一個抽象方法。同樣,抽象方法是不能被呼叫的方法,但可以被重寫。你需要用`@abstractmethod`裝飾器來裝飾它。

示例

from abc import ABC, abstractmethod
class demo(ABC):
   @abstractmethod
   def method1(self):
      print ("abstract method")
      return
   def method2(self):
      print ("concrete method")

`demo`類繼承了`ABC`類。有一個`method1()`是抽象方法。注意,該類可能還有其他非抽象(具體)方法。

如果你嘗試宣告`demo`類的物件,Python會引發`TypeError`:

   obj = demo()
         ^^^^^^
TypeError: Can't instantiate abstract class demo with abstract method method1

此處的demo類可以用作另一個類的父類。但是,子類必須重寫父類中的抽象方法。否則,Python會丟擲此錯誤:

TypeError: Can't instantiate abstract class concreteclass with abstract method method1

因此,在下面的示例中給出了重寫抽象方法的子類:

from abc import ABC, abstractmethod
class democlass(ABC):
   @abstractmethod
   def method1(self):
      print ("abstract method")
      return
   def method2(self):
      print ("concrete method")

class concreteclass(democlass):
   def method1(self):
      super().method1()
      return
      
obj = concreteclass()
obj.method1()
obj.method2()

輸出

執行此程式碼後,將產生以下輸出:

abstract method
concrete method

Python - 封裝

封裝的原理是面向物件程式設計正規化所基於的主要支柱之一。Python對封裝的實現採取了不同的方法。

我們知道,類是物件的自定義原型。它定義了一組資料成員和方法,能夠處理資料。根據資料封裝的原理,描述物件的那些資料成員對外部環境是隱藏的。它們只能用於類中定義的方法進行處理。另一方面,方法本身可以從類上下文外部訪問。因此,物件資料被方法封裝。這種封裝的結果是防止了對物件資料的任何無意訪問。

像C++和Java這樣的語言使用訪問修飾符來限制對類成員(即變數和方法)的訪問。這些語言具有關鍵字public、protected和private來指定訪問型別。

如果類成員可以從程式的任何地方訪問,則稱其為公共成員。私有成員只能從類內部訪問。通常,方法定義為公共的,例項變數是私有的。這種私有例項變數和公共方法的安排確保了封裝的實現。

與這些語言不同,Python沒有規定可以指定類成員可能具有的訪問型別。預設情況下,Python類中的所有變數和方法都是公共的,如下例所示。

示例1

這裡,我們有一個帶有例項變數nameage的Employee類。此類的物件具有這兩個屬性。可以直接從類外部訪問它們,因為它們是公共的。

class Student:
   def __init__(self, name="Rajaram", marks=50):
      self.name = name
      self.marks = marks

s1 = Student()
s2 = Student("Bharat", 25)

print ("Name: {} marks: {}".format(s1.name, s2.marks))
print ("Name: {} marks: {}".format(s2.name, s2.marks))

它將產生以下**輸出**:

Name: Rajaram marks: 50
Name: Bharat marks: 25

在上面的示例中,例項變數在類內部初始化。但是,沒有限制從類外部訪問例項變數的值,這與封裝的原則相違背。

儘管沒有關鍵字強制執行可見性,但Python有一種以特殊方式命名例項變數的約定。在Python中,使用單下劃線或雙下劃線作為變數/方法名稱的字首來模擬受保護和私有訪問修飾符的行為。

如果變數以單個雙下劃線開頭(例如“__age”),則例項變數是私有的;類似地,如果變數名稱以單個下劃線開頭(例如“_salary”)

示例2

讓我們修改Student類。新增另一個例項變數salary。透過在其前面新增雙下劃線,將name設為私有,將marks設為私有。

class Student:

   def __init__(self, name="Rajaram", marks=50):
      self.__name = name
      self.__marks = marks
   def studentdata(self):
      print ("Name: {} marks: {}".format(self.__name, self.__marks))
      
s1 = Student()
s2 = Student("Bharat", 25)

s1.studentdata()
s2.studentdata()
print ("Name: {} marks: {}".format(s1.__name, s2.__marks))
print ("Name: {} marks: {}".format(s2.__name, __s2.marks))

執行此程式碼時,將產生以下**輸出**:

Name: Rajaram marks: 50
Name: Bharat marks: 25
Traceback (most recent call last):
 File "C:\Python311\hello.py", line 14, in <module>
  print ("Name: {} marks: {}".format(s1.__name, s2.__marks))
AttributeError: 'Student' object has no attribute '__name'

上面的輸出清楚地表明,例項變數name和age雖然可以透過類內部宣告的方法(studentdata()方法)訪問,但是由於雙下劃線字首使變數成為私有的,因此不允許從類外部訪問它們,從而引發AttributeError。

Python不會完全阻止對私有資料的訪問。它只是留給程式設計師的智慧,不要編寫任何從類外部訪問它的程式碼。您仍然可以透過Python的名稱改編技術訪問私有成員。

名稱改編是將具有雙下劃線的成員名稱更改為 object._class__variable 形式的過程。如果需要,仍然可以從類外部訪問它,但應避免這種做法。

在我們的示例中,私有例項變數“__name”透過將其更改為以下格式來進行改編:

obj._class__privatevar

因此,要訪問“s1”物件的“__marks”例項變數的值,將其更改為“s1._Student__marks”。

將上述程式中的 print() 語句更改為:

print (s1._Student__marks)

它現在列印50,即s1的分數。

因此,我們可以得出結論,Python並沒有完全按照面向物件程式設計理論那樣實現封裝。它透過規定命名約定,並允許程式設計師在確實需要在公共作用域中訪問私有資料時使用名稱改編技術,從而採取了一種更成熟的方法。

Python - 介面

在軟體工程中,介面是一種軟體架構模式。介面類似於類,但其方法只有原型簽名定義,沒有任何實現主體。推薦的功能需要由具體的類來實現。

在Java等語言中,有interface關鍵字,這使得定義介面很容易。Python沒有它或任何類似的關鍵字。因此,與抽象類一樣,使用相同的ABC類和@abstractmethod裝飾器。

抽象類和介面在Python中看起來很相似。兩者之間唯一的區別在於抽象類可能有一些非抽象方法,而介面中的所有方法都必須是抽象的,並且實現類必須重寫所有抽象方法。

示例

from abc import ABC, abstractmethod
class demoInterface(ABC):
   @abstractmethod
   def method1(self):
      print ("Abstract method1")
      return

   @abstractmethod
   def method2(self):
      print ("Abstract method1")
      return

上述介面有兩個抽象方法。與抽象類一樣,我們不能例項化介面。

   obj = demoInterface()
         ^^^^^^^^^^^^^^^
TypeError: Can't instantiate abstract class demoInterface with abstract methods method1, method2

讓我們提供一個實現這兩個抽象方法的類。如果它不包含所有抽象方法的實現,Python會顯示以下錯誤:

   obj = concreteclass()
         ^^^^^^^^^^^^^^^
TypeError: Can't instantiate abstract class concreteclass with abstract method method2

以下類實現了這兩種方法:

class concreteclass(demoInterface):
   def method1(self):
      print ("This is method1")
      return
   
   def method2(self):
      print ("This is method2")
      return
      
obj = concreteclass()
obj.method1()
obj.method2()

輸出

執行此程式碼後,將產生以下輸出:

This is method1
This is method2

Python - 包

在Python中,模組是一個帶有.py副檔名的Python指令碼,包含類、函式等物件。Python中的包進一步擴充套件了模組化方法的概念。包是一個包含一個或多個模組檔案的資料夾;此外還有一個特殊的“__init__.py”檔案,它可以為空,但可以包含包列表。

讓我們建立一個名為mypackage的Python包。請按照以下步驟操作:

  • 建立一個外部資料夾來儲存mypackage的內容。讓它的名字是packagedemo。

  • 在其中,建立另一個資料夾mypackage。這將是我們即將構建的Python包。兩個Python模組areafuntions.py和mathfunctions.py將建立在mypackage內部。

  • 在mypackage資料夾內建立一個空的"__init__.py"檔案。

  • 稍後,我們將在外部資料夾中儲存一個Python指令碼example.py來測試我們的包。

檔案/資料夾結構應如下所示:

folder_structure

使用您喜歡的程式碼編輯器,將以下兩個Python模組儲存到mypackage資料夾中。

# mathfunctions.py
def sum(x,y):
   val = x+y
   return val
   
def average(x,y):
   val = (x+y)/2
   return val

def power(x,y):
   val = x**y
   return val

建立另一個Python指令碼:

# areafunctions.py
def rectangle(w,h):
   area = w*h
   return area
   
def circle(r):
   import math
   area = math.pi*math.pow(r,2)
   return area

現在讓我們在該包資料夾上方的Python指令碼的幫助下測試myexample包。請參考上面的資料夾結構。

#example.py
from mypackage.areafunctions import rectangle
print ("Area :", rectangle(10,20))

from mypackage.mathsfunctions import average
print ("average:", average(10,20))

此程式從mypackage匯入函式。如果執行上述指令碼,您應該得到以下輸出

Area : 200
average: 15.0

定義包列表

您可以將包中選擇的函式或任何其他資源放入"__init__.py"檔案中。讓我們在其中放入以下程式碼。

from .areafunctions import circle
from .mathsfunctions import sum, power

要從該包匯入可用的函式,請將以下指令碼儲存為testpackage.py,與之前一樣,儲存在包資料夾上方。

#testpackage.py
from mypackage import power, circle

print ("Area of circle:", circle(5))
print ("10 raised to 2:", power(10,2))

它將產生以下**輸出**:

Area of circle: 78.53981633974483
10 raised to 2: 100

包安裝

現在,我們能夠從包資料夾上方的指令碼訪問包資源。為了能夠在檔案系統的任何地方使用該包,您需要使用PIP實用程式安裝它。

首先,將以下指令碼儲存在父資料夾中,位於包資料夾的級別。

#setup.py
from setuptools import setup
setup(name='mypackage',
version='0.1',
description='Package setup script',
url='#',
author='anonymous',
author_email='test@gmail.com',
license='MIT',
packages=['mypackage'],
zip_safe=False)

在命令提示符下執行PIP實用程式,同時停留在父資料夾中。

C:\Users\user\packagedemo>pip3 install .
Processing c:\users\user\packagedemo
 Preparing metadata (setup.py) ... done
Installing collected packages: mypackage
 Running setup.py install for mypackage ... done
Successfully installed mypackage-0.1

您現在應該能夠在任何環境中匯入包的內容。

C:\Users>python
Python 3.11.2 (tags/v3.11.2:878ead1, Feb 7 2023, 16:38:35) [MSC v.1934 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import mypackage
>>> mypackage.circle(5)
78.53981633974483

Python - 內部類

在Python中,在另一個類中定義的類稱為內部類。有時內部類也稱為巢狀類。如果例項化內部類,則父類也可以使用內部類的物件。內部類的物件成為外部類的屬性之一。內部類自動繼承外部類的屬性,而無需正式建立繼承關係。

語法

class outer:
   def __init__(self):
      pass
   class inner:
      def __init__(self):
         pass

內部類允許您對類進行分組。巢狀類的優點之一是更容易理解哪些類是相關的。內部類具有區域性作用域。它充當外部類的一個屬性。

示例

在以下程式碼中,我們有student作為外部類,subjects作為內部類。student的__init__()建構函式初始化name屬性和subjects類的例項。另一方面,內部subjects類的建構函式初始化兩個例項變數sub1、sub2。

外部類的show()方法使用已例項化的物件呼叫內部類的方法。

class student:
   def __init__(self):
      self.name = "Ashish"
      self.subs = self.subjects()
      return
   def show(self):
      print ("Name:", self.name)
      self.subs.display()
   class subjects:
      def __init__(self):
         self.sub1 = "Phy"
         self.sub2 = "Che"
         return
      def display(self):
         print ("Subjects:",self.sub1, self.sub2)
         
s1 = student()
s1.show()

執行這段程式碼後,將產生以下輸出

Name: Ashish
Subjects: Phy Che

完全可以獨立宣告外部類的物件,並使其呼叫它自己的display()方法。

sub = student().subjects().display()

它將列出科目。

Python - 匿名類和物件

Python的內建type()函式返回物件所屬的類。在Python中,類(內建類或使用者定義類)都是class型別的物件。

示例

class myclass:
   def __init__(self):
      self.myvar=10
      return
      
obj = myclass()

print ('class of int', type(int))
print ('class of list', type(list))
print ('class of dict', type(dict))
print ('class of myclass', type(myclass))
print ('class of obj', type(obj))

它將產生以下**輸出**:

class of int <class 'type'>
class of list <class 'type'>
class of dict <class 'type'>
class of myclass <class 'type'>

type()具有以下三個引數的版本:

語法

newclass=type(name, bases, dict)

使用上述語法,可以動態建立類。三個函式型別引數為:

  • name - 類的名稱,成為新類的__name__屬性

  • bases - 包含父類的元組。如果不是派生類,則可以為空

  • dict - 形成新類名稱空間的字典,包含屬性、方法及其值。

我們可以使用上述版本的type()函式建立匿名類。name引數為空字串,第二個引數是一個包含一個類object類的元組(請注意,Python中的每個類都繼承自object類)。我們將某些例項變數新增到第三個引數字典中。現在我們暫時保持它為空。

anon=type('', (object, ), {})

要建立此匿名類的物件:

obj = anon()
print ("type of obj:", type(obj))

結果表明該物件是匿名類。

type of obj: <class '__main__.'>

示例

我們還可以動態新增例項變數和例項方法。請看這個例子:

def getA(self):
   return self.a
obj = type('',(object,),{'a':5,'b':6,'c':7,'getA':getA,'getB':lambda self : self.b})()
print (obj.getA(), obj.getB())

它將產生以下**輸出**:

5 6

Python - 單例類

單例類是一個只能建立一個物件的類。當您執行一些繁重的操作(例如建立資料庫連線)時,這有助於最佳化記憶體使用。

示例

class SingletonClass:
   _instance = None
   
   def __new__(cls):
      if cls._instance is None:
         print('Creating the object')
         cls._instance = super(SingletonClass, cls).__new__(cls)
      return cls._instance
      
obj1 = SingletonClass()
print(obj1)

obj2 = SingletonClass()
print(obj2)

這就是上述程式碼的工作方式:

當宣告Python類的例項時,它會在內部呼叫__new__()方法。我們重寫了__new__()方法,該方法在建立類的物件時由Python內部呼叫。它檢查我們的例項變數是否為None。如果例項變數為None,則建立一個新物件並呼叫super()方法,並返回包含此類物件的例項變數。

如果建立多個物件,則很明顯該物件只在第一次建立;之後,將返回相同的物件例項。

Creating the object
<__main__.SingletonClass object at 0x000002A5293A6B50>
<__main__.SingletonClass object at 0x000002A5293A6B50>

Python - 包裝器類

Python中的函式是一階物件。函式可以將另一個函式作為其引數,並在其中包裝另一個函式定義。這有助於修改函式而不實際更改它。這樣的函式稱為裝飾器。

此功能也可用於包裝類。此技術用於在透過包裝其邏輯在裝飾器內例項化類後管理類。

示例

def decorator_function(Wrapped):
   class Wrapper:
      def __init__(self,x):
         self.wrap = Wrapped(x)
      def print_name(self):
         return self.wrap.name
   return Wrapper
   
@decorator_function
class Wrapped:
   def __init__(self,x):
      self.name = x
      
obj = Wrapped('TutorialsPoint')
print(obj.print_name())

這裡,Wrapped是要包裝的類的名稱。它作為引數傳遞給函式。在函式內部,我們有一個Wrapper類,使用傳遞類的屬性修改其行為,並返回修改後的類。返回的類被例項化,現在可以呼叫其方法。

執行這段程式碼後,將產生以下輸出

TutorialsPoint

Python - 列舉

術語“列舉”是指為一組字串分配固定常量值的過程,以便可以透過與其繫結的值來標識每個字串。Python 的標準庫提供了enum模組。enum模組中包含的Enum類用作父類來定義一組識別符號的列舉——通常以大寫形式編寫。

示例1

from enum import Enum

class subjects(Enum):
   ENGLISH = 1
   MATHS = 2
   SCIENCE = 3
   SANSKRIT = 4

在上面的程式碼中,“subjects”是列舉。它具有不同的列舉成員,例如,subjects.MATHS。每個成員都分配了一個值。

每個成員都是列舉類subjects的一個物件,並且具有name和value屬性。

obj = subjects.MATHS
print (type(obj), obj.value)

結果如下所示輸出

<enum 'subjects'> 2

示例2

與列舉成員繫結的值不一定是整數,也可以是字串。請參見以下示例−

from enum import Enum

class subjects(Enum):
   ENGLISH = "E"
   MATHS = "M"
   GEOGRAPHY = "G"
   SANSKRIT = "S"
   
obj = subjects.SANSKRIT
print (type(obj), obj.name, obj.value)

它將產生以下**輸出**:

<enum 'subjects'> SANSKRIT S

示例3

您可以使用for迴圈按其在定義中出現的順序迭代列舉成員−

for sub in subjects:
   print (sub.name, sub.value)

它將產生以下**輸出**:

ENGLISH E
MATHS M
GEOGRAPHY G
SANSKRIT S

可以透過分配給它的唯一值或透過其name屬性訪問列舉成員。因此,subjects("E")以及subjects["ENGLISH"]都返回subjects.ENGLISH成員。

示例 4

列舉類不能出現相同的成員兩次,但是可以為多個成員分配相同的值。為了確保每個成員都有一個唯一的值與其繫結,請使用@unique裝飾器。

from enum import Enum, unique

@unique
class subjects(Enum):
   ENGLISH = 1
   MATHS = 2
   GEOGRAPHY = 3
   SANSKRIT = 2

這將引發如下異常−

   @unique
    ^^^^^^
   raise ValueError('duplicate values found in %r: %s' %
ValueError: duplicate values found in <enum 'subjects'>: SANSKRIT -> MATHS

Enum類是一個可呼叫類,因此您可以使用以下定義列舉的替代方法−

from enum import Enum
subjects = Enum("subjects", "ENGLISH MATHS SCIENCE SANSKRIT")

Enum建構函式在此處使用兩個引數。第一個是列舉的名稱。第二個引數是一個字串,其中包含列舉成員符號名稱,用空格分隔。

Python - 反射

在面向物件程式設計中,反射是指提取有關任何正在使用的物件的資訊的能力。您可以瞭解物件的型別,它是否是任何其他類的子類,它的屬性是什麼等等。Python 的標準庫有很多函式可以反映物件的不同屬性。反射有時也稱為內省。

讓我們回顧一下反射函式。

type() 函式

我們已經多次使用過這個函式。它會告訴你一個物件屬於哪個類。

示例

以下語句列印不同內建資料型別物件的相應類

print (type(10))
print (type(2.56))
print (type(2+3j))
print (type("Hello World"))
print (type([1,2,3]))
print (type({1:'one', 2:'two'}))

在這裡,您將得到以下輸出

<class 'int'>
<class 'float'>
<class 'complex'>
<class 'str'>
<class 'list'>
<class 'dict'>

讓我們驗證使用者定義類物件的型別−

class test:
   pass
   
obj = test()
print (type(obj))

它將產生以下**輸出**:

<class '__main__.test'>

isinstance() 函式

這是 Python 中的另一個內建函式,它確定一個物件是否是給定類的例項

語法

isinstance(obj, class)

此函式始終返回布林值,如果物件確實屬於給定類,則返回 true,否則返回 false。

示例

以下語句返回 True −

print (isinstance(10, int))
print (isinstance(2.56, float))
print (isinstance(2+3j, complex))
print (isinstance("Hello World", str))

相反,這些語句列印 False。

print (isinstance([1,2,3], tuple))
print (isinstance({1:'one', 2:'two'}, set))

它將產生以下**輸出**:

True
True
True
True
False
False

您也可以使用使用者定義的類執行檢查

class test:
   pass
   
obj = test()
print (isinstance(obj, test))

它將產生以下**輸出**:

True

在 Python 中,即使類也是物件。所有類都是 object 類的物件。可以透過以下程式碼驗證−

class test:
   pass
   
print (isinstance(int, object))
print (isinstance(str, object))
print (isinstance(test, object))

以上所有列印語句都列印 True。

issubclass() 函式

此函式檢查一個類是否是另一個類的子類。適用於類,不適用於它們的例項。

如前所述,所有 Python 類都是從 object 類繼承的。因此,以下列印語句的輸出對於所有情況都是 True。

class test:
   pass
   
print (issubclass(int, object))
print (issubclass(str, object))
print (issubclass(test, object))

它將產生以下**輸出**:

True
True
True

callable() 函式

如果物件呼叫某個過程,則該物件是可呼叫的。Python 函式執行某個過程,是一個可呼叫物件。因此 callable(function) 返回 True。任何函式,內建函式、使用者定義函式或方法都是可呼叫的。內建資料型別(如 int、str 等)的物件不可呼叫。

示例

def test():
   pass
   
print (callable("Hello"))
print (callable(abs))
print (callable(list.clear([1,2])))
print (callable(test))

字串物件不可呼叫。但 abs 是一個可呼叫的函式。list 的 pop 方法是可呼叫的,但 clear() 實際上是對函式的呼叫,而不是函式物件,因此不可呼叫

它將產生以下**輸出**:

False
True
True
False
True

如果類例項具有 __call__() 方法,則它是可呼叫的。在下面的示例中,test 類包含 __call__() 方法。因此,它的物件可以像呼叫函式一樣使用。因此,具有 __call__() 函式的類的物件是可呼叫的。

class test:
   def __init__(self):
      pass
   def __call__(self):
      print ("Hello")
      
obj = test()
obj()
print ("obj is callable?", callable(obj))

它將產生以下**輸出**:

Hello
obj is callable? True

getattr() 函式

內建函式 getattr() 檢索物件的命名屬性的值。

示例

class test:
   def __init__(self):
      self.name = "Manav"
      
obj = test()
print (getattr(obj, "name"))

它將產生以下**輸出**:

Manav

setattr() 函式

內建函式 setattr() 為物件新增一個新屬性併為其賦值。它還可以更改現有屬性的值。

在下面的示例中,test 類物件只有一個屬性 - name。我們使用 setattr 新增 age 屬性並修改 name 屬性的值。

class test:
   def __init__(self):
      self.name = "Manav"
      
obj = test()
setattr(obj, "age", 20)
setattr(obj, "name", "Madhav")
print (obj.name, obj.age)

它將產生以下**輸出**:

Madhav 20

hasattr() 函式

此內建函式如果給定屬性可用於物件引數,則返回 True,否則返回 false。我們使用相同的 test 類並檢查它是否具有某個屬性。

class test:
   def __init__(self):
      self.name = "Manav"
      
obj = test()
print (hasattr(obj, "age"))
print (hasattr(obj, "name"))

它將產生以下**輸出**:

False
True

dir() 函式

如果此內建函式沒有引數呼叫,則返回當前作用域中的名稱。對於任何物件作為引數,它都會返回給定物件的屬性列表,以及從中可以訪問的屬性。

  • 對於模組物件 - 該函式返回模組的屬性。

  • 對於類物件 - 該函式返回其屬性,並遞迴返回其基類的屬性。

  • 對於任何其他物件 - 其屬性、其類的屬性以及其類的基類的屬性(遞迴)。

示例

print ("dir(int):", dir(int))

它將產生以下**輸出**:

dir(int): ['__abs__', '__add__', '__and__', '__bool__', '__ceil__', '__class__', '__delattr__', '__dir__', '__divmod__', '__doc__', '__eq__', '__float__', '__floor__', '__floordiv__', '__format__', '__ge__', '__getattribute__', '__getnewargs__', '__getstate__', '__gt__', '__hash__', '__index__', '__init__', '__init_subclass__', '__int__', '__invert__', '__le__', '__lshift__', '__lt__', '__mod__', '__mul__', '__ne__', '__neg__', '__new__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__round__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', '__trunc__', '__xor__', 'as_integer_ratio', 'bit_count', 'bit_length', 'conjugate', 'denominator', 'from_bytes', 'imag', 'numerator', 'real', 'to_bytes']

示例

print ("dir(dict):", dir(dict))

它將產生以下**輸出**:

dir(dict): ['__class__', '__class_getitem__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__ior__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__or__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__ror__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'clear', 'copy', 'fromkeys', 'get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values']

示例

class test:
   def __init__(self):
      self.name = "Manav"

obj = test()
print ("dir(obj):", dir(obj))

它將產生以下**輸出**:

dir(obj): ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'name']

Python - 語法錯誤

通常,計算機程式中會出現三種類型的錯誤:語法錯誤、邏輯錯誤和執行時錯誤。語法錯誤是編寫程式時遇到的最常見型別的錯誤,無論您是程式設計新手還是經驗豐富的程式設計師。語法錯誤基本上與某種語言的語法規則有關。

每當不遵循語言規定的規則時,就會發生語法錯誤。在 Python 中,為識別符號命名有明確的規則,即變數、函式、類、模組或任何 Python 物件。同樣,應根據定義的語法使用 Python 關鍵字。每當不遵循這些規則時,Python 直譯器都會顯示語法錯誤訊息。

下面給出了在 Python 互動式 shell 中宣告變數的一個簡單示例。

>>> name="Python
   File "<stdin>", line 1
      name="Python
           ^
SyntaxError: unterminated string literal (detected at line 1)

Python 直譯器顯示語法錯誤以及某些解釋性訊息。在上面的示例中,由於引號符號未關閉,因此發生語法錯誤。

同樣,Python 要求每個函式名稱後面都應跟括號,在括號內應給出函式引數。

在以下示例中,我們得到一個語法錯誤−

>>> print "Hello"
   File "<stdin>", line 1
      print "Hello"
      ^^^^^^^^^^^^^
SyntaxError: Missing parentheses in call to 'print'. Did you mean print(...)?

原因可以從錯誤訊息中理解,即 print() 函式缺少括號。

Python 程式設計有很多流行的 IDE。它們中的大多數都使用彩色語法突出顯示,這使得很容易直觀地識別錯誤。

VS Code 就是這樣的 IDE 之一。在輸入指令時,語法錯誤會適當地突出顯示。

syntax error

錯誤已突出顯示。如果您將游標放在那裡,VS Code 會提供有關錯誤的更多資訊。如果您仍然繼續執行程式碼,則錯誤訊息將出現在命令終端中。

語法錯誤很容易識別和糾正。像 VS Code 這樣的 IDE 使其變得容易。但是,有時,您的程式碼不會顯示任何語法錯誤,但程式的輸出仍然不是您預期的結果。這種錯誤是邏輯錯誤。它們很難檢測到,因為錯誤在於程式碼中使用的邏輯。您會透過經驗學習如何糾正邏輯錯誤。VS Code 和其他 IDE 具有監視和斷點等功能來捕獲這些錯誤。

第三種類型的錯誤是執行時錯誤,也稱為異常。您的程式中沒有任何語法錯誤,也沒有任何邏輯錯誤。大多數情況下,程式會給出預期的輸出,但在某些特定情況下,您會得到程式的異常行為,例如程式異常終止或給出一些荒謬的結果。

導致異常的因素通常是程式外部的。例如,錯誤的輸入、型別轉換或 IO 裝置故障等。

什麼是異常?

異常是在程式執行期間發生的事件,它會中斷程式指令的正常流程。通常,當 Python 指令碼遇到無法處理的情況時,它會引發異常。異常是一個表示錯誤的 Python 物件。

當 Python 指令碼引發異常時,它必須立即處理異常,否則它將終止並退出。

Python 的標準庫定義了標準異常類。與其他 Python 類一樣,異常也是 Object 類的子類。以下是 Python 異常的物件層次結構。

object
   BaseException
      Exception
         ArithmeticError
            FloatingPointError
            OverflowError
            ZeroDivisionError
         AssertionError
         AttributeError
         BufferError
         EOFError
         ImportError
            ModuleNotFoundError
         LookupError
            IndexError
            KeyError
         MemoryError
         NameError
         OSError
         ReferenceError
         RuntimeError
         StopAsyncIteration
         StopIteration
         SyntaxError

Python - 異常處理

如果您有一些可能引發異常的可疑程式碼,您可以透過將可疑程式碼放在try: 塊中來保護您的程式。在try: 塊之後,包括一個except: 語句,然後是一個儘可能優雅地處理問題的程式碼塊。

  • try: 塊包含可能出現異常的語句

  • 如果發生異常,程式將跳轉到except: 塊。

  • 如果try: 塊中沒有異常,則跳過except: 塊。

語法

這是try...except...else塊的簡單語法−

try:
   You do your operations here
   ......................
except ExceptionI:
   If there is ExceptionI, then execute this block.
except ExceptionII:
   If there is ExceptionII, then execute this block.
   ......................
else:
   If there is no exception then execute this block.

以下是一些關於上述語法的要點−

  • 單個try語句可以有多個except語句。當try塊包含可能丟擲不同型別異常的語句時,這很有用。

  • 您還可以提供一個泛型except子句,該子句處理任何異常。

  • 在except子句之後,您可以包含一個else子句。如果try:塊中的程式碼沒有引發異常,則執行else塊中的程式碼。

  • else塊非常適合不需要try:塊保護的程式碼。

示例

此示例開啟一個檔案,在檔案中寫入內容並優雅地退出,因為根本沒有任何問題。

try:
   fh = open("testfile", "w")
   fh.write("This is my test file for exception handling!!")
except IOError:
   print ("Error: can\'t find file or read data")
else:
   print ("Written content in the file successfully")
   fh.close()

它將產生以下**輸出**:

Written content in the file successfully

但是,將open()函式中的mode引數更改為“w”。如果testfile不存在,程式會在except塊中遇到IOError,並列印以下錯誤訊息−

Error: can't find file or read data

Python - try-except 程式碼塊

你也可以使用沒有定義異常的except語句,如下所示:

try:
   You do your operations here
   ......................
except:
   If there is any exception, then execute this block.
   ......................
else:
   If there is no exception then execute this block.

這種 try-except 語句會捕獲所有發生的異常。但是,這種 try-except 語句不被認為是良好的程式設計實踐,因為它捕獲所有異常,但不會讓程式設計師識別可能出現問題的根本原因。

你也可以使用相同的 except 語句來處理多個異常,如下所示:

try:
   You do your operations here
   ......................
except(Exception1[, Exception2[,...ExceptionN]]]):
   If there is any exception from the given exception list,
   then execute this block.
   ......................
else:
   If there is no exception then execute this block.

Python - try-finally 程式碼塊

你可以將finally: 程式碼塊與try: 程式碼塊一起使用。finally: 程式碼塊用於放置必須執行的任何程式碼,無論 try 程式碼塊是否引發異常。

try-finally 語句的語法如下所示:

try:
   You do your operations here;
   ......................
   Due to any exception, this may be skipped.
finally:
   This would always be executed.
   ......................

注意 - 你可以提供 except 子句或 finally 子句,但不能同時提供兩者。你也不可以在 finally 子句中使用 else 子句。

示例

try:
   fh = open("testfile", "w")
   fh.write("This is my test file for exception handling!!")
finally:
   print ("Error: can\'t find file or read data")
   fh.close()

如果你沒有許可權以寫入模式開啟檔案,則會產生以下輸出

Error: can't find file or read data

同樣的例子可以更簡潔地寫成如下:

try:
   fh = open("testfile", "w")
   try:
      fh.write("This is my test file for exception handling!!")
   finally:
      print ("Going to close the file")
      fh.close()
except IOError:
   print ("Error: can\'t find file or read data")

當 try 程式碼塊中丟擲異常時,執行會立即傳遞到finally程式碼塊。在finally程式碼塊中的所有語句執行完畢後,異常將再次被丟擲,如果在 try-except 語句的上一層存在 except 語句,則會在其中處理該異常。

帶有引數的異常

異常可以有一個引數,該引數是一個值,提供關於問題的更多資訊。引數的內容因異常而異。你可以透過在 except 子句中提供一個變數來捕獲異常的引數,如下所示:

try:
   You do your operations here
   ......................
except ExceptionType as Argument:
   You can print value of Argument here...

如果你編寫程式碼來處理單個異常,你可以在 except 語句中在異常名稱後面新增一個變數。如果你要捕獲多個異常,你可以在異常元組後面新增一個變數。

此變數接收異常的值,其中主要包含異常的原因。該變數可以接收單個值或多個值(以元組的形式)。此元組通常包含錯誤字串、錯誤號和錯誤位置。

示例

以下是單個異常的示例:

# Define a function here.
def temp_convert(var):
   try:
      return int(var)
   except ValueError as Argument:
      print("The argument does not contain numbers\n",Argument)
# Call above function here.
temp_convert("xyz")

它將產生以下**輸出**:

The argument does not contain numbers
invalid literal for int() with base 10: 'xyz'

Python - 丟擲異常

你可以透過使用 raise 語句以幾種方式引發異常。raise 語句的通用語法如下所示:

語法

raise [Exception [, args [, traceback]]]

這裡,Exception 是異常的型別(例如,NameError),argument 是異常引數的值。引數是可選的;如果不提供,則異常引數為 None。

最後一個引數 traceback 也是可選的(在實踐中很少使用),如果存在,則是用於異常的 traceback 物件。

示例

異常可以是字串、類或物件。Python 核心引發的多數異常都是類,其引數是該類的例項。定義新的異常非常容易,可以按如下方式完成:

def functionName( level ):
   if level <1:
      raise Exception(level)
      # The code below to this would not be executed
      # if we raise the exception
   return level

注意 - 為了捕獲異常,“except”子句必須引用以類物件或簡單字串形式丟擲的相同異常。例如,要捕獲上述異常,我們必須按如下方式編寫 except 子句:

try:
   Business Logic here...
except Exception as e:
   Exception handling here using e.args...
else:
   Rest of the code here...

以下示例說明了引發異常的使用:

def functionName( level ):
   if level <1:
      raise Exception(level)
      # The code below to this would not be executed
      # if we raise the exception
   return level
   
try:
   l=functionName(-10)
   print ("level=",l)
except Exception as e:
   print ("error in level argument",e.args[0])

這將產生以下輸出

error in level argument -10

Python - 異常鏈

異常鏈是一種透過在將捕獲的異常包裝在新異常中後重新丟擲該異常來處理異常的技術。原始異常被儲存為新異常的屬性(例如 cause)。

在處理一個異常“A”的過程中,可能會發生另一個異常“B”。為了除錯問題,瞭解這兩個異常都很有用。有時,異常處理程式故意重新引發異常很有用,這樣做是為了提供額外資訊或將異常轉換為另一種型別。

在 Python 3.x 中,可以實現異常鏈。如果 except 部分中存在任何未處理的異常,則該異常將附加到正在處理的異常中,幷包含在錯誤訊息中。

示例

在以下程式碼片段中,嘗試開啟不存在的檔案會引發 FileNotFoundError。except 塊會檢測到它。在處理時,會引發另一個異常。

try:
   open("nofile.txt")
except OSError:
   raise RuntimeError("unable to handle error")

它將產生以下**輸出**:

Traceback (most recent call last):
  File "/home/cg/root/64afcad39c651/main.py", line 2, in <module>
open("nofile.txt")
FileNotFoundError: [Errno 2] No such file or directory: 'nofile.txt'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/cg/root/64afcad39c651/main.py", line 4, in <module>
    raise RuntimeError("unable to handle error")
RuntimeError: unable to handle error

raise . . from

如果你在 raise 語句中使用可選的 from 子句,則表示異常是另一個異常的直接結果。當轉換異常時,這可能很有用。from 關鍵字後的標記應為異常物件。

try:
   open("nofile.txt")
except OSError as exc:
   raise RuntimeError from exc

它將產生以下**輸出**:

Traceback (most recent call last):
  File "/home/cg/root/64afcad39c651/main.py", line 2, in <module>
    open("nofile.txt")
FileNotFoundError: [Errno 2] No such file or directory: 'nofile.txt'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/home/cg/root/64afcad39c651/main.py", line 4, in <module>
    raise RuntimeError from exc
RuntimeError

raise . . from None

如果在 from 子句中使用 None 而不是異常物件,則會停用在前面示例中找到的自動異常鏈。

try:
   open("nofile.txt")
except OSError as exc:
   raise RuntimeError from None

它將產生以下**輸出**:

Traceback (most recent call last):
 File "C:\Python311\hello.py", line 4, in <module>
  raise RuntimeError from None
RuntimeError

__context__ 和 __cause__

在 except 塊中引發異常會自動將捕獲的異常新增到新異常的 __context__ 屬性。同樣,你也可以使用表示式raise ... from語法將 __cause__ 新增到任何異常。

try:
   try:
      raise ValueError("ValueError")
   except ValueError as e1:
      raise TypeError("TypeError") from e1
except TypeError as e2:
   print("The exception was", repr(e2))
   print("Its __context__ was", repr(e2.__context__))
   print("Its __cause__ was", repr(e2.__cause__))

它將產生以下**輸出**:

The exception was TypeError('TypeError')
Its __context__ was ValueError('ValueError')
Its __cause__ was ValueError('ValueError')

Python - 巢狀 try 塊

在 Python 程式中,如果在try塊或其except塊記憶體在另一個try-except結構,則稱為巢狀 try 塊。當外部塊和內部塊可能導致不同的錯誤時,需要這樣做。為了處理它們,我們需要巢狀 try 塊。

我們從具有單個“try - except - finally”結構的示例開始。如果 try 內部的語句遇到異常,則由 except 塊處理。無論是否發生異常,finally 塊始終都會執行。

示例1

這裡,try塊存在“除以 0”的情況,因此except塊開始發揮作用。它配備了使用 Exception 類處理通用異常的功能。

a=10
b=0
try:
   print (a/b)
except Exception:
   print ("General Exception")
finally:
   print ("inside outer finally block")

它將產生以下**輸出**:

General Exception
inside outer finally block

示例2

現在讓我們看看如何巢狀try結構。我們將另一個“try - except - finally”塊放在現有的 try 塊內。內部 try 的 except 關鍵字現在處理通用 Exception,而我們要求外部 try 的 except 塊處理 ZeroDivisionError。

由於內部try塊中沒有發生異常,因此不會呼叫其相應的通用 Except。除以 0 的情況由外部 except 子句處理。

a=10
b=0
try:
   print (a/b)
   try:
      print ("This is inner try block")
   except Exception:
      print ("General exception")
   finally:
      print ("inside inner finally block")
      
except ZeroDivisionError:
   print ("Division by 0")
finally:
   print ("inside outer finally block")

它將產生以下**輸出**:

Division by 0
inside outer finally block

示例3

現在我們反轉一下情況。在巢狀的try塊中,外部塊沒有引發任何異常,但導致除以 0 的語句在內部 try 中,因此異常由內部except塊處理。顯然,對應於外部try: 的except部分不會被呼叫。

a=10
b=0
try:
   print ("This is outer try block")
   try:
      print (a/b)
   except ZeroDivisionError:
      print ("Division by 0")
   finally:
      print ("inside inner finally block")
      
except Exception:
   print ("General Exception")
finally:
   print ("inside outer finally block")

它將產生以下**輸出**:

This is outer try block
Division by 0
inside inner finally block
inside outer finally block

最後,讓我們討論一下巢狀塊中可能發生的另一種情況。雖然外部try: 中沒有任何異常,但沒有合適的 except 塊來處理內部try: 塊中的異常。

示例 4

在以下示例中,內部try: 遇到“除以 0”,但其對應的 except: 正在查詢 KeyError 而不是 ZeroDivisionError。因此,異常物件被傳遞到後續 except 語句的 except: 塊,該語句與外部 try: 語句匹配。在那裡,zeroDivisionError 異常被捕獲並處理。

a=10
b=0
try:
   print ("This is outer try block")
   try:
      print (a/b)
   except KeyError:
      print ("Key Error")
   finally:
      print ("inside inner finally block")
      
except ZeroDivisionError:
   print ("Division by 0")
finally:
   print ("inside outer finally block")

它將產生以下**輸出**:

This is outer try block
inside inner finally block
Division by 0
inside outer finally block

Python - 使用者自定義異常

Python 還允許你透過從標準內建異常派生類來建立你自己的異常。

這是一個包含使用者定義的 MyException 類的示例。這裡,建立了一個從基類 Exception 類繼承的類。當你需要在捕獲異常時顯示更具體的信時,這非常有用。

try塊中,每當 num 變數的值小於 0 或大於 100 時,都會引發使用者定義的異常,並在except塊中捕獲。變數 e 用於建立 MyException 類的例項。

示例

class MyException(Exception):
   "Invalid marks"
   pass
   
num = 10
try:
   if num <0 or num>100:
      raise MyException
except MyException as e:
   print ("Invalid marks:", num)
else:
   print ("Marks obtained:", num)

輸出

對於不同的num值,程式顯示以下輸出

Marks obtained: 10
Invalid marks: 104
Invalid marks: -10

Python - 日誌記錄

術語“日誌記錄”指的是記錄某個過程中不同中間事件的機制。在軟體應用程式中記錄日誌有助於開發人員除錯和跟蹤應用程式邏輯中的任何錯誤。Python 的標準庫包含 logging 模組,可以使用該模組生成和記錄應用程式日誌。

在程式中間歇性地使用 print() 語句來檢查不同變數和物件的中值是一種常見做法。它有助於開發人員驗證程式是否按預期執行。但是,日誌記錄比間歇性 print 語句更有益,因為它提供了對事件的更多洞察。

日誌級別

日誌記錄的一個重要功能是你可以生成不同嚴重性級別的日誌訊息。logging 模組定義了以下級別及其值。

級別 使用時間

DEBUG

詳細資訊,通常僅在診斷問題時才感興趣。

10

INFO

確認事情按預期工作。

20

WARNING

表明發生了意外情況,或表明不久的將來會出現某些問題(例如,“磁碟空間不足”)。軟體仍在按預期工作。

30

ERROR

由於更嚴重的問題,軟體無法執行某些功能。

40

CRITICAL

嚴重錯誤,表明程式本身可能無法繼續執行。

50

示例

以下程式碼說明了如何生成日誌訊息。

import logging

logging.debug('This is a debug message')
logging.info('This is an info message')
logging.warning('This is a warning message')
logging.error('This is an error message')
logging.critical('This is a critical message')

它將產生以下**輸出**:

WARNING:root:This is a warning message
ERROR:root:This is an error message
CRITICAL:root:This is a critical message

請注意,此處僅顯示 WARNING 級別後的日誌訊息。這是因為 root(預設記錄器)忽略所有高於 WARNING 嚴重性級別的嚴重性級別。請注意,嚴重性級別記錄在每一行的第一個冒號 (:) 之前。同樣,root 也是顯示在 LogRecord 中的記錄器的名稱。

日誌記錄配置

可以使用 BasicConfig() 方法自定義程式生成的日誌。你可以定義一個或多個以下引數進行配置:

  • filename - 指定建立 FileHandler,使用指定的 filename,而不是 StreamHandler。

  • filemode - 如果指定了 filename,則以這種模式開啟檔案。預設為 'a'。

  • datefmt - 使用指定的日期/時間格式,time.strftime() 接受。

  • style - 如果指定了 format,則對格式字串使用此樣式。分別是 printf 樣式、str.format() 或 string.Template 的 '%', '{' 或 '$' 之一。預設為 '%'。

  • level - 將根記錄器級別設定為指定的級別。

  • 錯誤處理 (errors) − 如果此關鍵字引數與檔名一起指定,則在建立 FileHandler 時使用其值,並在開啟輸出檔案時使用。如果未指定,則使用值“backslashreplace”。請注意,如果指定 None,則會將其原樣傳遞給 open(),這意味著它將與傳遞“errors”相同。

示例

要記錄 DEBUG 級別以上的所有訊息,請將 level 引數設定為 logging.DEBUG。

import logging

logging.basicConfig(level=logging.DEBUG)
logging.debug('This message will get logged')

它將產生以下**輸出**:

DEBUG:root:This message will get logged

要將日誌訊息記錄到檔案而不是在控制檯上回顯它們,請使用 filename 引數。

import logging

logging.basicConfig(filename='logs.txt', filemode='w', level=logging.DEBUG)
logging.warning('This messagewill be saved to a file')

控制檯上不會顯示任何輸出。但是,在當前目錄中建立了一個 logs.txt 檔案,其中包含文字 WARNING:root:This message will be saved to a file

日誌訊息中的變數資料

大多數情況下,您希望在日誌訊息中包含一個或多個變數的值,以便更好地瞭解應用程式執行時生成的錯誤原因。為此,可以使用任何動態字串格式化技術,例如str類的 format() 方法或 f-字串。

示例

import logging

logging.basicConfig(level=logging.DEBUG)
marks = 120
logging.error("Invalid marks:{} Marks must be between 0 to 100".format(marks))
subjects = ["Phy", "Maths"]
logging.warning("Number of subjects: {}. Should be at least three".format(len(subjects)))

它將產生以下**輸出**:

ERROR:root:Invalid marks:120 Marks must be between 0 to 100
WARNING:root:Number of subjects: 2. Should be at least three

Python - 斷言

斷言是一種健全性檢查,您可以在完成程式測試後將其開啟或關閉。

  • 最簡單的理解斷言的方法是將其比作 raise-if 語句(或者更準確地說,是 raise-if-not 語句)。測試一個表示式,如果結果為假,則引發異常。

  • 斷言由 assert 語句執行,這是 Python 中最新引入的關鍵字,在 1.5 版本中引入。

  • 程式設計師通常在函式開始時放置斷言以檢查有效輸入,並在函式呼叫後檢查有效輸出。

assert 語句

當遇到 assert 語句時,Python 會評估伴隨的表示式,該表示式應該為真。如果表示式為假,Python 將引發 AssertionError 異常。

assert 的語法為:

assert Expression[, Arguments]

如果斷言失敗,Python 使用 ArgumentExpression 作為 AssertionError 的引數。可以使用 try-except 語句捕獲和處理 AssertionError 異常,就像處理任何其他異常一樣。如果未處理它們,它們將終止程式併產生回溯。

示例

print ('enter marks out of 100')
num=75
assert num>=0 and num<=100
print ('marks obtained: ', num)

num=125
assert num>=0 and num<=100
print ('marks obtained: ', num)

它將產生以下**輸出**:

enter marks out of 100
marks obtained: 75
Traceback (most recent call last):
 File "C:\Users\user\example.py", line 7, in <module>
  assert num>=0 and num<=100
                    ^^^^^^^^
AssertionError

要顯示自定義錯誤訊息,請在 assert 語句中的表示式後新增一個字串:

assert num>=0 and num<=100, "only numbers in 0-100 accepted"

AssertionError 也是一個內建異常。因此它可以用作 except 塊中的引數。當輸入導致 AssertionError 異常時,它將由 except 塊處理。except 塊將 assert 語句中的字串視為異常物件。

try:
   num=int(input('enter a number'))
   assert (num >=0), "only non negative numbers accepted"
   print (num)
except AssertionError as msg:
   print (msg)

Python - 內建異常

以下是 Python 中可用的標準異常列表:

序號 異常名稱和描述
1

異常

所有異常的基類

2

StopIteration

當迭代器的 next() 方法不指向任何物件時引發。

3

SystemExit

由 sys.exit() 函式引發。

4

StandardError

除 StopIteration 和 SystemExit 之外,所有內建異常的基類。

5

ArithmeticError

所有針對數字計算發生的錯誤的基類。

6

OverflowError

當計算超過數字型別的最大限制時引發。

7

FloatingPointError

當浮點計算失敗時引發。

8

ZeroDivisionError

當對所有數字型別進行零除或模運算時引發。

9

AssertionError

在 Assert 語句失敗的情況下引發。

10

AttributeError

在屬性引用或賦值失敗的情況下引發。

11

EOFError

當 raw_input() 或 input() 函式沒有輸入並且達到檔案結尾時引發。

12

ImportError

當 import 語句失敗時引發。

13

KeyboardInterrupt

當用戶中斷程式執行時引發,通常是透過按 Ctrl+C。

14

LookupError

所有查詢錯誤的基類。

15

IndexError

當在序列中找不到索引時引發。

16

KeyError

當在字典中找不到指定的鍵時引發。

17

NameError

當在本地或全域性名稱空間中找不到識別符號時引發。

18

UnboundLocalError

當嘗試訪問函式或方法中的區域性變數但尚未為其賦值時引發。

19

EnvironmentError

所有在 Python 環境之外發生的異常的基類。

20

IOError

當輸入/輸出操作失敗時引發,例如 print 語句或 open() 函式在嘗試開啟不存在的檔案時。

21

OSError

針對與作業系統相關的錯誤引發。

22

SyntaxError

當 Python 語法中存在錯誤時引發。

23

IndentationError

當縮排未正確指定時引發。

24

SystemError

當直譯器發現內部問題時引發,但是當遇到此錯誤時,Python 直譯器不會退出。

25

SystemExit

當使用 sys.exit() 函式退出 Python 直譯器時引發。如果程式碼中未處理,則會導致直譯器退出。

26

TypeError

當嘗試對指定資料型別無效的操作或函式時引發。

27

ValueError

當資料型別的內建函式具有有效的引數型別,但引數具有無效的值時引發。

28

RuntimeError

當生成的錯誤不屬於任何類別時引發。

29

NotImplementedError

當需要在繼承類中實現的抽象方法實際上未實現時引發。

以下是一些標準異常示例:

IndexError

嘗試訪問無效索引處的專案時顯示。

numbers=[10,20,30,40]
for n in range(5):
   print (numbers[n])

它將產生以下**輸出**:

10
20
30
40
Traceback (most recent call last):

   print (numbers[n])
IndexError: list index out of range

ModuleNotFoundError

當找不到模組時顯示。

import notamodule
Traceback (most recent call last):

   import notamodule
ModuleNotFoundError: No module named 'notamodule'

KeyError

當找不到字典鍵時發生。

D1={'1':"aa", '2':"bb", '3':"cc"}
print ( D1['4'])
Traceback (most recent call last):

   D1['4']
KeyError: '4'

ImportError

當指定的函式不可匯入時顯示。

from math import cube
Traceback (most recent call last):

   from math import cube
ImportError: cannot import name 'cube'

StopIteration

當迭代器流耗盡後呼叫 next() 函式時出現此錯誤。

.it=iter([1,2,3])
next(it)
next(it)
next(it)
next(it)
Traceback (most recent call last):

   next(it)
StopIteration

TypeError

當運算子或函式應用於不合適的型別的物件時顯示。

print ('2'+2)
Traceback (most recent call last):

   '2'+2
TypeError: must be str, not int

ValueError

當函式的引數型別不合適時顯示。

print (int('xyz'))
Traceback (most recent call last):

   int('xyz')
ValueError: invalid literal for int() with base 10: 'xyz'

NameError

當找不到物件時遇到此錯誤。

print (age)
Traceback (most recent call last):

   age
NameError: name 'age' is not defined

ZeroDivisionError

當除法中的第二個運算數為零時顯示。

x=100/0
Traceback (most recent call last):

   x=100/0
ZeroDivisionError: division by zero

KeyboardInterrupt

當用戶在程式執行期間按下中斷鍵(通常是 Control-C)時。

name=input('enter your name')
enter your name^c
Traceback (most recent call last):

   name=input('enter your name')
KeyboardInterrupt

Python - 多執行緒

預設情況下,計算機程式以順序方式執行指令,從開始到結束。多執行緒是指將主要任務劃分為多個子任務並以重疊方式執行它們的機制。這使得執行速度比單執行緒更快。

作業系統能夠併發處理多個程序。它為每個程序分配單獨的記憶體空間,這樣一來,一個程序就不能訪問或寫入其他程序的空間。另一方面,執行緒可以被認為是單個程式中的輕量級子程序。單個程式的執行緒共享分配給它的記憶體空間。

程序內的多個執行緒與主執行緒共享相同的數 據空間,因此可以比單獨的程序更容易地共享資訊或彼此通訊。

由於它們是輕量級的,不需要大量的記憶體開銷;它們比程序更便宜。

multithreading

程序總是從單個執行緒(主執行緒)開始。根據需要,可以啟動新執行緒並將子任務委派給它。現在這兩個執行緒以重疊的方式工作。當分配給輔助執行緒的任務結束後,它與主執行緒合併。

Python - 執行緒生命週期

執行緒物件會經歷不同的階段。建立新的執行緒物件後,必須啟動它。這將呼叫執行緒類的 run() 方法。此方法包含新執行緒要執行的程序的邏輯。當 run() 方法結束時,執行緒完成其任務,新建立的執行緒與主執行緒合併。

執行緒執行時,可以將其暫停預定義的時間段,或者可以要求其暫停直到發生某個事件。在指定的時間間隔或程序結束後,執行緒恢復。

thread_life_cycle

Python 的標準庫包含兩個模組,“_thread”和“threading”,它們包含處理執行緒的功能。“_thread”模組是一個低階 API。在 Python 3 中,包含了threading 模組,它提供了更全面的執行緒管理功能。

Python _thread 模組

_thread 模組(之前的thread模組)自 2.0 版以來一直是 Python 標準庫的一部分。它是一個用於執行緒管理的低階 API,並作為許多其他具有高階併發執行功能(如 threading 和 multiprocessing)的模組的支援。

Python - threading 模組

較新的 threading 模組提供了更強大、更高級別的執行緒管理支援。

Thread 類表示在單獨的控制執行緒中執行的活動。有兩種方法可以指定活動:透過將可呼叫物件傳遞給建構函式,或者透過在子類中覆蓋 run() 方法。

threading.Thread(target, name, args, kwarg, daemon)

引數

  • target − 當新執行緒啟動時要呼叫的函式。預設為 None,這意味著不呼叫任何內容。

  • name − 是執行緒名稱。預設情況下,會構造一個唯一的名稱,例如“Thread-N”。

  • daemon − 如果設定為 True,則新執行緒在後臺執行。

  • args 和 kwargs − 要傳遞給目標函式的可選引數。

Python - 建立執行緒

_thread 模組中包含的start_new_thread()函式用於在正在執行的程式中建立新執行緒。

語法

_thread.start_new_thread ( function, args[, kwargs] )

此函式啟動一個新執行緒並返回其識別符號。

引數

  • function − 新建立的執行緒開始執行並呼叫指定的函式。如果函式需要任何引數,則可以將其作為引數 args 和 kwargs 傳遞。

示例

import _thread
import time
# Define a function for the thread
def thread_task( threadName, delay):
   for count in range(1, 6):
      time.sleep(delay)
      print ("Thread name: {} Count: {}".format ( threadName, count ))

# Create two threads as follows
try:
   _thread.start_new_thread( thread_task, ("Thread-1", 2, ) )
   _thread.start_new_thread( thread_task, ("Thread-2", 4, ) )
except:
   print ("Error: unable to start thread")

while True:
   pass

它將產生以下**輸出**:

Thread name: Thread-1 Count: 1
Thread name: Thread-2 Count: 1
Thread name: Thread-1 Count: 2
Thread name: Thread-1 Count: 3
Thread name: Thread-2 Count: 2
Thread name: Thread-1 Count: 4
Thread name: Thread-1 Count: 5
Thread name: Thread-2 Count: 3
Thread name: Thread-2 Count: 4
Thread name: Thread-2 Count: 5
Traceback (most recent call last):
 File "C:\Users\user\example.py", line 17, in <module>
  while True:
KeyboardInterrupt

程式進入無限迴圈。您必須按“ctrl-c”才能停止。

Python - 啟動執行緒

此 start() 方法啟動執行緒的活動。建立執行緒物件後必須呼叫一次此方法。

start() 方法會自動在單獨的執行緒中呼叫物件的 run() 方法。但是,如果呼叫此方法多次,則會引發 RuntimeError。

語法

以下是使用 start() 方法啟動執行緒的語法:

threading.thread.start()

示例

請看下面的例子:

thread1 = myThread("Thread-1")

# Start new Thread
thread1.start()

這會自動呼叫 run() 方法。

run() 方法

run() 方法表示執行緒的活動。可以在子類中覆蓋它。物件不會呼叫標準 run() 方法,而是呼叫作為目標引數傳遞給其建構函式的函式。

Python - 合併執行緒

執行緒類中的 join() 方法會阻塞呼叫執行緒,直到呼叫其 join() 方法的執行緒終止。終止可能是正常的,也可能是由於未處理的異常導致的——或者直到可選的超時發生。它可以被多次呼叫。如果嘗試加入當前執行緒,則 join() 會引發 RuntimeError 異常。線上程啟動之前嘗試呼叫 join() 也會引發相同的異常。

語法

thread.join(timeout)

引數

  • 超時 (timeout) —— 它應該是一個浮點數,指定執行緒阻塞的超時時間。

join() 方法始終返回 None。你必須在 join() 之後呼叫 is_alive() 來判斷是否發生了超時——如果執行緒仍然存活,則 join() 呼叫超時了。當 timeout 引數不存在或為 None 時,操作將阻塞直到執行緒終止。

一個執行緒可以被多次加入。

示例

thread1.start()
thread2.start()
thread1.join()
thread2.join()

is_alive() 方法

此方法返回執行緒是否存活。它在呼叫 run() 方法之前和 run() 方法終止之後返回 True。

Python - 執行緒命名

執行緒的名稱僅用於標識目的,在語義上沒有任何作用。多個執行緒可以具有相同的名稱。執行緒名稱可以在 thread() 建構函式的引數之一中指定。

thread(name)

這裡 name 是執行緒名稱。預設情況下,會構造一個唯一的名稱,例如 "Thread-N"。

Thread 物件也具有一個屬性物件,用於執行緒名稱屬性的 getter 和 setter 方法。

thread.name = "Thread-1"

守護程序屬性 (The daemon Property)

一個布林值,指示此執行緒是守護執行緒 (True) 還是非守護執行緒 (False)。必須在呼叫 start() 之前設定此屬性。

示例

要使用 threading 模組實現新執行緒,您需要執行以下操作:

  • 定義 _Thread_ 類的新的子類。

  • 重寫 _init__(self [,args])_ 方法以新增其他引數。

  • 然後,重寫 run(self [,args]) 方法以實現執行緒啟動時應執行的操作。

建立新的 Thread 子類後,您可以建立其例項,然後透過呼叫 start() 方法啟動新執行緒,該方法會依次呼叫 run() 方法。

import threading
import time
class myThread (threading.Thread):
   def __init__(self, name):
      threading.Thread.__init__(self)
      self.name = name

   def run(self):
      print ("Starting " + self.name)
      for count in range(1,6):
         time.sleep(5)
         print ("Thread name: {} Count: {}".format ( self.name, count ))
      print ("Exiting " + self.name)

# Create new threads
thread1 = myThread("Thread-1")
thread2 = myThread("Thread-2")

# Start new Threads
thread1.start()
thread2.start()
thread1.join()
thread2.join()
print ("Exiting Main Thread")

它將產生以下**輸出**:

Starting Thread-1
Starting Thread-2
Thread name: Thread-1 Count: 1
Thread name: Thread-2 Count: 1
Thread name: Thread-1 Count: 2
Thread name: Thread-2 Count: 2
Thread name: Thread-1 Count: 3
Thread name: Thread-2 Count: 3
Thread name: Thread-1 Count: 4
Thread name: Thread-2 Count: 4
Thread name: Thread-1 Count: 5
Exiting Thread-1
Thread name: Thread-2 Count: 5
Exiting Thread-2
Exiting Main Thread

Python - 執行緒排程

Python 支援程式中的多執行緒。多執行緒程式可以獨立執行多個子任務,這允許並行執行任務。

Python 直譯器將 Python 執行緒請求對映到 POSIX/pthreads 或 Windows 執行緒。因此,與普通執行緒類似,Python 執行緒由主機作業系統處理。

但是,Python 直譯器不支援執行緒排程。因此,使用 Python 直譯器無法實現執行緒優先順序、排程方案和執行緒搶佔。Python 執行緒的排程和上下文切換由主機排程程式控制。

Python 確實以 sched 模組作為標準庫的形式支援任務排程。它可用於建立機器人和其他監控和自動化應用程式。_sched_ 模組實現了一個通用的事件排程器,用於在特定時間執行任務。它提供了類似於 Windows 或 Linux 中任務排程的工具。

_scheduler_ 類在 _sched_ 內建模組中定義。

scheduler(timefunc=time.monotonic, delayfunc=time.sleep)

_scheduler_ 類中定義的方法包括:

  • scheduler.enter() —— 可以排程事件在延遲後或特定時間執行。要使用延遲排程它們,請使用 enter() 方法。

  • scheduler.cancel() —— 從佇列中刪除事件。如果事件不是佇列中當前存在的事件,此方法將引發 ValueError。

  • scheduler.run(blocking=True) —— 執行所有已計劃的事件。

可以排程事件在延遲後或特定時間執行。要使用延遲排程它們,請使用 enter() 方法,它接受四個引數。

  • 表示延遲的數字

  • 優先順序值

  • 要呼叫的函式

  • 函式的引數元組

示例1

此示例計劃了兩個不同的事件:

import sched
import time

scheduler = sched.scheduler(time.time, time.sleep)

def schedule_event(name, start):
   now = time.time()
   elapsed = int(now - start)
   print('elapsed=',elapsed, 'name=', name)

start = time.time()
print('START:', time.ctime(start))
scheduler.enter(2, 1, schedule_event, ('EVENT_1', start))
scheduler.enter(5, 1, schedule_event, ('EVENT_2', start))

scheduler.run()

它將產生以下**輸出**:

START: Mon Jun 5 15:37:29 2023
elapsed= 2 name= EVENT_1
elapsed= 5 name= EVENT_2

示例2

讓我們來看另一個例子,以更好地理解這個概念:

import sched
from datetime import datetime
import time

def addition(a,b):
   print("Performing Addition : ", datetime.now())
   print("Time : ", time.monotonic())
   print("Result : ", a+b)

s = sched.scheduler()

print("Start Time : ", datetime.now())

event1 = s.enter(10, 1, addition, argument = (5,6))
print("Event Created : ", event1)
s.run()
print("End Time : ", datetime.now())

它將產生以下**輸出**:

Start Time : 2023-06-05 15:49:49.508400
Event Created : Event(time=774087.453, priority=1, sequence=0, action=<function addition at 0x000001FFE71A1080>, argument=(5, 6), kwargs={})
Performing Addition : 2023-06-05 15:49:59.512213
Time : 774087.484
Result : 11
End Time : 2023-06-05 15:49:59.559659

Python - 執行緒池

什麼是執行緒池?

執行緒池是一種自動管理工作執行緒池的機制。池中的每個執行緒都稱為工作執行緒或工作者執行緒。任務完成後,可以重複使用工作執行緒。單個執行緒一次只能執行一個任務。

執行緒池控制何時建立執行緒以及執行緒在未使用時應執行的操作。

與手動啟動、管理和關閉執行緒相比,使用執行緒池的效率要高得多,尤其是在處理大量任務時。

Python 中的多執行緒併發地執行某個函式。可以透過 _concurrent.futures_ 模組中定義的 _ThreadPoolExecutor_ 類來實現多個執行緒非同步執行函式。

_concurrent.futures_ 模組包括 _Future_ 類和兩個 _Executor_ 類:_ThreadPoolExecutor_ 和 _ProcessPoolExecutor_。

_Future_ 類

_concurrent.futures.Future_ 類負責處理任何可呼叫物件(例如函式)的非同步執行。要獲取 _Future_ 類的物件,應在任何 _Executor_ 物件上呼叫 _submit()_ 方法。不應透過其建構函式直接建立它。

_Future_ 類中的重要方法:

result(timeout=None)

此方法返回呼叫返回的值。如果呼叫尚未完成,則此方法將等待最多 timeout 秒。如果在 timeout 秒內呼叫未完成,則將引發 _TimeoutError_。如果未指定 timeout,則等待時間沒有限制。

cancel()

此方法嘗試取消呼叫。如果呼叫當前正在執行或已完成執行並且無法取消,則該方法將返回 False,否則呼叫將被取消,該方法將返回 True。

cancelled()

如果呼叫已成功取消,此方法將返回 True。

running()

如果呼叫當前正在執行且無法取消,此方法將返回 True。

done()

如果呼叫已成功取消或完成執行,此方法將返回 True。

_ThreadPoolExecutor_ 類

此類表示指定數量的最大工作執行緒池,用於非同步執行呼叫。

concurrent.futures.ThreadPoolExecutor(max_threads)

示例

from concurrent.futures import ThreadPoolExecutor
from time import sleep
def square(numbers):
   for val in numbers:
      ret = val*val
      sleep(1)
      print("Number:{} Square:{}".format(val, ret))
def cube(numbers):
   for val in numbers:
      ret = val*val*val
      sleep(1)
      print("Number:{} Cube:{}".format(val, ret))
if __name__ == '__main__':
   numbers = [1,2,3,4,5]
   executor = ThreadPoolExecutor(4)
   thread1 = executor.submit(square, (numbers))
   thread2 = executor.submit(cube, (numbers))
   print("Thread 1 executed ? :",thread1.done())
   print("Thread 2 executed ? :",thread2.done())
   sleep(2)
   print("Thread 1 executed ? :",thread1.done())
   print("Thread 2 executed ? :",thread2.done())

它將產生以下**輸出**:

Thread 1 executed ? : False
Thread 2 executed ? : False
Number:1 Square:1
Number:1 Cube:1
Number:2 Square:4
Number:2 Cube:8
Thread 1 executed ? : False
Thread 2 executed ? : False
Number:3 Square:9
Number:3 Cube:27
Number:4 Square:16
Number:4 Cube:64
Number:5 Square:25
Number:5 Cube:125
Thread 1 executed ? : True
Thread 2 executed ? : True

Python - 主執行緒

每個 Python 程式至少有一個稱為主執行緒的執行執行緒。預設情況下,主執行緒是非守護執行緒。

有時,我們可能需要在程式中建立其他執行緒以併發執行程式碼。

以下是建立新執行緒的語法

object = threading.Thread(target, daemon)

_Thread()_ 建構函式建立一個新物件。透過呼叫 _start()_ 方法,新執行緒開始執行,它會自動呼叫作為引數傳遞給 _target_ 引數的函式(預設為 _run_)。第二個引數是“daemon”,預設為 None。

示例

from time import sleep
from threading import current_thread
from threading import Thread

# function to be executed by a new thread
def run():
   # get the current thread
   thread = current_thread()
   # is it a daemon thread?
   print(f'Daemon thread: {thread.daemon}')

# create a new thread
thread = Thread(target=run)

# start the new thread
thread.start()

# block for a 0.5 sec
sleep(0.5)

它將產生以下**輸出**:

Daemon thread: False

因此,透過以下語句建立執行緒:

t1=threading.Thread(target=run)

此語句建立一個非守護執行緒。啟動後,它將呼叫 _run()_ 方法。

Python - 執行緒優先順序

Python 標準庫中的 _queue_ 模組在必須線上程之間安全交換資訊的多執行緒程式設計中很有用。此模組中的 _PriorityQueue_ 類實現了所有必需的鎖定語義。

使用優先順序佇列,條目保持排序(使用 _heapq_ 模組),並且首先檢索最低值條目。

_Queue_ 物件具有以下方法來控制佇列:

  • get() —— _get()_ 從佇列中刪除並返回一個專案。

  • put() —— _put()_ 將專案新增到佇列。

  • qsize() —— _qsize()_ 返回當前在佇列中的專案數。

  • empty() —— _empty()_ 如果佇列為空,則返回 True;否則返回 False。

  • full() —— _full()_ 如果佇列已滿,則返回 True;否則返回 False。

queue.PriorityQueue(maxsize=0)

這是優先順序佇列的建構函式。_maxsize_ 是一個整數,它設定可以放入佇列中的專案數量的上限。如果 _maxsize_ 小於或等於零,則佇列大小是無限的。

首先檢索最低值條目(最低值條目是 _min(entries)_ 將返回的條目)。條目的典型模式是形式為:

(priority_number, data)

示例

from time import sleep
from random import random, randint
from threading import Thread
from queue import PriorityQueue

queue = PriorityQueue()

def producer(queue):
   print('Producer: Running')
   for i in range(5):

      # create item with priority
      value = random()
      priority = randint(0, 5)
      item = (priority, value)
      queue.put(item)
   # wait for all items to be processed
   queue.join()

   queue.put(None)
   print('Producer: Done')

def consumer(queue):
   print('Consumer: Running')

   while True:

      # get a unit of work
      item = queue.get()
      if item is None:
         break

      sleep(item[1])
      print(item)
      queue.task_done()
   print('Consumer: Done')

producer = Thread(target=producer, args=(queue,))
producer.start()

consumer = Thread(target=consumer, args=(queue,))
consumer.start()

producer.join()
consumer.join()

它將產生以下**輸出**:

Producer: Running
Consumer: Running
(0, 0.15332707626852804)
(2, 0.4730737391435892)
(2, 0.8679231358257962)
(3, 0.051924220435665025)
(4, 0.23945882716108446)
Producer: Done
Consumer: Done

Python - 守護執行緒

有時,需要在後臺執行任務。一種特殊型別的執行緒用於後臺任務,稱為守護執行緒。換句話說,守護執行緒在後臺執行任務。

需要注意的是,守護執行緒執行這樣的非關鍵任務,雖然可能對應用程式有用,但如果它們失敗或在操作中途被取消,也不會妨礙應用程式。

此外,守護執行緒將無法控制何時終止。一旦所有非守護執行緒完成,程式將終止,即使此時仍有守護執行緒正在執行。

這是守護執行緒和非守護執行緒之間的主要區別。如果只有守護執行緒正在執行,則程序將退出;如果至少有一個非守護執行緒正在執行,則程序將無法退出。

守護執行緒 (Daemon) 非守護執行緒 (Non-daemon)
如果只有守護執行緒正在執行(或沒有執行緒正在執行),則程序將退出。 如果至少有一個非守護執行緒正在執行,則程序將不會退出。

建立守護執行緒

要建立守護執行緒,需要將 _daemon_ 屬性設定為 True。

t1=threading.Thread(daemon=True)

如果建立執行緒物件時沒有任何引數,則也可以在呼叫 _start()_ 方法之前將其 _daemon_ 屬性設定為 True。

t1=threading.Thread()
t1.daemon=True

示例

請看下面的例子:

from time import sleep
from threading import current_thread
from threading import Thread

# function to be executed in a new thread
def run():

   # get the current thread
   thread = current_thread()
   # is it a daemon thread?
   print(f'Daemon thread: {thread.daemon}')

# create a new thread
thread = Thread(target=run, daemon=True)

# start the new thread
thread.start()

# block for a 0.5 sec for daemon thread to run
sleep(0.5)

它將產生以下**輸出**:

Daemon thread: True

守護執行緒可以執行支援程式中非守護執行緒的任務。例如:

  • 建立在後臺儲存日誌資訊的檔案。

  • 在後臺執行網路抓取。

  • 自動將資料儲存到後臺的資料庫中。

示例

如果將正在執行的執行緒配置為守護執行緒,則會引發 _RuntimeError_。請看下面的例子:

from time import sleep
from threading import current_thread
from threading import Thread

# function to be executed in a new thread
def run():
   # get the current thread
   thread = current_thread()
   # is it a daemon thread?
   print(f'Daemon thread: {thread.daemon}')
   thread.daemon = True
   
# create a new thread
thread = Thread(target=run)

# start the new thread
thread.start()

# block for a 0.5 sec for daemon thread to run
sleep(0.5)

它將產生以下**輸出**:

Exception in thread Thread-1 (run):
Traceback (most recent call last):
. . . .
. . . .
   thread.daemon = True
   ^^^^^^^^^^^^^
 File "C:\Python311\Lib\threading.py", line 1219, in daemon
  raise RuntimeError("cannot set daemon status of active thread")
RuntimeError: cannot set daemon status of active thread

Python - 執行緒同步

Python 提供的 _threading_ 模組包含一個易於實現的鎖定機制,允許您同步執行緒。透過呼叫 _Lock()_ 方法建立一個新的鎖,該方法返回新的鎖。

新鎖物件的 _acquire(blocking)_ 方法用於強制執行緒同步執行。可選的 _blocking_ 引數允許您控制執行緒是否等待獲取鎖。

如果 _blocking_ 設定為 0,則如果無法獲取鎖,執行緒將立即返回 0 值;如果獲取了鎖,則返回 1。如果 _blocking_ 設定為 1,則執行緒將阻塞並等待鎖被釋放。

新鎖物件的release()方法用於在不再需要鎖定時釋放鎖。

示例

import threading
import time

class myThread (threading.Thread):
   def __init__(self, threadID, name, counter):
      threading.Thread.__init__(self)
      self.threadID = threadID
      self.name = name
      self.counter = counter
   def run(self):
      print ("Starting " + self.name)
      # Get lock to synchronize threads
      threadLock.acquire()
      print_time(self.name, self.counter, 3)
      # Free lock to release next thread
      threadLock.release()
      
def print_time(threadName, delay, counter):
   while counter:
      time.sleep(delay)
      print ("%s: %s" % (threadName, time.ctime(time.time())))
      counter -= 1
      
threadLock = threading.Lock()
threads = []

# Create new threads
thread1 = myThread(1, "Thread-1", 1)
thread2 = myThread(2, "Thread-2", 2)

# Start new Threads
thread1.start()
thread2.start()

# Add threads to thread list
threads.append(thread1)
threads.append(thread2)

# Wait for all threads to complete
for t in threads:
   t.join()
print ("Exiting Main Thread")

輸出

執行上述程式碼時,會產生以下輸出:

Starting Thread-1
Starting Thread-2
Thread-1: Thu Jul 13 21:10:11 2023
Thread-1: Thu Jul 13 21:10:12 2023
Thread-1: Thu Jul 13 21:10:13 2023
Thread-2: Thu Jul 13 21:10:15 2023
Thread-2: Thu Jul 13 21:10:17 2023
Thread-2: Thu Jul 13 21:10:19 2023
Exiting Main Thread

Python - 執行緒間通訊

執行緒共享分配給程序的記憶體。因此,同一程序中的執行緒可以相互通訊。為了促進執行緒間通訊,threading模組提供了Event物件和Condition物件。

Event 物件

Event物件管理內部標誌的狀態。該標誌最初為false,使用set()方法變為true,使用clear()方法重置為false。wait()方法會阻塞,直到標誌為true。

Event 物件的方法:

is_set() 方法

當且僅當內部標誌為true時返回True。

set() 方法

將內部標誌設定為true。所有等待它變為true的執行緒都被喚醒。一旦標誌為true,呼叫wait()的執行緒根本不會阻塞。

clear() 方法

將內部標誌重置為false。隨後,呼叫wait()的執行緒將阻塞,直到呼叫set()再次將內部標誌設定為true。

wait(timeout=None) 方法

阻塞直到內部標誌為true。如果在進入時內部標誌為true,則立即返回。否則,阻塞直到另一個執行緒呼叫set()將標誌設定為true,或直到可選的超時發生。

當timeout引數存在且不為None時,它應該是一個浮點數,以秒為單位指定操作的超時時間。

示例

以下程式碼嘗試模擬交通流量由交通訊號燈狀態(綠色或紅色)控制的情況。

程式中包含兩個執行緒,分別針對兩個不同的函式。signal_state()函式定期設定和重置事件,指示訊號從綠色變為紅色。

traffic_flow()函式等待事件被設定,並在事件保持設定狀態時執行一個迴圈。

from threading import *
import time

def signal_state():
   while True:
      time.sleep(5)
      print("Traffic Police Giving GREEN Signal")
      event.set()
      time.sleep(10)
      print("Traffic Police Giving RED Signal")
      event.clear()

def traffic_flow():
   num=0
   while num<10:
      print("Waiting for GREEN Signal")
      event.wait()
      print("GREEN Signal ... Traffic can move")
      while event.is_set():
         num=num+1
         print("Vehicle No:", num," Crossing the Signal")
         time.sleep(2)
      print("RED Signal ... Traffic has to wait")

event=Event()
t1=Thread(target=signal_state)
t2=Thread(target=traffic_flow)
t1.start()
t2.start()

輸出

Waiting for GREEN Signal
Traffic Police Giving GREEN Signal
GREEN Signal ... Traffic can move
Vehicle No: 1 Crossing the Signal
Vehicle No: 2 Crossing the Signal
Vehicle No: 3 Crossing the Signal
Vehicle No: 4 Crossing the Signal
Vehicle No: 5 Crossing the Signal
Signal is RED
RED Signal ... Traffic has to wait
Waiting for GREEN Signal
Traffic Police Giving GREEN Signal
GREEN Signal ... Traffic can move
Vehicle No: 6 Crossing the Signal
Vehicle No: 7 Crossing the Signal
Vehicle No: 8 Crossing the Signal
Vehicle No: 9 Crossing the Signal
Vehicle No: 10 Crossing the Signal

Condition 物件

threading模組中的Condition類實現條件變數物件。Condition物件強制一個或多個執行緒等待,直到被另一個執行緒通知。Condition與可重入鎖相關聯。Condition物件具有acquire()和release()方法,它們呼叫關聯鎖的相應方法。

threading.Condition(lock=None)

以下是Condition物件的 方法:

acquire(*args)

獲取底層鎖。此方法呼叫底層鎖上的相應方法;返回值是該方法返回的任何值。

release()

釋放底層鎖。此方法呼叫底層鎖上的相應方法;沒有返回值。

wait(timeout=None)

此方法釋放底層鎖,然後阻塞,直到被另一個執行緒對同一條件變數的notify()或notify_all()呼叫喚醒,或者直到可選的超時發生。一旦被喚醒或超時,它重新獲取鎖並返回。

wait_for(predicate, timeout=None)

此實用程式方法可能會重複呼叫wait(),直到滿足謂詞,或直到超時發生。返回值是謂詞的最後一個返回值,如果方法超時,則將評估為False。

notify(n=1)

此方法最多喚醒n個等待條件變數的執行緒;如果沒有執行緒正在等待,則它是一個空操作。

notify_all()

喚醒所有等待此條件的執行緒。此方法的作用類似於notify(),但喚醒所有等待執行緒而不是一個執行緒。如果呼叫執行緒在呼叫此方法時沒有獲取鎖,則會引發RuntimeError。

示例

在下面的程式碼中,執行緒t2執行taskB()函式,t1執行taskA()函式。t1執行緒獲取條件併發出通知。此時,t2執行緒處於等待狀態。條件釋放後,等待執行緒繼續使用通知函式生成的隨機數。

from threading import *
import time
import random

numbers=[]
def taskA(c):
   while True:
      c.acquire()
      num=random.randint(1,10)
      print("Generated random number:", num)
      numbers.append(num)
      print("Notification issued")
      c.notify()
      c.release()
      time.sleep(5)

def taskB(c):
   while True:
      c.acquire()
      print("waiting for update")
      c.wait()
      print("Obtained random number", numbers.pop())
      c.release()
      time.sleep(5)

c=Condition()
t1=Thread(target=taskB, args=(c,))
t2=Thread(target=taskA, args=(c,))
t1.start()
t2.start()

執行這段程式碼後,將產生以下輸出

waiting for update
Generated random number: 4
Notification issued
Obtained random number 4
waiting for update
Generated random number: 6
Notification issued
Obtained random number 6
waiting for update
Generated random number: 10
Notification issued
Obtained random number 10
waiting for update

Python - 執行緒死鎖

死鎖可以描述為一種併發故障模式。它是程式中的一種情況,其中一個或多個執行緒等待永遠不會發生的條件。結果,執行緒無法繼續執行,程式卡住或凍結,必須手動終止。

死鎖情況可能在您的併發程式中以多種方式出現。死鎖絕不是故意開發的,實際上,它們實際上是程式碼中的副作用或錯誤。

執行緒死鎖的常見原因如下:

  • 嘗試兩次獲取相同互斥鎖的執行緒。

  • 相互等待的執行緒(例如,A等待B,B等待A)。

  • 當執行緒未能釋放資源(例如鎖、訊號量、條件、事件等)時。

  • 以不同順序獲取互斥鎖的執行緒(例如,未能執行鎖排序)。

如果多執行緒應用程式中的多個執行緒嘗試訪問同一資源,例如對同一檔案執行讀/寫操作,則可能會導致資料不一致。因此,重要的是同步併發處理,以便當一個執行緒使用資源時,將其鎖定以防止其他執行緒訪問。

Python提供的threading模組包含一個易於實現的鎖定機制,允許您同步執行緒。透過呼叫Lock()方法建立一個新的鎖,該方法返回新的鎖。

Lock 物件

Lock類的物件有兩種可能的狀態:鎖定或解鎖,最初在建立時處於解鎖狀態。鎖不屬於任何特定執行緒。

Lock類定義了acquire()和release()方法。

acquire() 方法

當狀態為解鎖時,此方法將狀態更改為鎖定並立即返回。該方法採用可選的blocking引數。

語法

Lock.acquire(blocking, timeout)

引數

  • blocking - 如果設定為False,則表示不阻塞。如果設定blocking為True的呼叫會阻塞,則立即返回False;否則,將鎖設定為鎖定並返回True。

此方法的返回值為True,如果鎖成功獲取;否則為False。

release() 方法

當狀態為鎖定狀態時,此方法在另一個執行緒中將其更改為解鎖狀態。這可以從任何執行緒呼叫,而不只是獲取鎖的執行緒。

語法

Lock.release()

release()方法只能在鎖定狀態下呼叫。如果嘗試釋放解鎖的鎖,則會引發RuntimeError。

當鎖被鎖定,將其重置為解鎖,然後返回。如果任何其他執行緒阻塞等待鎖解鎖,則允許其中恰好一個執行緒繼續執行。此方法沒有返回值。

示例

在下面的程式中,兩個執行緒嘗試呼叫synchronized()方法。其中一個執行緒獲取鎖並獲得訪問許可權,而另一個執行緒等待。當第一個執行緒的run()方法完成時,鎖被釋放,synchronized方法可用於第二個執行緒。

當兩個執行緒都加入時,程式結束。

from threading import Thread, Lock
import time

lock=Lock()
threads=[]

class myThread(Thread):
   def __init__(self,name):
      Thread.__init__(self)
      self.name=name
   def run(self):
      lock.acquire()
      synchronized(self.name)
      lock.release()

def synchronized(threadName):
   print ("{} has acquired lock and is running synchronized method".format(threadName))
   counter=5
   while counter:
      print ('**', end='')
      time.sleep(2)
      counter=counter-1
   print('\nlock released for', threadName)

t1=myThread('Thread1')
t2=myThread('Thread2')

t1.start()
threads.append(t1)

t2.start()
threads.append(t2)

for t in threads:
   t.join()
print ("end of main thread")

它將產生以下**輸出**:

Thread1 has acquired lock and is running synchronized method
**********
lock released for Thread1
Thread2 has acquired lock and is running synchronized method
**********
lock released for Thread2
end of main thread

Semaphore 物件

Python使用另一種稱為訊號量的機制支援執行緒同步。這是著名的計算機科學家Edsger W. Dijkstra發明的最古老的同步技術之一。

訊號量的基本概念是使用一個內部計數器,每個acquire()呼叫遞減,每個release()呼叫遞增。計數器永遠不會低於零;當acquire()發現它為零時,它會阻塞,等待直到其他一些執行緒呼叫release()。

threading模組中的Semaphore類定義了acquire()和release()方法。

acquire() 方法

如果在進入時內部計數器大於零,則將其減一併立即返回True。

如果在進入時內部計數器為零,則阻塞直到被對release()的呼叫喚醒。一旦被喚醒(並且計數器大於0),則將計數器減1並返回True。每個對release()的呼叫都將喚醒恰好一個執行緒。執行緒喚醒的順序是任意的。

如果blocking引數設定為False,則不阻塞。如果沒有任何引數的呼叫會阻塞,則立即返回False;否則,執行與不帶引數呼叫相同的事情,並返回True。

release() 方法

釋放訊號量,將內部計數器加1。當它在進入時為零並且其他執行緒正在等待它再次大於零時,喚醒n個這些執行緒。

示例

from threading import *
import time

# creating thread instance where count = 3
lock = Semaphore(4)

# creating instance
def synchronized(name):
   
   # calling acquire method
   lock.acquire()

   for n in range(3):
      print('Hello! ', end = '')
      time.sleep(1)
      print( name)

      # calling release method
      lock.release()

# creating multiple thread
thread_1 = Thread(target = synchronized , args = ('Thread 1',))
thread_2 = Thread(target = synchronized , args = ('Thread 2',))
thread_3 = Thread(target = synchronized , args = ('Thread 3',))

# calling the threads
thread_1.start()
thread_2.start()
thread_3.start()

它將產生以下**輸出**:

Hello! Hello! Hello! Thread 1
Hello! Thread 2
Thread 3
Hello! Hello! Thread 1
Hello! Thread 3
Thread 2
Hello! Hello! Thread 1
Thread 3
Thread 2

Python - 中斷執行緒

在多執行緒程式中,新執行緒中的任務可能需要停止。這可能是由於許多原因,例如:(a) 不再需要任務的結果,或者 (b) 任務的結果出錯,或者 (c) 應用程式正在關閉。

可以使用threading.Event物件停止執行緒。Event物件管理內部標誌的狀態,該標誌可以設定為已設定或未設定。

建立新的Event物件時,其標誌最初未設定(false)。如果一個執行緒呼叫其set()方法,則可以在另一個執行緒中檢查其標誌值。如果發現為true,則可以終止其活動。

示例

在此示例中,我們有一個MyThread類。其物件開始執行run()方法。主執行緒休眠一段時間,然後設定一個事件。在檢測到事件之前,run()方法中的迴圈會繼續。一旦檢測到事件,迴圈就會終止。

from time import sleep
from threading import Thread
from threading import Event

class MyThread(Thread):
   def __init__(self, event):
      super(MyThread, self).__init__()
      self.event = event

   def run(self):
      i=0
      while True:
         i+=1
         print ('Child thread running...',i)
         sleep(0.5)
         if self.event.is_set():
            break
         print()
      print('Child Thread Interrupted')

event = Event()
thread1 = MyThread(event)
thread1.start()

sleep(3)
print('Main thread stopping child thread')
event.set()
thread1.join()

執行這段程式碼後,將產生以下輸出

Child thread running... 1
Child thread running... 2
Child thread running... 3
Child thread running... 4
Child thread running... 5
Child thread running... 6
Main thread stopping child thread
Child Thread Interrupted

Python - 網路程式設計

Python標準庫中的threading模組能夠處理單個程序中的多個執行緒及其互動。執行在同一臺機器上的兩個程序之間的通訊由Unix域套接字處理,而對於執行在透過TCP(傳輸控制協議)連線的不同機器上的程序,則使用Internet域套接字。

network_programming

Python的標準庫包含各種支援程序間通訊和網路的內建模組。Python提供了兩級訪問網路服務的許可權。在低級別,您可以訪問底層作業系統中的基本套接字支援,這允許您為面向連線和無連線協議實現客戶端和伺服器。

Python還擁有提供對特定應用程式級網路協議(例如FTP、HTTP等)的更高級別訪問的庫。

協議 常用功能 埠號 Python模組
HTTP 網頁 80 httplib, urllib, xmlrpclib
NNTP Usenet新聞 119 nntplib
FTP 檔案傳輸 20 ftplib, urllib
SMTP 傳送電子郵件 25 smtplib
POP3 獲取電子郵件 110 poplib
IMAP4 獲取電子郵件 143 imaplib
Telnet 命令列 23 telnetlib
Gopher 文件傳輸 70 gopherlib, urllib

Python - Socket 程式設計

標準庫中的socket模組包含伺服器和客戶端在硬體級別通訊所需的功能。

此模組提供對BSD套接字介面的訪問。它適用於所有作業系統,例如Linux、Windows、MacOS。

什麼是套接字?

套接字是雙向通訊通道的端點。套接字可以在程序內、同一臺機器上的程序之間或不同大陸上的程序之間進行通訊。

套接字由IP地址和埠號的組合標識。它應該在兩端正確配置才能開始通訊。

connection IP_address

套接字可以實現多種不同的通道型別:Unix域套接字、TCP、UDP等等。套接字型檔提供用於處理常用傳輸的特定類,以及用於處理其餘傳輸的通用介面。

套接字程式設計意味著以程式設計方式設定套接字,以便能夠傳送和接收資料。

有兩種型別的通訊協議:

  • 面向連線的協議

  • 無連線協議

TCP或傳輸控制協議是一種面向連線的協議。資料由伺服器以資料包的形式傳輸,並按照相同的傳輸順序由接收方組裝。由於通訊兩端的套接字需要在開始之前設定,因此此方法更可靠。

UDP或使用者資料報協議是無連線的。此方法不可靠,因為套接字不需要建立任何連線和終止過程來傳輸資料。

Python socket模組

此模組包含Socket類。套接字物件表示主機名和埠號對。構造方法具有以下簽名:

語法

socket.socket (socket_family, socket_type, protocol=0)

引數

  • family – 預設情況下為AF_INET。其他值 - AF_INET6(八組四個十六進位制數字)、AF_UNIX、AF_CAN(控制器區域網)或AF_RDS(可靠資料報套接字)。

  • socket_type – 應為SOCK_STREAM(預設值)、SOCK_DGRAM、SOCK_RAW或其他SOCK_常量之一。

  • protocol – 數字通常為零,可以省略。

返回值型別

此方法返回一個套接字物件。

獲得套接字物件後,可以使用所需的方法建立客戶端或伺服器程式。

伺服器套接字方法

在伺服器上例項化的套接字稱為伺服器套接字。伺服器上的套接字物件可以使用以下方法:

  • bind() 方法 – 此方法將套接字繫結到指定的IP地址和埠號。

  • listen() 方法 – 此方法啟動伺服器並進入監聽迴圈,查詢來自客戶端的連線請求。

  • accept() 方法 – 當伺服器攔截連線請求時,此方法接受請求並使用其地址標識客戶端套接字。

要在伺服器上建立套接字,請使用以下程式碼片段:

import socket
server = socket.socket()
server.bind(('localhost',12345))
server.listen()
client, addr = server.accept()
print ("connection request from: " + str(addr))

預設情況下,伺服器繫結到本地機器的IP地址“localhost”,偵聽任意空閒埠號。

客戶端套接字方法

在客戶端也設定了類似的套接字。它主要向在其IP地址和埠號上偵聽的伺服器套接字傳送連線請求。

connect() 方法

此方法將一個包含兩個專案的元組物件作為引數。這兩個專案是伺服器的IP地址和埠號。

obj=socket.socket()
obj.connect((host,port))

伺服器接受連線後,兩個套接字物件都可以傳送和/或接收資料。

send() 方法

伺服器使用它攔截的地址將資料傳送到客戶端。

client.send(bytes)

客戶端套接字將資料傳送到它已建立連線的套接字。

sendall() 方法

類似於send()。但是,與send()不同的是,此方法會繼續從位元組傳送資料,直到所有資料已傳送或發生錯誤為止。成功時不返回任何值。

sendto() 方法

此方法僅在UDP協議的情況下使用。

recv() 方法

此方法用於檢索傳送到客戶端的資料。在伺服器的情況下,它使用已接受請求的遠端套接字。

client.recv(bytes)

recvfrom() 方法

此方法在UDP協議的情況下使用。

Python - Socket 伺服器

要編寫Internet伺服器,我們使用socket模組中提供的socket函式來建立一個套接字物件。然後使用套接字物件呼叫其他函式來設定套接字伺服器。

現在呼叫bind(hostname, port)函式來為給定主機上的服務指定一個埠。

接下來,呼叫返回物件的accept方法。此方法等待客戶端連線到您指定的埠,然後返回一個連線物件,該物件表示與該客戶端的連線。

import socket
host = "127.0.0.1"
port = 5001
server = socket.socket()
server.bind((host,port))
server.listen()
conn, addr = server.accept()
print ("Connection from: " + str(addr))
while True:
   data = conn.recv(1024).decode()
   if not data:
      break
   data = str(data).upper()
   print (" from client: " + str(data))
   data = input("type message: ")
   conn.send(data.encode())
conn.close()

Python - Socket 客戶端

讓我們編寫一個非常簡單的客戶端程式,它開啟到給定埠5001和給定localhost的連線。使用Python的socket模組函式建立套接字客戶端非常簡單。

socket.connect(hosname, port)開啟到埠上主機名的TCP連線。開啟套接字後,您可以像任何IO物件一樣從中讀取資料。完成後,請記住關閉它,就像關閉檔案一樣。

以下程式碼是一個非常簡單的客戶端,它連線到給定的主機和埠,從套接字讀取任何可用資料,然後在輸入“q”時退出。

import socket
host = '127.0.0.1'
port = 5001
obj = socket.socket()
obj.connect((host,port))
message = input("type message: ")
while message != 'q':
   obj.send(message.encode())
   data = obj.recv(1024).decode()
   print ('Received from server: ' + data)
   message = input("type message: ")
obj.close()
  • 先執行伺服器程式碼。它開始監聽。

  • 然後啟動客戶端程式碼。它傳送請求。

  • 請求已接受。客戶端地址已識別

  • 輸入一些文字並按Enter鍵。

  • 接收到的資料被列印。將資料傳送到客戶端。

  • 收到來自伺服器的資料。

  • 輸入“q”時迴圈終止。

伺服器-客戶端互動如下所示:

server_client_interaction

我們已經在本地機器上使用socket模組實現了客戶端-伺服器通訊。要將伺服器和客戶端程式碼放在網路上的兩臺不同的機器上,我們需要找到伺服器機器的IP地址。

在Windows上,您可以透過執行ipconfig命令來查詢IP地址。ifconfig命令是Ubuntu上的等效命令。

ipv4_address

使用IPv4地址值更改伺服器和客戶端程式碼中的主機字串,然後像以前一樣執行它們。

使用Socket模組進行Python檔案傳輸

以下程式演示如何使用套接字通訊將檔案從伺服器傳輸到客戶端。

伺服器程式碼

建立連線的程式碼與之前相同。接受連線請求後,伺服器上的檔案將以二進位制模式開啟以進行讀取,並且位元組將連續讀取併發送到客戶端流,直到達到檔案結尾。

import socket
host = "127.0.0.1"
port = 5001
server = socket.socket()
server.bind((host, port))
server.listen()
conn, addr = server.accept()
data = conn.recv(1024).decode()
filename='test.txt'
f = open(filename,'rb')
while True:
   l = f.read(1024)
   if not l:
      break
   conn.send(l)
   print('Sent ',repr(l))
f.close()
print('File transferred')
conn.close()

客戶端程式碼

在客戶端,一個新檔案以wb模式開啟。從伺服器接收到的資料流被寫入檔案。隨著流的結束,輸出檔案被關閉。客戶端機器上將建立一個新檔案。

import socket

s = socket.socket()
host = "127.0.0.1"
port = 5001

s.connect((host, port))
s.send("Hello server!".encode())

with open('recv.txt', 'wb') as f:
   while True:
      print('receiving data...')
      data = s.recv(1024)
      if not data:
         break
      f.write(data)
      
f.close()
print('Successfully received')
s.close()
print('connection closed')

Python socketserver模組

Python標準庫中的socketserver模組是一個框架,用於簡化編寫網路伺服器的任務。模組中包含以下類,它們表示同步伺服器:

socketserver_module

這些類與相應的RequestHandler類一起工作以實現服務。BaseServer是模組中所有Server物件的超類。

TCPServer類使用網際網路TCP協議,在客戶端和伺服器之間提供連續的資料流。建構函式自動嘗試呼叫server_bind()和server_activate()。其他引數傳遞給BaseServer基類。

您還必須建立一個StreamRequestHandler類的子類。它提供self.rfile和self.wfile屬性來讀取或寫入以獲取請求資料或將資料返回給客戶端。

  • UDPServerDatagramRequestHandler – 這些類用於UDP協議。

  • DatagramRequestHandlerUnixDatagramServer – 這些類使用Unix域套接字;它們在非Unix平臺上不可用。

伺服器程式碼

您必須編寫一個RequestHandler類。它為每個與伺服器的連線例項化一次,並且必須覆蓋handle()方法以實現與客戶端的通訊。

import socketserver
class MyTCPHandler(socketserver.BaseRequestHandler):
   def handle(self):
      self.data = self.request.recv(1024).strip()
      host,port=self.client_address
      print("{}:{} wrote:".format(host,port))
      print(self.data.decode())
      msg=input("enter text .. ")
      self.request.sendall(msg.encode())

在伺服器分配的埠號上,TCPServer類的物件呼叫forever()方法將伺服器置於監聽模式,並接受來自客戶端的傳入請求。

if __name__ == "__main__":
   HOST, PORT = "localhost", 9999
   with socketserver.TCPServer((HOST, PORT), MyTCPHandler) as server:
      server.serve_forever()

客戶端程式碼

使用socketserver時,客戶端程式碼與socket客戶端應用程式大致相似。

import socket
import sys

HOST, PORT = "localhost", 9999

while True:
   with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
      # Connect to server and send data
      sock.connect((HOST, PORT))
      data = input("enter text .. .")
      sock.sendall(bytes(data + "\n", "utf-8"))
      
      # Receive data from the server and shut down
      received = str(sock.recv(1024), "utf-8")
      print("Sent: {}".format(data))
      print("Received: {}".format(received))

在一個命令提示符終端中執行伺服器程式碼。為客戶端例項開啟多個終端。您可以模擬伺服器和多個客戶端之間的併發通訊。

伺服器 客戶端-1 客戶端-2

D:\socketsrvr>python myserver.py

127.0.0.1:54518 wrote

from client-1

enter text ..

hello

127.0.0.1:54522 wrote

how are you

enter text ..

fine

127.0.0.1:54523 wrote

from client-2

enter text ..

hi client-2

127.0.0.1:54526 wrote

good bye

enter text ..

bye bye

127.0.0.1:54530 wrote

thanks

enter text ..

bye client-2

D:\socketsrvr>python myclient.py

enter text .. .

from client-1

Sent

from client-1

Received: hello

enter text .. .

how are you

Sent

how are you

Received: fine

enter text .. .

good bye

Sent: good bye

Received: bye bye

enter text .. .

D:\socketsrvr>python myclient.py

enter text .. .

from client-2

Sent

from client-2

Received: hi client-2

enter text .. .

thanks

Sent: thanks

Received

bye client-2

enter text .. .

Python - URL 處理

在網際網路世界中,不同的資源由URL(統一資源定位符)標識。與Python標準庫捆綁在一起的urllib包提供了一些處理URL的實用程式。它包含以下模組:

  • urllib.parse模組用於將URL解析為其各個部分。

  • urllib.request模組包含用於開啟和讀取URL的函式。

  • urllib.error模組包含urllib.request引發的異常的定義。

  • urllib.robotparser模組解析robots.txt檔案。

urllib.parse模組

此模組作為標準介面,用於從URL字串中獲取各個部分。該模組包含以下函式:

urlparse(urlstring)

將URL解析為六個元件,返回一個包含6個專案的命名元組。每個元組專案都是一個字串,對應於以下屬性:

屬性 索引
scheme 0 URL方案說明符
netloc 1 網路位置部分
path 2 分層路徑
params 3 最後一個路徑元素的引數
query 4 查詢元件
fragment 5 片段識別符號
username 使用者名稱
password 密碼
hostname 主機名(小寫)
Port 埠號(整數,如果存在)

示例

from urllib.parse import urlparse
url = "https://example.com/employees/name/?salary>=25000"
parsed_url = urlparse(url)
print (type(parsed_url))
print ("Scheme:",parsed_url.scheme)
print ("netloc:", parsed_url.netloc)
print ("path:", parsed_url.path)
print ("params:", parsed_url.params)
print ("Query string:", parsed_url.query)
print ("Frgment:", parsed_url.fragment)

它將產生以下**輸出**:

<class 'urllib.parse.ParseResult'>
Scheme: https
netloc: example.com
path: /employees/name/
params:
Query string: salary>=25000
Frgment:

parse_qs(qs))

此函式解析作為字串引數給出的查詢字串。資料作為字典返回。字典鍵是唯一的查詢變數名,值是每個名稱的值列表。

要進一步將查詢字串中的查詢引數提取到字典中,請按如下方式使用ParseResult物件的query屬性的parse_qs()函式:

from urllib.parse import urlparse, parse_qs
url = "https://example.com/employees?name=Anand&salary=25000"
parsed_url = urlparse(url)
dct = parse_qs(parsed_url.query)
print ("Query parameters:", dct)

它將產生以下**輸出**:

Query parameters: {'name': ['Anand'], 'salary': ['25000']}

urlsplit(urlstring)

這類似於urlparse(),但不從URL中拆分params。如果需要允許將引數應用於URL路徑部分的每個段的較新URL語法,則通常應使用它而不是urlparse()。

urlunparse(parts)

此函式是 urlparse() 函式的反函式。它根據 urlparse() 函式返回的元組構造 URL。parts 引數可以是任何六項可迭代物件。這將返回一個等效的 URL。

示例

from urllib.parse import urlunparse

lst = ['https', 'example.com', '/employees/name/', '', 'salary>=25000', '']
new_url = urlunparse(lst)
print ("URL:", new_url)

它將產生以下**輸出**:

URL: https://example.com/employees/name/?salary>=25000

urlunsplit(parts)

將 urlsplit() 返回的元組元素組合成一個完整的 URL 字串。parts 引數可以是任何五項可迭代物件。

urllib.request 模組

此模組定義了有助於開啟 URL 的函式和類。

urlopen() 函式

此函式開啟給定的 URL,該 URL 可以是字串或 Request 物件。可選的 timeout 引數指定阻塞操作的超時時間(以秒為單位)。實際上,這僅適用於 HTTP、HTTPS 和 FTP 連線。

此函式始終返回一個可以用作上下文管理器並具有 url、headers 和 status 屬性的物件。

對於 HTTP 和 HTTPS URL,此函式返回一個略微修改過的 http.client.HTTPResponse 物件。

示例

以下程式碼使用 urlopen() 函式讀取影像檔案的二進位制資料,並將其寫入本地檔案。您可以使用任何影像檢視器在您的計算機上開啟影像檔案。

from urllib.request import urlopen
obj = urlopen("https://tutorialspoint.tw/static/images/simply-easy-learning.jpg")
data = obj.read()
img = open("img.jpg", "wb")
img.write(data)
img.close()

它將產生以下**輸出**:

urllib_request

Request 物件

urllib.request 模組包含 Request 類。此類是對 URL 請求的抽象。建構函式需要一個必需的字串引數,即有效的 URL。

語法

urllib.request.Request(url, data, headers, origin_req_host, method=None)

引數

  • url − 一個有效的 URL 字串

  • data − 指定要傳送到伺服器的其他資料的物件。此引數只能與 HTTP 請求一起使用。資料可以是位元組、類檔案物件和位元組類物件的迭代器。

  • headers − 應該是標頭及其關聯值的字典。

  • origin_req_host − 應該是原始事務的請求主機

  • method − 應該是指示 HTTP 請求方法的字串。GET、POST、PUT、DELETE 和其他 HTTP 動詞之一。預設為 GET。

示例

from urllib.request import Request
obj = Request("https://tutorialspoint.tw/")

此 Request 物件現在可以用作 urlopen() 方法的引數。

from urllib.request import Request, urlopen
obj = Request("https://tutorialspoint.tw/")
resp = urlopen(obj)

urlopen() 函式返回一個 HttpResponse 物件。呼叫其 read() 方法可以獲取給定 URL 上的資源。

from urllib.request import Request, urlopen
obj = Request("https://tutorialspoint.tw/")
resp = urlopen(obj)
data = resp.read()
print (data)

傳送資料

如果將 data 引數定義為 Request 建構函式,則將向伺服器傳送 POST 請求。資料應該是以位元組表示的任何物件。

示例

from urllib.request import Request, urlopen
from urllib.parse import urlencode

values = {'name': 'Madhu',
   'location': 'India',
   'language': 'Hindi' }
data = urlencode(values).encode('utf-8')
obj = Request("https://example.com", data)

傳送標頭

Request 建構函式還接受 header 引數,以便將標頭資訊推送到請求中。它應該是一個字典物件。

headers = {'User-Agent': user_agent}
obj = Request("https://example.com", data, headers)

urllib.error 模組

urllib.error 模組中定義了以下異常:

URLError

由於沒有網路連線(沒有到指定伺服器的路由)或指定的伺服器不存在,因此引發 URLError。在這種情況下,引發的異常將具有 'reason' 屬性。

from urllib.request import Request, urlopen
import urllib.error as err

obj = Request("http://www.nosuchserver.com")
try:
   urlopen(obj)
except err.URLError as e:
   print(e)

它將產生以下**輸出**:

HTTP Error 403: Forbidden

HTTPError

每次伺服器傳送 HTTP 響應時,它都與一個數字“狀態程式碼”相關聯。該程式碼指示伺服器為何無法完成請求。預設處理程式將為您處理其中一些響應。對於它無法處理的那些響應,urlopen() 函式將引發 HTTPError。HTTPErrors 的典型示例是“404”(未找到頁面),“403”(請求被禁止)和“401”(需要身份驗證)。

from urllib.request import Request, urlopen
import urllib.error as err

obj = Request("https://python.club.tw/fish.html")
try:
   urlopen(obj)
except err.HTTPError as e:
   print(e.code)

它將產生以下**輸出**:

404

Python - 泛型

在 Python 中,泛型是一種機制,您可以使用它來定義可以在多個型別上運行同時保持型別安全的函式、類或方法。透過泛型的實現,可以編寫可重用且可在不同資料型別中使用的程式碼。它確保提高程式碼靈活性和型別正確性。

Python 中的泛型使用型別提示實現。此功能從 Python 3.5 版本開始引入。

通常,您不需要宣告變數型別。型別由分配給它的值動態確定。Python 直譯器不執行型別檢查,因此可能會引發執行時異常。

Python 的新型別提示功能有助於提示使用者要傳遞的引數的預期型別。

型別提示允許您指定變數、函式引數和返回值的預期型別。泛型透過引入型別變數擴充套件了此功能,型別變量表示在使用泛型函式或類時可以替換為特定型別的泛型型別。

示例1

讓我們來看一下定義泛型函式的以下示例:

from typing import List, TypeVar, Generic
T = TypeVar('T')
def reverse(items: List[T]) -> List[T]:
   return items[::-1]

在這裡,我們定義了一個名為“reverse”的泛型函式。該函式接受一個列表('List[T]')作為引數,並返回相同型別的列表。型別變數“T”表示泛型型別,在使用該函式時將用特定型別替換。

示例2

reverse() 函式使用不同的資料型別呼叫:

numbers = [1, 2, 3, 4, 5]
reversed_numbers = reverse(numbers)
print(reversed_numbers)

fruits = ['apple', 'banana', 'cherry']
reversed_fruits = reverse(fruits)
print(reversed_fruits)

它將產生以下**輸出**:

[5, 4, 3, 2, 1]
['cherry', 'banana', 'apple']

示例3

以下示例將泛型與泛型類一起使用:

from typing import List, TypeVar, Generic
T = TypeVar('T')
class Box(Generic[T]):
   def __init__(self, item: T):
      self.item = item
   def get_item(self) -> T:
      return self.item
Let us create objects of the above generic class with int and str type
box1 = Box(42)
print(box1.get_item())

box2 = Box('Hello')
print(box2.get_item())

它將產生以下**輸出**:

42
Hello

Python - 日期和時間

Python 程式可以透過多種方式處理日期和時間。在日期格式之間進行轉換是計算機的常見任務。Python 標準庫中的以下模組處理與日期和時間相關的處理:

  • DateTime 模組

  • Time 模組

  • Calendar 模組

什麼是 Tick 區間?

時間間隔是以秒為單位的浮點數。特定時刻以自 1970 年 1 月 1 日凌晨 12:00(紀元)以來的秒數表示。

Python 中有一個常用的time模組,它提供用於處理時間以及在表示之間進行轉換的函式。函式time.time()返回自 1970 年 1 月 1 日凌晨 12:00(紀元)以來的滴答數表示的當前系統時間。

示例

import time # This is required to include time module.
ticks = time.time()
print ("Number of ticks since 12:00am, January 1, 1970:", ticks)

這將產生如下結果:

Number of ticks since 12:00am, January 1, 1970: 1681928297.5316436

使用滴答數進行日期運算很容易。但是,紀元之前的日期不能以這種形式表示。遙遠的將來的日期也無法以這種方式表示 - UNIX 和 Windows 的截止點是在 2038 年的某個時候。

什麼是 TimeTuple?

許多 Python 的時間函式將時間處理為包含 9 個數字的元組,如下所示:

索引 欄位
0 4 位數年 2016
1 1 到 12
2 1 到 31
3 小時 0 到 23
4 分鐘 0 到 59
5 0 到 61(60 或 61 是閏秒)
6 星期幾 0 到 6(0 是星期一)
7 一年中的第幾天 1 到 366(儒略日)
8 夏令時 -1、0、1,-1 表示庫確定 DST

例如:

>>>import time
>>> print (time.localtime())

這將產生如下輸出

time.struct_time(tm_year=2023, tm_mon=4, tm_mday=19, tm_hour=23, tm_min=49, tm_sec=8, tm_wday=2, tm_yday=109, tm_isdst=0)

上述元組等效於 struct_time 結構。此結構具有以下屬性:

索引 屬性
0 tm_year 2016
1 tm_mon 1 到 12
2 tm_mday 1 到 31
3 tm_hour 0 到 23
4 tm_min 0 到 59
5 tm_sec 0 到 61(60 或 61 是閏秒)
6 tm_wday 0 到 6(0 是星期一)
7 tm_yday 1 到 366(儒略日)
8 tm_isdst -1、0、1,-1 表示庫確定 DST

獲取當前時間

要將自紀元以來的秒數浮點值的時間瞬間轉換為時間元組,請將浮點值傳遞給返回具有所有有效九個專案的 time 元組的函式(例如,localtime)。

import time
localtime = time.localtime(time.time())
print ("Local current time :", localtime)

這將產生以下結果,可以將其格式化為任何其他可表示的形式:

Local current time : time.struct_time(tm_year=2023, tm_mon=4, tm_mday=19, tm_hour=23, tm_min=42, tm_sec=41, tm_wday=2, tm_yday=109, tm_isdst=0)

獲取格式化的時間

您可以根據需要格式化任何時間,但是獲取易於閱讀的格式的時間的一種簡單方法是asctime()

import time

localtime = time.asctime( time.localtime(time.time()) )
print ("Local current time :", localtime)

這將產生以下輸出

Local current time : Wed Apr 19 23:45:27 2023

獲取一個月的日曆

calendar 模組提供了各種方法來處理年曆和月曆。在這裡,我們列印給定月份(2008 年 1 月)的日曆。

import calendar
cal = calendar.month(2023, 4)
print ("Here is the calendar:")
print (cal)

這將產生以下輸出

Here is the calendar:
     April 2023
Mo Tu We Th Fr Sa Su
                1  2
 3  4  5  6  7  8  9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30

time 模組

Python 中有一個常用的time模組,它提供用於處理時間以及在表示之間進行轉換的函式。以下是所有可用方法的列表。

序號 帶有說明的函式
1 time.altzone

如果定義了本地 DST 時區,則其相對於 UTC 的偏移量(以秒為單位),如果定義了本地 DST 時區,則為負值,如果本地 DST 時區在 UTC 以東(如西歐,包括英國)。僅當 daylight 非零時才使用此值。

2 time.asctime([tupletime])

接受一個時間元組並返回一個可讀的 24 個字元的字串,例如“Tue Dec 11 18:07:14 2008”。

3 time.clock( )

以浮點數秒的形式返回當前 CPU 時間。為了測量不同方法的計算成本,time.clock 的值比 time.time() 的值更有用。

4 time.ctime([secs])

類似於 asctime(localtime(secs)),如果沒有引數,則類似於 asctime( )

5 time.gmtime([secs])

接受以自紀元以來的秒數表示的瞬間,並返回一個包含 UTC 時間的 time 元組 t。注意:t.tm_isdst 始終為 0

6 time.localtime([secs])

接受以自紀元以來的秒數表示的瞬間,並返回一個包含本地時間的時間元組 t(t.tm_isdst 為 0 或 1,具體取決於 DST 是否根據本地規則適用於瞬間 secs)。

7 time.mktime(tupletime)

接受以本地時間表示為時間元組的瞬間,並返回一個浮點值,其中包含以自紀元以來的秒數表示的瞬間。

8 time.sleep(secs)

將呼叫執行緒掛起 secs 秒。

9 time.strftime(fmt[,tupletime])

接受以本地時間表示為時間元組的瞬間,並返回一個字串,該字串表示由字串 fmt 指定的瞬間。

10 time.strptime(str,fmt='%a %b %d %H:%M:%S %Y')

根據格式字串 fmt 解析 str,並以時間元組格式返回瞬間。

11 time.time( )

返回當前時間瞬間,即自紀元以來的浮點數秒。

12 time.tzset()

重置庫例程使用的時區轉換規則。環境變數 TZ 指定如何執行此操作。

讓我們簡要介紹一下這些函式。

time 模組有兩個重要的屬性。它們是:

序號 帶有說明的屬性
1

time.timezone

屬性 time.timezone 是本地時區(不含 DST)相對於 UTC 的偏移量(在美洲 >0;在大多數歐洲、亞洲、非洲 <=0)。

2

time.tzname

屬性 time.tzname 是一對與區域設定相關的字串,它們分別是本地時區(不含 DST)和含 DST 的名稱。

calendar 模組

calendar 模組提供與日曆相關的函式,包括列印給定月份或年份的文字日曆的函式。

預設情況下,calendar 將星期一作為一週的第一天,將星期日作為最後一天。要更改此設定,請呼叫calendar.setfirstweekday()函式。

以下是calendar模組中可用函式的列表:

序號 帶有說明的函式
1

calendar.calendar(year,w=2,l=1,c=6)

返回一個多行字串,包含 year 年份的日曆,格式化為三列,列間用 c 個空格隔開。w 是每個日期的字元寬度;每行的長度為 21*w+18+2*c。l 是每一週的行數。

2

calendar.firstweekday( )

返回當前一週開始日期的設定。預設情況下,首次匯入 calendar 時,此值為 0,表示星期一。

3

calendar.isleap(year)

如果 year 是閏年,則返回 True;否則返回 False。

4

calendar.leapdays(y1,y2)

返回 range(y1,y2) 範圍內年份的閏年總數。

5

calendar.month(year,month,w=2,l=1)

返回一個多行字串,包含 year 年 month 月份的日曆,每行表示一週,另加兩行標題。w 是每個日期的字元寬度;每行的長度為 7*w+6。l 是每一週的行數。

6

calendar.monthcalendar(year,month)

返回一個整數列表的列表。每個子列表表示一週。year 年 month 月之外的日期設定為 0;該月內的日期設定為其月份中的日期,從 1 開始。

7

calendar.monthrange(year,month)

返回兩個整數。第一個是 year 年 month 月份第一天對應的星期幾的程式碼;第二個是該月的總天數。星期幾程式碼為 0(星期一)到 6(星期日);月份數字為 1 到 12。

8

calendar.prcal(year,w=2,l=1,c=6)

類似於 print calendar.calendar(year,w,l,c)。

9

calendar.prmonth(year,month,w=2,l=1)

類似於 print calendar.month(year,month,w,l)。

10

calendar.setfirstweekday(weekday)

將每一週的第一天設定為星期幾程式碼 weekday。星期幾程式碼為 0(星期一)到 6(星期日)。

11

calendar.timegm(tupletime)

time.gmtime 的逆函式:接受時間元組形式的時間點,並返回自紀元以來的浮點型秒數。

12

calendar.weekday(year,month,day)

返回給定日期的星期幾程式碼。星期幾程式碼為 0(星期一)到 6(星期日);月份數字為 1(一月)到 12(十二月)。

datetime 模組

Python 的 datetime 模組包含在標準庫中。它包含有助於操作日期和時間資料並執行日期時間運算的類。

datetime 類的物件要麼是已知時區的,要麼是未知時區的。如果物件包含時區資訊,則它是已知時區的;否則,它被歸類為未知時區的。date 類物件是未知時區的,而 time 和 datetime 物件是已知時區的。

date

date 物件表示一個日期,包含年、月和日。當前的格里高利曆在兩個方向上無限期地擴充套件。

語法

datetime.date(year, month, day)

引數必須是整數,範圍如下:

  • year − MINYEAR <= year <= MAXYEAR

  • month − 1 <= month <= 12

  • day − 1 <= day <= 給定月份和年份的天數

如果任何引數的值超出這些範圍,則會引發 ValueError。

示例

from datetime import date
date1 = date(2023, 4, 19)
print("Date:", date1)
date2 = date(2023, 4, 31)

它將產生以下**輸出**:

Date: 2023-04-19
Traceback (most recent call last):
 File "C:\Python311\hello.py", line 8, in <module>
  date2 = date(2023, 4, 31)
ValueError: day is out of range for month

date 類屬性

  • date.min − 可表示的最早日期,date(MINYEAR, 1, 1)。

  • date.max − 可表示的最新日期,date(MAXYEAR, 12, 31)。

  • date.resolution − 不同 date 物件之間可能的最小差值。

  • date.year − 包含在 MINYEAR 和 MAXYEAR 之間。

  • date.month − 包含在 1 和 12 之間。

  • date.day − 包含在 1 和給定年份給定月份的天數之間。

示例

from datetime import date

# Getting min date
mindate = date.min
print("Minimum Date:", mindate)

# Getting max date
maxdate = date.max
print("Maximum Date:", maxdate)

Date1 = date(2023, 4, 20)
print("Year:", Date1.year)
print("Month:", Date1.month)
print("Day:", Date1.day)

它將產生以下**輸出**:

Minimum Date: 0001-01-01
Maximum Date: 9999-12-31
Year: 2023
Month: 4
Day: 20

date 類中的類方法

  • today() − 返回當前本地日期。

  • fromtimestamp(timestamp) − 返回與 POSIX 時間戳對應的本地日期,例如 time.time() 返回的日期。

  • fromordinal(ordinal) − 返回與儒略日對應的日期,其中公元 1 年 1 月 1 日的儒略日為 1。

  • fromisoformat(date_string) − 返回與任何有效的 ISO 8601 格式的 date_string 對應的日期,序數日期除外。

示例

from datetime import date

print (date.today())
d1=date.fromisoformat('2023-04-20')
print (d1)
d2=date.fromisoformat('20230420')
print (d2)
d3=date.fromisoformat('2023-W16-4')
print (d3)

它將產生以下**輸出**:

2023-04-20
2023-04-20
2023-04-20
2023-04-20

date 類中的例項方法

  • replace() − 透過關鍵字引數指定的新值替換指定的屬性,返回一個新的日期。

  • timetuple() − 返回 time.struct_time,類似於 time.localtime() 返回的結構。

  • toordinal() − 返回日期的儒略日,其中公元 1 年 1 月 1 日的儒略日為 1。對於任何日期物件 d,date.fromordinal(d.toordinal()) == d。

  • weekday() − 返回星期幾的整數程式碼,其中星期一為 0,星期日為 6。

  • isoweekday() − 返回星期幾的整數程式碼,其中星期一為 1,星期日為 7。

  • isocalendar() − 返回一個包含三個元件的命名元組物件:年、周和星期幾。

  • isoformat() − 返回一個以 ISO 8601 格式(YYYY-MM-DD)表示日期的字串。

  • __str__() − 對於日期 d,str(d) 等效於 d.isoformat()

  • ctime() − 返回表示日期的字串

  • strftime(format) − 返回表示日期的字串,由顯式格式字串控制。

  • __format__(format) − 與 date.strftime() 相同。

示例

from datetime import date
d = date.fromordinal(738630) # 738630th day after 1. 1. 0001
print (d)
print (d.timetuple())
# Methods related to formatting string output
print (d.isoformat())
print (d.strftime("%d/%m/%y"))
print (d.strftime("%A %d. %B %Y"))
print (d.ctime())

print ('The {1} is {0:%d}, the {2} is {0:%B}.'.format(d, "day", "month"))

# Methods for to extracting 'components' under different calendars
t = d.timetuple()
for i in t:
   print(i)
   
ic = d.isocalendar()
for i in ic:
   print(i)
   
# A date object is immutable; all operations produce a new object
print (d.replace(month=5))

它將產生以下**輸出**:

2023-04-20
time.struct_time(tm_year=2023, tm_mon=4, tm_mday=20, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=3, tm_yday=110, tm_isdst=-1)
2023-04-20
20/04/23
Thursday 20. April 2023
Thu Apr 20 00:00:00 2023
The day is 20, the month is April.
2023
4
20
0
0
0
3
110
-1
2023
16
4
2023-05-20

time

time 類物件表示一天中的本地時間。它獨立於任何特定日期。如果物件包含 tzinfo 詳細資訊,則它是已知時區的物件。如果為 None,則 time 物件是未知時區的物件。

語法

datetime.time(hour=0, minute=0, second=0, microsecond=0, tzinfo=None)

所有引數都是可選的。tzinfo 可以是 None,也可以是 tzinfo 子類的例項。其餘引數必須是以下範圍內的整數:

  • hour − 0 <= hour < 24,

  • minute − 0 <= minute < 60,

  • second − 0 <= second < 60,

  • microsecond − 0 <= microsecond < 1000000

如果任何引數的值超出這些範圍,則會引發 ValueError。

示例

from datetime import time

time1 = time(8, 14, 36)
print("Time:", time1)

time2 = time(minute = 12)
print("time", time2)

time3 = time()
print("time", time3)

time4 = time(hour = 26)

它將產生以下**輸出**:

Time: 08:14:36
time 00:12:00
time 00:00:00
Traceback (most recent call last):
  File "/home/cg/root/64b912f27faef/main.py", line 12, in 
    time4 = time(hour = 26)
ValueError: hour must be in 0..23

類屬性

  • time.min − 可表示的最早時間,time(0, 0, 0, 0)。

  • time.max − 可表示的最新時間,time(23, 59, 59, 999999)。

  • time.resolution − 不同 time 物件之間可能的最小差值。

示例

from datetime import time
print(time.min)
print(time.max)
print (time.resolution)

它將產生以下**輸出**:

00:00:00
23:59:59.999999
0:00:00.000001

例項屬性

  • time.hour − 在 range(24) 內

  • time.minute − 在 range(60) 內

  • time.second − 在 range(60) 內

  • time.microsecond − 在 range(1000000) 內

  • time.tzinfo − time 建構函式的 tzinfo 引數,或 None。

示例

from datetime import time
t = time(8,23,45,5000)
print(t.hour)
print(t.minute)
print (t.second)
print (t.microsecond)

它將產生以下**輸出**:

8
23
455000

例項方法

  • replace() − 返回具有相同值的時間,但指定關鍵字引數給出的屬性除外。

  • isoformat() − 返回一個以 ISO 8601 格式表示時間的字串。

  • __str__() − 對於時間 t,str(t) 等效於 t.isoformat()。

  • strftime(format) − 返回一個表示時間的字串,由顯式格式字串控制。

  • __format__(format) − 與 time.strftime() 相同。

  • utcoffset() − 如果 tzinfo 為 None,則返回 None,否則返回 self.tzinfo.utcoffset(None)。

  • dst() − 如果 tzinfo 為 None,則返回 None,否則返回 self.tzinfo.dst(None)。

  • tzname() − 如果 tzinfo 為 None,則返回 None,否則返回 self.tzinfo.tzname(None),或引發異常。

datetime

datetime 類物件同時包含日期和時間資訊。它假設當前的格里高利曆在兩個方向上無限期地擴充套件;就像 time 物件一樣,每一天都有 3600*24 秒。

語法

datetime.datetime(year, month, day, hour=0, minute=0, second=0, microsecond=0, tzinfo=None, *, fold=0)

year、month 和 day 引數是必需的。

  • year − MINYEAR <= year <= MAXYEAR,

  • month − 1 <= month <= 12,

  • day − 1 <= day <= 給定月份和年份的天數,

  • hour − 0 <= hour < 24,

  • minute − 0 <= minute < 60,

  • second −0 <= second < 60,

  • microsecond − 0 <= microsecond < 1000000,

  • fold − 在 [0, 1] 中。

如果任何引數的值超出範圍,則會引發 ValueError。

示例

from datetime import datetime
dt = datetime(2023, 4, 20)
print(dt)

dt = datetime(2023, 4, 20, 11, 6, 32, 5000)
print(dt)

它將產生以下**輸出**:

2023-04-20 00:00:00
2023-04-20 11:06:32.005000

類屬性

  • datetime.min − 可表示的最早 datetime,datetime(MINYEAR, 1, 1, tzinfo=None)。

  • datetime.max − 可表示的最新 datetime,datetime(MAXYEAR, 12, 31, 23, 59, 59, 999999, tzinfo=None)。

  • datetime.resolution − 不同 datetime 物件之間可能的最小差值,timedelta(microseconds=1)。

示例

from datetime import datetime
min = datetime.min
print("Min DateTime ", min)

max = datetime.max
print("Max DateTime ", max)

它將產生以下**輸出**:

Min DateTime 0001-01-01 00:00:00
Max DateTime 9999-12-31 23:59:59.999999

例項屬性

  • datetime.year − 包含在 MINYEAR 和 MAXYEAR 之間。

  • datetime.month − 包含在 1 和 12 之間。

  • datetime.day − 包含在 1 和給定年份給定月份的天數之間。

  • datetime.hour − 在 range(24) 內

  • datetime.minute − 在 range(60) 內

  • datetime.second − 在 range(60) 內

  • datetime.microsecond − 在 range(1000000) 內。

  • datetime.tzinfo − 傳遞給 datetime 建構函式的 tzinfo 物件,如果沒有傳遞則為 None。

  • datetime.fold − 在 [0, 1] 中。用於在重複的時間間隔內消除歧義。

示例

from datetime import datetime
dt = datetime.now()

print("Day: ", dt.day)
print("Month: ", dt.month)
print("Year: ", dt.year)
print("Hour: ", dt.hour)
print("Minute: ", dt.minute)
print("Second: ", dt.second)

它將產生以下**輸出**:

Day: 20
Month: 4
Year: 2023
Hour: 15
Minute: 5
Second: 52

類方法

  • today() − 返回當前本地 datetime,tzinfo 為 None。

  • now(tz=None) − 返回當前本地日期和時間。

  • utcnow() − 返回當前 UTC 日期和時間,tzinfo 為 None。

  • utcfromtimestamp(timestamp) − 返回與 POSIX 時間戳對應的 UTC datetime,tzinfo 為 None。

  • fromtimestamp(timestamp, timezone.utc) − 在符合 POSIX 標準的平臺上,它等效於 datetime(1970, 1, 1, tzinfo=timezone.utc) + timedelta(seconds=timestamp)

  • fromordinal(ordinal) − 返回與儒略日對應的 datetime,其中公元 1 年 1 月 1 日的儒略日為 1。

  • fromisoformat(date_string) − 返回與任何有效的 ISO 8601 格式的 date_string 對應的 datetime。

例項方法

  • date() − 返回具有相同年、月和日的 date 物件。

  • time() − 返回具有相同小時、分鐘、秒、微秒和 fold 的 time 物件。

  • timetz() − 返回具有相同小時、分鐘、秒、微秒、fold 和 tzinfo 屬性的 time 物件。另請參見方法 time()。

  • replace() − 返回具有相同屬性的 datetime,但指定關鍵字引數給出的屬性除外。

  • astimezone(tz=None) − 返回一個具有新的 tzinfo 屬性 tz 的 datetime 物件。

  • utcoffset() − 如果 tzinfo 為 None,則返回 None,否則返回 self.tzinfo.utcoffset(self)。

  • dst() − 如果 tzinfo 為 None,則返回 None,否則返回 self.tzinfo.dst(self)。

  • tzname() − 如果 tzinfo 為 None,則返回 None,否則返回 self.tzinfo.tzname(self)。

  • timetuple() − 返回 time.struct_time,類似於 time.localtime() 返回的結構。

  • datetime.toordinal() − 返回日期的儒略日。

  • timestamp() − 返回與 datetime 例項對應的 POSIX 時間戳。

  • isoweekday() − 返回星期幾的整數程式碼,其中星期一為 1,星期日為 7。

  • isocalendar() − 返回一個包含三個元件的命名元組:年、周和星期幾。

  • isoformat(sep='T', timespec='auto') − 返回一個以 ISO 8601 格式表示日期和時間的字串。

  • __str__() − 對於 datetime 例項 d,str(d) 等效於 d.isoformat(' ')。

  • ctime() − 返回一個表示日期和時間的字串。

  • strftime(format) − 返回一個表示日期和時間的字串,由顯式格式字串控制。

  • __format__(format) − 與 strftime() 相同。

示例

from datetime import datetime, date, time, timezone

# Using datetime.combine()
d = date(2022, 4, 20)
t = time(12, 30)
datetime.combine(d, t)

# Using datetime.now()
d = datetime.now()
print (d)

# Using datetime.strptime()
dt = datetime.strptime("23/04/20 16:30", "%d/%m/%y %H:%M")

# Using datetime.timetuple() to get tuple of all attributes
tt = dt.timetuple()
for it in tt:
   print(it)

# Date in ISO format
ic = dt.isocalendar()
for it in ic:
   print(it)

它將產生以下**輸出**:

2023-04-20 15:12:49.816343
2020
4
23
16
30
0
3
114
-1
2020
17
4

timedelta

timedelta 物件表示兩個日期或兩個時間物件之間的時間差。

語法

datetime.timedelta(days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours=0, weeks=0)

在內部,屬性以天、秒和微秒儲存。其他引數將轉換為這些單位:

  • 毫秒轉換為 1000 微秒。

  • 分鐘轉換為 60 秒。

  • 小時轉換為 3600 秒。

  • 星期轉換為 7 天。

然後對天、秒和微秒進行標準化,使其表示唯一。

示例

以下示例顯示 Python 內部只儲存天、秒和微秒。

from datetime import timedelta
delta = timedelta(
   days=100,
   seconds=27,
   microseconds=10,
   milliseconds=29000,
   minutes=5,
   hours=12,
   weeks=2
)
# Only days, seconds, and microseconds remain
print (delta)

它將產生以下**輸出**:

114 days, 12:05:56.000010

示例

以下示例演示如何將 timedelta 物件新增到 datetime 物件。

from datetime import datetime, timedelta

date1 = datetime.now()

date2= date1+timedelta(days = 4)
print("Date after 4 days:", date2)

date3 = date1-timedelta(15)
print("Date before 15 days:", date3)

它將產生以下**輸出**:

Date after 4 days: 2023-04-24 18:05:39.509905
Date before 15 days: 2023-04-05 18:05:39.509905

類屬性

  • timedelta.min − 最小的 timedelta 物件,timedelta(-999999999)。

  • timedelta.max − 最大的 timedelta 物件,timedelta(days=999999999, hours=23, minutes=59, seconds=59, microseconds=999999)。

  • timedelta.resolution − 不相等 timedelta 物件之間可能的最小差值,timedelta(microseconds=1)

示例

from datetime import timedelta

# Getting minimum value
min = timedelta.min
print("Minimum value:", min)

max = timedelta.max
print("Maximum value", max)

它將產生以下**輸出**:

Minimum value: -999999999 days, 0:00:00
Maximum value 999999999 days, 23:59:59.999999

例項屬性

由於內部只儲存天、秒和微秒,因此這些是timedelta物件的唯一例項屬性。

  • days − 包含 -999999999 到 999999999

  • seconds − 包含 0 到 86399

  • microseconds − 包含 0 到 999999

例項方法

timedelta.total_seconds() − 返回持續時間內包含的總秒數。

示例

from datetime import timedelta
year = timedelta(days=365)
years = 5 * year
print (years)
print (years.days // 365)
646
year_1 = years // 5
print(year_1.days)

它將產生以下**輸出**:

1825 days, 0:00:00
5
365

Python - 數學

Python 的標準庫提供 math 模組。此模組包含許多預定義函式,用於執行不同的數學運算。這些函式不適用於複數。cmath 模組包含複數的數學函式。

math 模組中的函式

以下是 math 模組中可用函式的列表:

序號 方法和說明
1

acos (x)

返回 x 的反餘弦值(以弧度表示)。

2

acosh (x)

返回 x 的反雙曲餘弦值。

3

asin

返回 x 的反正弦值(以弧度表示)。

4

asinh (x)

返回 x 的反雙曲正弦值。

5

atan

返回 x 的反正切值(以弧度表示)。

6

atan2

返回 atan(y/x)(以弧度表示)。

7

atanh (x)

返回 x 的反雙曲正切值。

8

cbrt (x)

返回 x 的立方根。

9

ceil(x)

x 的上界:不小於 x 的最小整數。

10

comb (x,y)

返回從 y 個專案中選擇 x 個專案的方法數(可重複選擇,無序)。

11

copysign(x,y)

返回一個浮點數,其大小與 x 相同,但符號與 y 相同。

12

cos (x)

返回 x 弧度的餘弦值。

13

cosh (x)

返回 x 的雙曲餘弦值。

14

degrees

將角度 x 從弧度轉換為度。

15

dist (x,y)

返回兩點 x 和 y 之間的歐幾里得距離。

16

e

數學常數 e = 2.718281...,精確到可用精度。

17

erf (x)

返回 x 處的誤差函式。

18

erfc (x)

返回 x 處的互補誤差函式。

19

exp (x)

返回 e 的 x 次冪,其中 e = 2.718281...

20

exp2 (x)

返回 2 的 x 次冪。

21

expm1 (x)

返回 e 的 x 次冪減 1。

22

fabs(x)

x 的絕對值(浮點數)。

23

factorial(x)

返回 x 的階乘(整數)。

24

floor (x)

x 的下界:不大於 x 的最大整數。

25

fmod (x,y)

始終返回浮點數,類似於 x%y

26

frexp (x)

返回給定數字 x 的尾數和指數。

27

fsum (iterable)

任何可迭代物件中所有數字的和,返回浮點數。

28

gamma (x)

返回 x 處的伽馬函式。

29

gcd (x,y,z)

返回指定整數引數的最大公約數。

30

hypot

返回歐幾里得範數,sqrt(x*x + y*y)。

31

inf

浮點正無窮大。等效於 float('inf') 的輸出。

32

isclose (x,y)

如果值 x 和 y 彼此接近,則返回 True,否則返回 False。

33

isfinite (x)

如果既不是無窮大也不是 NaN,則返回 True,否則返回 False。

34

isinf (x)

如果 x 是正無窮大或負無窮大,則返回 True,否則返回 False。

35

isnan (x)

如果 x 是 NaN(非數字),則返回 True,否則返回 False。

36

isqrt (x)

返回非負整數 x 的整數平方根。

37

lcm (x1, x2, ..)

返回指定整數引數的最小公倍數。

38

ldexp (x,y)

返回 x * (2**y)。這是函式 frexp() 的逆函式。

39

lgamma (x)

返回 x 處的伽馬函式絕對值的自然對數。

40

log (x)

返回 x 的自然對數(以 e 為底)。

41

log10 (x)

返回 x 的以 10 為底的對數。

42

log1p (x)

返回 1+x 的自然對數(以 e 為底)。

43

log2 (x)

返回 x 的以 2 為底的對數。

44

modf (x)

x 的小數部分和整數部分組成的兩個元素的元組。兩部分都與 x 符號相同。整數部分作為浮點數返回。

45

nan

浮點“非數字”(NaN)值。

46

nextafter (x,y)

返回 x 之後朝向 y 的下一個浮點值。

47

perm (x,y)

返回從 y 個專案中選擇 x 個專案的方法數(不可重複選擇,有序)。

48

pi

數學常數 π = 3.141592...,精確到可用精度。

49

pow (x,y)

返回 x 的 y 次冪。

50

prod (iterable)

返回輸入可迭代物件中所有元素的乘積。

51

radians

將角度 x 從度轉換為弧度。

52

remainder (x,y)

返回 x 對 y 的餘數。

53

sin (x)

返回 x 弧度的正弦值。

54

sinh (x)

返回 x 的反雙曲正弦值。

55

sqrt (x)

返回 x 的平方根。

56

tan (x)

返回 x 弧度的正切值。

57

tanh (x)

返回 x 的雙曲正切值。

58

tau

數學常數 τ = 6.283185...,精確到可用精度。

59

trunc (x)

返回去除小數部分後的 x,保留整數部分。

60

ulp

返回浮點數 x 的最低有效位的數值。

這些函式可以分為以下幾類:

Python - 迭代器

Python 中的迭代器是一個表示資料流的物件。它遵循迭代器協議,該協議要求它支援 __iter__() 和 __next__() 方法。Python 的內建方法 iter() 實現 __iter__() 方法。它接收一個可迭代物件並返回迭代器物件。內建的 next() 函式在內部呼叫迭代器的 __next__() 方法,返回流中的連續專案。當沒有更多資料可用時,將引發 StopIteration 異常。

Python 在處理集合資料型別(如列表、元組或字串)時隱式地使用迭代器。這就是為什麼這些資料型別被稱為可迭代物件的原因。我們通常使用 for 迴圈迭代可迭代物件,如下所示:

for element in sequence:
 print (element)

Python 的內建方法 iter() 實現 __iter__() 方法。它接收一個可迭代物件並返回迭代器物件。

示例

以下程式碼從序列型別列表、字串和元組中獲取迭代器物件。iter() 函式還從字典中返回鍵迭代器。但是,int 不是可迭代的,因此它會產生 TypeError。

print (iter("aa"))
print (iter([1,2,3]))
print (iter((1,2,3)))
print (iter({}))
print (iter(100))

它將產生以下**輸出**:

<str_ascii_iterator object at 0x000001BB03FFAB60>
<list_iterator object at 0x000001BB03FFAB60>
<tuple_iterator object at 0x000001BB03FFAB60>
<dict_keyiterator object at 0x000001BB04181670>
Traceback (most recent call last):
   File "C:\Users\user\example.py", line 5, in <module>
      print (iter(100))
            ^^^^^^^^^
TypeError: 'int' object is not iterable

迭代器物件具有 __next__() 方法。每次呼叫它時,它都會返回迭代器流中的下一個元素。當流耗盡時,會引發 StopIteration 錯誤。對 next() 函式的呼叫等同於呼叫迭代器物件的 __next__() 方法。

示例

it = iter([1,2,3])
print (next(it))
print (it.__next__())
print (it.__next__())
print (next(it))

它將產生以下**輸出**:

1
2
3
Traceback (most recent call last):
   File "C:\Users\user\example.py", line 5, in <module>
      print (next(it))
            ^^^^^^^^
StopIteration

示例

您可以使用異常處理機制來捕獲 StopIteration。

it = iter([1,2,3, 4, 5])
print (next(it))
while True:
   try:
      no = next(it)
      print (no)
   except StopIteration:
      break

它將產生以下**輸出**:

1
2
3
4
5

要在 Python 中定義自定義迭代器類,該類必須定義 __iter__() 和 __next__() 方法。

在下面的示例中,Oddnumbers 是一個實現 __iter__() 和 __next__() 方法的類。每次呼叫 __next__() 時,數字都會遞增 2,從而在 1 到 10 的範圍內流式傳輸奇數。

示例

class Oddnumbers:

   def __init__(self, end_range):
      self.start = -1
      self.end = end_range

   def __iter__(self):
      return self

   def __next__(self):
      if self.start < self.end-1:
         self.start += 2
         return self.start
      else:
         raise StopIteration

countiter = Oddnumbers(10)
while True:
   try:
      no = next(countiter)
      print (no)
   except StopIteration:
      break

它將產生以下**輸出**:

1
3
5
7
9

非同步迭代器

從 Python 3.10 版本開始,添加了兩個內建函式 aiter() 和 anext()。aiter() 函式返回一個非同步迭代器物件。它是經典迭代器的非同步對應部分。任何非同步迭代器都必須支援 __aiter__() 和 __anext__() 方法。這兩個方法由這兩個內建函式在內部呼叫。

與經典迭代器一樣,非同步迭代器提供一個物件流。當流耗盡時,將引發 StopAsyncIteration 異常。

在下面給出的示例中,聲明瞭一個非同步迭代器類 Oddnumbers。它實現了 __aiter__() 和 __anext__() 方法。每次迭代都會返回下一個奇數,程式會等待一秒鐘,以便它可以非同步執行任何其他程序。

與常規函式不同,非同步函式被稱為協程,並使用 asyncio.run() 方法執行。main() 協程包含一個 while 迴圈,它連續獲取奇數,如果數字超過 9,則引發 StopAsyncIteration。

示例

import asyncio

class Oddnumbers():
   def __init__(self):
      self.start = -1

   def __aiter__(self):
      return self
      
   async def __anext__(self):
      if self.start >= 9:
         raise StopAsyncIteration
      self.start += 2
      await asyncio.sleep(1)
      return self.start
      
async def main():
   it = Oddnumbers()
   while True:
      try:
         awaitable = anext(it)
         result = await awaitable
         print(result)
      except StopAsyncIteration:
         break
         
asyncio.run(main())

它將產生以下**輸出**:

1
3
5
7
9

Python - 生成器

Python 中的生成器是一種特殊的函式,它返回一個迭代器物件。它看起來類似於普通的 Python 函式,因為它的定義也以 def 關鍵字開頭。但是,它在末尾不使用 return 語句,而是使用 yield 關鍵字。

語法

def generator():
 . . .
 . . .
 yield obj
it = generator()
next(it)
. . .

函式末尾的 return 語句表示函式體的執行結束,函式中的所有區域性變數都將超出範圍。如果再次呼叫該函式,則會重新初始化區域性變數。

生成器函式的行為有所不同。它第一次像普通函式一樣被呼叫,但是當它的 yield 語句出現時,它的執行會暫時暫停,並將控制權轉移回去。產生的結果由呼叫者使用。對 next() 內建函式的呼叫會從暫停的地方重新啟動生成器的執行,併為迭代器生成下一個物件。該迴圈會重複,因為後續的 yield 會提供迭代器中的下一個專案,直到它耗盡。

示例1

下面程式碼中的函式是一個生成器,它連續地從 1 到 5 生成整數。當被呼叫時,它返回一個迭代器。每次呼叫 next() 時,控制權都會轉移回生成器並獲取下一個整數。

def generator(num):
   for x in range(1, num+1):
      yield x
   return
   
it = generator(5)
while True:
   try:
      print (next(it))
   except StopIteration:
      break

它將產生以下**輸出**:

1
2
3
4
5

生成器函式返回一個動態迭代器。因此,它比從 Python 序列物件獲得的普通迭代器更節省記憶體。例如,如果要獲取斐波那契數列中的前 n 個數字。您可以編寫一個普通函式並構建一個斐波那契數列表,然後使用迴圈迭代該列表。

示例2

下面是獲取斐波那契數列表的普通函式:

def fibonacci(n):
   fibo = []
   a, b = 0, 1
   while True:
      c=a+b
      if c>=n:
         break
      fibo.append(c)
      a, b = b, c
   return fibo
f = fibonacci(10)
for i in f:
   print (i)

它將產生以下輸出:

1
2
3
5
8

上面的程式碼將所有斐波那契數列數字收集到一個列表中,然後使用迴圈遍歷該列表。想象一下,我們想要一個很大的斐波那契數列。在這種情況下,所有數字都必須收集到一個列表中,這需要大量的記憶體。這就是生成器有用的地方,因為它生成列表中的單個數字並將其提供給使用者。

示例3

以下程式碼是基於生成器的斐波那契數列表解決方案:

def fibonacci(n):
   a, b = 0, 1
   while True:
      c=a+b
      if c>=n:
         break
      yield c
      a, b = b, c
   return
   
f = fibonacci(10)
while True:
   try:
      print (next(f))
   except StopIteration:
      break 

非同步生成器

非同步生成器是一個返回非同步迭代器的協程。協程是用 async 關鍵字定義的 Python 函式,它可以排程和等待其他協程和任務。就像普通的生成器一樣,非同步生成器每次呼叫 anext() 函式(而不是 next() 函式)時都會生成迭代器中的增量專案。

語法

async def generator():
. . .
. . .
yield obj
it = generator()
anext(it)
. . .

示例 4

以下程式碼演示了一個協程生成器,它在async for迴圈的每次迭代中都會生成遞增的整數。

import asyncio

async def async_generator(x):
   for i in range(1, x+1):
      await asyncio.sleep(1)
      yield i
      
async def main():
   async for item in async_generator(5):
      print(item)
      
asyncio.run(main())

它將產生以下**輸出**:

1
2
3
4
5

示例5

現在讓我們為斐波那契數編寫一個非同步生成器。為了模擬協程中的某些非同步任務,程式在生成下一個數字之前呼叫 sleep() 方法持續 1 秒。結果,您將在延遲一秒後在螢幕上看到列印的數字。

import asyncio

async def fibonacci(n):
   a, b = 0, 1
   while True:
      c=a+b
      if c>=n:
         break
      await asyncio.sleep(1)
      yield c
      a, b = b, c
   return
   
async def main():
   f = fibonacci(10)
   async for num in f:
      print (num)
      
asyncio.run(main())

它將產生以下**輸出**:

1
2
3
5
8

Python - 閉包

本章我們來討論Python中的閉包概念。在Python中,函式被稱為一等物件。就像基本資料型別一樣,函式也可以被賦值給變數,或者作為引數傳遞。

巢狀函式

你也可以巢狀宣告函式,即在一個函式的主體內部定義另一個函式。

示例

def functionA():
   print ("Outer function")
   def functionB():
      print ("Inner function")
   functionB()

functionA()

它將產生以下**輸出**:

Outer function
Inner function

在上面的例子中,函式B在函式A內部定義。內部函式然後在外部函式的作用域內被呼叫。

如果外部函式接收任何引數,它可以傳遞給內部函式。

def functionA(name):
   print ("Outer function")
   def functionB():
      print ("Inner function")
      print ("Hi {}".format(name))
   functionB()
   
functionA("Python")

它將產生以下輸出:

Outer function
Inner function
Hi Python

什麼是閉包?

閉包是一個巢狀函式,它可以訪問來自封閉函式的變數,而封閉函式已經完成了它的執行。這樣的變數不會繫結在區域性作用域中。要使用不可變變數(數字或字串),我們必須使用`nonlocal`關鍵字。

Python閉包的主要優點是,它可以幫助我們避免使用全域性變數,並提供某種程度的資料隱藏。它們常用於Python裝飾器。

示例

def functionA(name):
   name ="New name"
   def functionB():
      print (name)
   return functionB
   
myfunction = functionA("My name")
myfunction()

它將產生以下**輸出**:

New name

在上面的例子中,我們有一個函式A,它建立並返回另一個函式functionB。巢狀函式B是閉包。

外部函式A返回一個函式B,並將其賦值給myfunction變數。即使它已經完成了執行,列印閉包仍然可以訪問name變數。

`nonlocal`關鍵字

在Python中,`nonlocal`關鍵字允許訪問區域性作用域之外的變數。這在閉包中用於修改存在於外部變數作用域中的不可變變數。

示例

def functionA():
   counter =0
   def functionB():
      nonlocal counter
      counter+=1
      return counter
   return functionB

myfunction = functionA()

retval = myfunction()
print ("Counter:", retval)

retval = myfunction()
print ("Counter:", retval)

retval = myfunction()
print ("Counter:", retval)

它將產生以下**輸出**:

Counter: 1
Counter: 2
Counter: 3

Python - 裝飾器

Python中的裝飾器是一個函式,它接收另一個函式作為引數。引數函式是被裝飾器裝飾的函式。裝飾器擴充套件了引數函式的行為,而無需實際修改它。

本章我們將學習如何使用Python裝飾器。

Python中的函式是一等物件。這意味著它可以作為引數傳遞給另一個函式,就像其他資料型別(如數字、字串或列表等)一樣。也可以在一個函式內部定義另一個函式。這樣的函式稱為巢狀函式。此外,函式也可以返回其他函式。

語法

裝飾器函式的典型定義如下:

def decorator(arg_function): #arg_function to be decorated
   def nested_function():
      #this wraps the arg_function and extends its behaviour
      #call arg_function
      arg_function()
   return nested_function

這是一個普通的Python函式:

def function():
   print ("hello")

現在你可以透過將它傳遞給裝飾器來裝飾這個函式,以擴充套件它的行為:

function=decorator(function)

如果現在執行這個函式,它將顯示由裝飾器擴充套件的輸出。

示例1

下面的程式碼是一個簡單的裝飾器示例:

def my_function(x):
   print("The number is=",x)

def my_decorator(some_function,num):
   def wrapper(num):
      print("Inside wrapper to check odd/even")
      if num%2 == 0:
         ret= "Even"
      else:
         ret= "Odd!"
      some_function(num)
      return ret
   print ("wrapper function is called")
   return wrapper

no=10
my_function = my_decorator(my_function, no)
print ("It is ",my_function(no))

`my_function()` 只打印接收到的數字。但是,透過將其傳遞給 `my_decorator` 來修改其行為。內部函式接收數字並返回它是奇數還是偶數。上述程式碼的輸出是:

wrapper function is called
Inside wrapper to check odd/even
The number is= 10
It is Even

示例2

裝飾函式的一種優雅方法是在其定義之前,使用 `@` 符號加上裝飾器的名稱。上面的例子使用這種表示法重寫:

def my_decorator(some_function):
   def wrapper(num):
      print("Inside wrapper to check odd/even")
      if num%2 == 0:
         ret= "Even"
      else:
         ret= "Odd!"
      some_function(num)
      return ret
   print ("wrapper function is called")
   return wrapper

@my_decorator
def my_function(x):
   print("The number is=",x)
no=10
print ("It is ",my_function(no))

Python的標準庫定義了以下內建裝飾器:

`@classmethod` 裝飾器

`classmethod` 是一個內建函式。它將方法轉換為類方法。類方法與例項方法不同。在類中定義的例項方法由其物件呼叫。該方法接收一個由 `self` 引用的隱式物件。另一方面,類方法隱式地接收類本身作為第一個引數。

語法

要宣告類方法,使用以下裝飾器表示法:

class Myclass:
   @classmethod
   def mymethod(cls):
   #....

`@classmethod` 的形式如前所述是函式裝飾器。`mymethod` 接收對類的引用。它可以由類及其物件呼叫。這意味著 `Myclass.mymethod` 和 `Myclass().mymethod` 都是有效的呼叫。

示例3

讓我們透過以下示例瞭解類方法的行為:

class counter:
   count=0
   def __init__(self):
      print ("init called by ", self)
      counter.count=counter.count+1
      print ("count=",counter.count)
   @classmethod
   def showcount(cls):
      print ("called by ",cls)
      print ("count=",cls.count)

c1=counter()
c2=counter()
print ("class method called by object")
c1.showcount()
print ("class method called by class")
counter.showcount()

在類定義中,`count` 是一個類屬性。`__init__()` 方法是建構函式,顯然是一個例項方法,因為它接收 `self` 作為物件引用。宣告的每個物件都會呼叫此方法並將 `count` 加 1。

`@classmethod` 裝飾器將 `showcount()` 方法轉換為類方法,即使它是被其物件呼叫,它也接收對類的引用作為引數。即使 `c1` 物件呼叫 `showcount`,它也會顯示 `counter` 類的引用。

它將顯示以下**輸出**:

init called by <__main__.counter object at 0x000001D32DB4F0F0>
count= 1
init called by <__main__.counter object at 0x000001D32DAC8710>
count= 2
class method called by object
called by <class '__main__.counter'>
count= 2
class method called by class
called by <class '__main__.counter'>

`@staticmethod` 裝飾器

`staticmethod` 也是Python標準庫中的內建函式。它將方法轉換為靜態方法。靜態方法無論是由類的例項還是類本身呼叫,都不會接收任何引用引數。在類中宣告靜態方法使用以下表示法:

語法

class Myclass:
@staticmethod
def mymethod():
#....

即使 `Myclass.mymethod` 和 `Myclass().mymethod` 都是有效的呼叫,靜態方法也不會接收任何引用。

示例 4

`counter` 類修改如下:

class counter:
   count=0
   def __init__(self):
      print ("init called by ", self)
      counter.count=counter.count+1
      print ("count=",counter.count)
   @staticmethod
   def showcount():
      print ("count=",counter.count)

c1=counter()
c2=counter()
print ("class method called by object")
c1.showcount()
print ("class method called by class")
counter.showcount()

和以前一樣,在 `__init__()` 方法內部宣告每個物件時,類屬性 `count` 會遞增。但是,由於 `mymethod()` 是一個靜態方法,它既不接收 `self` 引數也不接收 `cls` 引數。因此,類屬性 `count` 的值使用對 `counter` 的顯式引用顯示。

上述程式碼的**輸出**如下:

init called by <__main__.counter object at 0x000002512EDCF0B8>
count= 1
init called by <__main__.counter object at 0x000002512ED48668>
count= 2
class method called by object
count= 2
class method called by class
count= 2

`@property` 裝飾器

Python 的 `property()` 內建函式是訪問類例項變數的介面。`@property` 裝飾器將例項方法轉換為與同名只讀屬性的“getter”,並將屬性的文件字串設定為“獲取例項變數的當前值”。

您可以使用以下三個裝飾器來定義屬性:

  • **`@property`** - 將方法宣告為屬性。

  • **`@.setter`** - 指定用於設定屬性值的屬性的 setter 方法。

  • **`@.deleter`** - 指定作為刪除屬性的屬性的刪除方法。

`property()` 函式返回的屬性物件具有 getter、setter 和刪除方法。

property(fget=None, fset=None, fdel=None, doc=None)

`fget` 引數是 getter 方法,`fset` 是 setter 方法。它可以選擇具有 `fdel` 作為刪除物件的方法,而 `doc` 是文件字串。

屬性物件的 setter 和 getter 也可以使用以下語法賦值。

speed = property()
speed=speed.getter(speed, get_speed)
speed=speed.setter(speed, set_speed)

其中 `get_speed()` 和 `set_speeds()` 是用於檢索和設定 `Car` 類中例項變數 `speed` 值的例項方法。

上述語句可以使用 `@property` 裝飾器實現。使用該裝飾器,`car` 類被重寫為:

class car:
   def __init__(self, speed=40):
      self._speed=speed
      return
   @property
   def speed(self):
      return self._speed
   @speed.setter
   def speed(self, speed):
      if speed<0 or speed>100:
         print ("speed limit 0 to 100")
         return
      self._speed=speed
      return

c1=car()
print (c1.speed) #calls getter
c1.speed=60 #calls setter

屬性裝飾器是一種非常方便且推薦的處理例項屬性的方法。

Python - 遞迴

一個呼叫自身的函式稱為遞迴函式。當某個問題用自身來定義時,使用此方法。雖然這涉及迭代,但使用迭代方法來解決此問題可能會很繁瑣。遞迴方法為看似複雜的問題提供了一個非常簡潔的解決方案。

遞迴最流行的例子是階乘的計算。數學上階乘定義為:

n! = n × (n-1)!

可以看出,我們使用階乘本身來定義階乘。因此,這是一個編寫遞迴函式的合適案例。讓我們展開上述定義來計算 5 的階乘值。

5! = 5 × 4!
   5 × 4 × 3!
   5 × 4 × 3 × 2!
   5 × 4 × 3 × 2 × 1!
   5 × 4 × 3 × 2 × 1
= 120

雖然我們可以使用迴圈執行此計算,但它的遞迴函式透過遞減數字直到達到 1 來連續呼叫它。

示例1

以下示例顯示瞭如何使用遞迴函式來計算階乘:

def factorial(n):

   if n == 1:
      print (n)
      return 1
   else:
      print (n,'*', end=' ')
      return n * factorial(n-1)
      
print ('factorial of 5=', factorial(5))

它將產生以下**輸出**:

5 * 4 * 3 * 2 * 1
factorial of 5= 120

讓我們再看一個例子來了解遞迴是如何工作的。手頭的問題是檢查給定數字是否在一個列表中。

雖然我們可以使用 for 迴圈並比較每個數字來對列表中的某個數字進行順序搜尋,但順序搜尋效率不高,尤其是在列表太大時。二分查詢演算法檢查索引“high”是否大於索引“low”。根據“mid”變數中存在的值,再次呼叫函式以搜尋元素。

我們有一個按升序排列的數字列表。然後我們找到列表的中點,並根據所需數字是否小於或大於中點的數字,將檢查限制在中點的左側或右側。

下圖顯示了二分查詢的工作原理:

Python Recursion

示例2

以下程式碼實現了遞迴二分查詢技術:

def bsearch(my_list, low, high, elem):
   if high >= low:
      mid = (high + low) // 2
      if my_list[mid] == elem:
         return mid
      elif my_list[mid] > elem:
         return bsearch(my_list, low, mid - 1, elem)
      else:
         return bsearch(my_list, mid + 1, high, elem)
   else:
      return -1

my_list = [5,12,23, 45, 49, 67, 71, 77, 82]
num = 67
print("The list is")
print(my_list)
print ("Check for number:", num)
my_result = bsearch(my_list,0,len(my_list)-1,num)

if my_result != -1:
   print("Element found at index ", str(my_result))
else:
   print("Element not found!")

它將產生以下**輸出**:

The list is
[5, 12, 23, 45, 49, 67, 71, 77, 82]
Check for number: 67
Element found at index 5

您可以檢查列表中不同數字的輸出,以及列表中不存在的數字。

Python - 正則表示式

正則表示式是一系列特殊的字元,它可以幫助您使用包含在模式中的特殊語法來匹配或查詢其他字串或字串集。正則表示式也稱為regex,是一系列字元,用於定義文字中的搜尋模式。通常稱為regex或regexp;它是一系列字元,用於指定文字中的匹配模式。通常,此類模式由字串搜尋演算法用於字串的“查詢”或“查詢和替換”操作,或用於輸入驗證。

資料科學專案中的大規模文字處理需要對文字資料進行操作。許多程式語言(包括Python)都支援正則表示式處理。Python的標準庫為此目的提供了`re`模組。

由於`re`模組中定義的大多數函式都使用原始字串,讓我們首先了解什麼是原始字串。

原始字串

正則表示式使用反斜槓字元('\')來指示特殊形式或允許使用特殊字元而不呼叫它們的特殊含義。另一方面,Python使用相同的字元作為跳脫字元。因此,Python使用原始字串表示法。

如果字串在引號符號之前以r或R為字首,則它成為原始字串。因此,'Hello'是一個普通字串,而r'Hello'是一個原始字串。

>>> normal="Hello"
>>> print (normal)
Hello
>>> raw=r"Hello"
>>> print (raw)
Hello

在正常情況下,兩者之間沒有區別。但是,當跳脫字元嵌入到字串中時,普通字串實際上會解釋轉義序列,而原始字串不會處理跳脫字元。

>>> normal="Hello\nWorld"
>>> print (normal)
Hello
World
>>> raw=r"Hello\nWorld"
>>> print (raw)
Hello\nWorld

在上面的例子中,當列印普通字串時,跳脫字元'\n'被處理以引入換行符。但是,由於原始字串運算子'r',跳脫字元的效果不會根據其含義進行轉換。

元字元

大多數字母和字元都會與自身匹配。但是,某些字元是特殊的元字元,不與自身匹配。元字元是具有特殊含義的字元,類似於萬用字元中的 *。

以下是元字元的完整列表:

. ^ $ * + ? { } [ ] \ | ( )

方括號符號 [ 和 ] 表示您希望匹配的一組字元。字元可以單獨列出,也可以作為字元範圍列出,用“-”分隔。

序號 元字元 & 描述
1

[abc]

匹配字元 a、b 或 c 中的任何一個
2

[a-c]

使用範圍表示相同的字元集。
3

[a-z]

僅匹配小寫字母。
4

[0-9]

僅匹配數字。
5

'^'

對 [] 中的字元集取反。[^5] 將匹配除 '5' 之外的任何字元。

'\' 是轉義元字元。當後面跟著各種字元時,它會形成各種特殊的序列。如果您需要匹配 [ 或 \,可以在它們前面加上反斜槓以消除它們的特殊含義:\[ 或 \\。

下面列出了以 '\' 開頭的此類特殊序列表示的預定義字元集:

序號 元字元 & 描述
1

\d

匹配任何十進位制數字;這等效於類 [0-9]。
2

\D

匹配任何非數字字元;這等效於類 [^0-9]。
3 \s匹配任何空白字元;這等效於類 [\t\n\r\f\v]。
4

\S

匹配任何非空白字元;這等效於類 [^\t\n\r\f\v]。
5

\w

匹配任何字母數字字元;這等效於類 [a-zA-Z0-9_]。
6

\W

匹配任何非字母數字字元。等效於類 [^a-zA-Z0-9_]。
7

.

匹配除換行符 '\n' 之外的任何單個字元。
8

?

匹配其左側模式的 0 次或 1 次出現
9

+

匹配其左側模式的 1 次或多次出現
10

*

匹配其左側模式的 0 次或多次出現
11

\b

單詞和非單詞之間的邊界,/B 與 /b 相反
12

[..]

匹配方括號中的任何單個字元,[^..] 匹配方括號中不存在的任何單個字元。
13

\

它用於特殊含義的字元,例如 \. 用於匹配句點或 \+ 用於匹配加號。
14

{n,m}

匹配前面至少 n 次最多 m 次出現
15

a|b

匹配 a 或 b

Python 的 re 模組提供了用於查詢匹配項、搜尋模式以及用其他字串替換匹配字串等的有用函式。

re.match() 函式

此函式嘗試使用可選的 flagsstring 的開頭匹配 RE pattern

以下是此函式的語法

re.match(pattern, string, flags=0)

以下是引數的描述:

序號 引數 & 描述
1

pattern

這是要匹配的正則表示式。

2

String

這是字串,將在其中搜索在字串開頭匹配模式。

3

Flags

您可以使用按位 OR (|) 指定不同的標誌。這些是修飾符,在下表中列出。

re.match 函式在成功時返回一個匹配物件,失敗時返回None。匹配物件例項包含有關匹配的資訊:它從哪裡開始和結束,它匹配的子字串等。

匹配物件的 start() 方法返回模式在字串中的起始位置,end() 返回結束位置。

如果找不到模式,則匹配物件為 None。

我們使用匹配物件的 group(num)groups() 函式來獲取匹配的表示式。

序號 匹配物件方法 & 描述
1 group(num=0)此方法返回整個匹配項(或特定的子組 num)
2 groups()此方法在一個元組中返回所有匹配的子組(如果沒有,則為空)

示例

import re
line = "Cats are smarter than dogs"
matchObj = re.match( r'Cats', line)
print (matchObj.start(), matchObj.end())
print ("matchObj.group() : ", matchObj.group())

它將產生以下**輸出**:

0 4
matchObj.group() : Cats

re.search() 函式

此函式使用可選的 flags 搜尋 string 中 RE pattern 的第一次出現。

以下是此函式的語法

re.search(pattern, string, flags=0)

以下是引數的描述:

序號 引數 & 描述
1

Pattern

這是要匹配的正則表示式。

2

String

這是字串,將在其中搜索在字串任何位置匹配模式。

3

Flags

您可以使用按位 OR (|) 指定不同的標誌。這些是修飾符,在下表中列出。

re.search 函式在成功時返回一個匹配物件,失敗時返回none。我們使用匹配物件的 group(num)groups() 函式來獲取匹配的表示式。

序號 匹配物件方法 & 描述
1 group(num=0)此方法返回整個匹配項(或特定的子組 num)
2 groups()此方法在一個元組中返回所有匹配的子組(如果沒有,則為空)

示例

import re
line = "Cats are smarter than dogs"
matchObj = re.search( r'than', line)
print (matchObj.start(), matchObj.end())
print ("matchObj.group() : ", matchObj.group())

它將產生以下**輸出**:

17 21
matchObj.group() : than

匹配與搜尋

Python 提供了兩種基於正則表示式的不同基本操作:match 只檢查字串開頭的匹配項,而 search 檢查字串中任何位置的匹配項(這是 Perl 預設執行的操作)。

示例

import re
line = "Cats are smarter than dogs";
matchObj = re.match( r'dogs', line, re.M|re.I)
if matchObj:
   print ("match --> matchObj.group() : ", matchObj.group())
else:
   print ("No match!!")
searchObj = re.search( r'dogs', line, re.M|re.I)
if searchObj:
   print ("search --> searchObj.group() : ", searchObj.group())
else:
   print ("Nothing found!!")

執行上述程式碼時,它會產生以下輸出

No match!!
search --> matchObj.group() : dogs

re.findall() 函式

findall() 函式返回字串中模式的所有不重疊匹配項,作為一個字串或元組列表。字串從左到右掃描,匹配項按找到的順序返回。結果中包含空匹配項。

語法

re.findall(pattern, string, flags=0)

引數

序號 引數 & 描述
1

Pattern

這是要匹配的正則表示式。

2

String

這是字串,將在其中搜索在字串任何位置匹配模式。

3

Flags

您可以使用按位 OR (|) 指定不同的標誌。這些是修飾符,在下表中列出。

示例

import re
string="Simple is better than complex."
obj=re.findall(r"ple", string)
print (obj)

它將產生以下**輸出**:

['ple', 'ple']

以下程式碼在句子中獲取單詞列表,藉助 findall() 函式。

import re
string="Simple is better than complex."
obj=re.findall(r"\w*", string)
print (obj)

它將產生以下**輸出**:

['Simple', '', 'is', '', 'better', '', 'than', '', 'complex', '', '']

re.sub() 函式

使用正則表示式的最重要的re方法之一是sub

語法

re.sub(pattern, repl, string, max=0)

此方法將 string 中 RE pattern 的所有出現替換為 repl,除非提供了 max,否則替換所有出現。此方法返回修改後的字串。

示例

import re
phone = "2004-959-559 # This is Phone Number"

# Delete Python-style comments
num = re.sub(r'#.*$', "", phone)
print ("Phone Num : ", num)

# Remove anything other than digits
num = re.sub(r'\D', "", phone)
print ("Phone Num : ", num)

它將產生以下**輸出**:

Phone Num : 2004-959-559
Phone Num : 2004959559

示例

以下示例使用 sub() 函式替換所有出現的 is 為 was 單詞:

import re
string="Simple is better than complex. Complex is better than complicated."
obj=re.sub(r'is', r'was',string)
print (obj)

它將產生以下**輸出**:

Simple was better than complex. Complex was better than complicated.

re.compile() 函式

compile() 函式將正則表示式模式編譯成正則表示式物件,可以使用其 match()、search() 及其他方法進行匹配。

語法

re.compile(pattern, flags=0)

Flags

序號 修飾符 & 描述
1

re.I

執行不區分大小寫的匹配。

2

re.L

根據當前區域設定解釋單詞。此解釋會影響字母數字組(\w 和 \W),以及單詞邊界行為(\b 和 \B)。

3

re.

M 使 $ 匹配行尾(不僅僅是字串的結尾),並使 ^ 匹配任何行的開頭(不僅僅是字串的開頭)。

4

re.S

使句點 (.) 匹配任何字元,包括換行符。

5

re.U

根據 Unicode 字元集解釋字母。此標誌會影響 \w、\W、\b、\B 的行為。

6

re.X

允許使用“更簡潔”的正則表示式語法。它忽略空格(集合 [] 內部除外,或者當用反斜槓轉義時),並將未轉義的 # 視為註釋標記。

序列:

prog = re.compile(pattern)
result = prog.match(string)

等效於:

result = re.match(pattern, string)

但是,當在一個程式中多次使用表示式時,使用 re.compile() 並儲存生成的正則表示式物件以供重複使用效率更高。

示例

import re
string="Simple is better than complex. Complex is better than complicated."
pattern=re.compile(r'is')
obj=pattern.match(string)
obj=pattern.search(string)
print (obj.start(), obj.end())

obj=pattern.findall(string)
print (obj)

obj=pattern.sub(r'was', string)
print (obj)

它將產生以下輸出:

7 9
['is', 'is']
Simple was better than complex. Complex was better than complicated.

re.finditer() 函式

此函式返回一個迭代器,在字串中為 RE 模式的所有不重疊匹配項生成匹配物件。

語法

re.finditer(pattern, string, flags=0)

示例

import re
string="Simple is better than complex. Complex is better than
complicated."
pattern=re.compile(r'is')
iterator = pattern.finditer(string)
print (iterator )

for match in iterator:
   print(match.span())

它將產生以下**輸出**:

(7, 9)
(39, 41)

Python 正則表示式的用例

查詢所有副詞

findall() 匹配模式的所有出現,而不僅僅是 search() 的第一個出現。例如,如果作者想要查詢某些文字中的所有副詞,他們可能會如下使用 findall():

import re
text = "He was carefully disguised but captured quickly by police."
obj = re.findall(r"\w+ly\b", text)
print (obj)

它將產生以下**輸出**:

['carefully', 'quickly']

查詢以母音開頭的單詞

import re
text = 'Errors should never pass silently. Unless explicitly silenced.'
obj=re.findall(r'\b[aeiouAEIOU]\w+', text)
print (obj)

它將產生以下**輸出**:

['Errors', 'Unless', 'explicitly']

Python - PIP

Python 的標準庫是一個大型的現成模組和包集合。除了這些包之外,Python 程式設計師通常還需要使用某些第三方庫。第三方 Python 包託管在一個名為 Python 包索引的儲存庫中 (https://pypi.org/)

要從此儲存庫安裝包,您需要一個包管理器工具。PIP 是最流行的包管理器之一。

PIP 實用程式會自動與 Python 的標準發行版一起安裝,尤其是在 3.4 版及更高版本中。它位於 Python 安裝目錄內的 scripts 資料夾中。例如,當在 Windows 計算機上安裝 Python 3.11 時,您可以在 C:\Python311\Scripts 資料夾中找到 pip3.exe。

如果預設情況下未安裝pip,則可以透過以下步驟安裝。

從以下 URL 下載 get-pip.py 指令碼:

https://bootstrap.pypa.io/get-pip.py

要安裝,請從命令提示符執行上述指令碼:

c:\Python311>python get-pip.py

在 scripts 資料夾中,pip 和 pip3 都存在。如果使用 pip 安裝某個包,則將安裝其與 Python 2.x 相容的版本。因此,要安裝與 Python 3 相容的版本,請使用 pip3。

安裝包

要從 PyPI 安裝某個包,請使用 PIP 的 install 命令。以下命令在當前 Python 安裝中安裝 Flask 庫。

pip3 install flask

該包及其任何依賴項都將從 PyPI 儲存庫安裝。上述命令在終端中生成以下日誌:

Collecting flask
   Downloading Flask-2.2.3-py3-none-any.whl (101 kB)
      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
101.8/101.8 kB 3.0 MB/s eta 0:00:00
Collecting Werkzeug>=2.2.2
   Downloading Werkzeug-2.2.3-py3-none-any.whl (233 kB)
      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
233.6/233.6 kB 7.2 MB/s eta 0:00:00
Collecting Jinja2>=3.0
   Downloading Jinja2-3.1.2-py3-none-any.whl (133 kB)
      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
133.1/133.1 kB 8.2 MB/s eta 0:00:00
Collecting itsdangerous>=2.0
   Downloading itsdangerous-2.1.2-py3-none-any.whl (15 kB)
Collecting click>=8.0
   Downloading click-8.1.3-py3-none-any.whl (96 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
96.6/96.6 kB 5.4 MB/s eta 0:00:00
Requirement already satisfied: colorama in
c:\users\mlath\appdata\roaming\python\python311\site-packages (from
click>=8.0->flask) (0.4.6)
Collecting MarkupSafe>=2.0
   Downloading MarkupSafe-2.1.2-cp311-cp311-win_amd64.whl (16 kB)
Installing collected packages: MarkupSafe, itsdangerous, click,
Werkzeug, Jinja2, flask
Successfully installed Jinja2-3.1.2 MarkupSafe-2.1.2 Werkzeug-2.2.3
click-8.1.3 flask-2.2.3 itsdangerous-2.1.2

預設情況下,將安裝所需包的最新可用版本。要指定所需的版本,

pip3 install flask==2.0.0

要測試包安裝是否完成,請開啟 Python 直譯器並嘗試匯入它並檢查版本。如果包未成功安裝,則會收到 ModuleNotFoundError。

>>> import flask
>>> print (flask.__version__)
2.2.3
>>> import dummypackage
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'dummypackage'

PIP 實用程式可與以下工具配合使用:

  • 使用需求規範符的 PyPI(和其他索引)。

  • VCS 專案網址。

  • 本地專案目錄。

  • 本地或遠端源存檔。

使用 requirements.txt

您可以透過在一個名為 requirements.txt 的文字檔案中提及所需包的列表來一次性執行包安裝。

例如,以下 requirements.txt 檔案包含要為 FastAPI 庫安裝的依賴項列表。

anyio==3.6.2
click==8.1.3
colorama==0.4.6
fastapi==0.88.0
gunicorn==20.1.0
h11==0.14.0
idna==3.4
pydantic==1.10.4
sniffio==1.3.0
starlette==0.22.0
typing_extensions==4.4.0
uvicorn==0.20.0

現在在 PIP install 命令中使用 -r 開關。

pip3 install -r requirements.txt

PIP 實用程式與以下命令一起使用:

pip uninstall

此命令用於解除安裝已安裝的一個或多個包。

語法

pip3 uninstall package, [package2, package3, . . ]

這將解除安裝包及其依賴項。

示例

pip3 uninstall flask

在繼續之前,系統會詢問您是否確認刪除。

pip3 uninstall flask
Found existing installation: Flask 2.2.3
Uninstalling Flask-2.2.3:
   Would remove:
   c:\python311\lib\site-packages\flask-2.2.3.dist-info\*
   c:\python311\lib\site-packages\flask\*
   c:\python311\scripts\flask.exe
Proceed (Y/n)?

pip list

此命令列出已安裝的包,包括可編輯的包。包按不區分大小寫的排序順序列出。

語法

pip3 list

pip list 命令可以使用以下開關:

-o, --outdated: 列出過時的包

pip3 list --outdated
Package     Version    Latest     Type
--------    -------    -------    -----
debugpy     1.6.6      1.6.7      wheel
ipython     8.11.0     8.12.0     wheel
pip         22.3.1     23.0.1     wheel
Pygments    2.14.0     2.15.0     wheel
setuptools  65.5.0     67.6.1     wheel

-u, --uptodate: 列出最新的包

pip3 list --uptodate
Package           Version
--------          --------- -------
click             8.1.3
colorama          0.4.6
executing         1.2.0
Flask             2.2.3
jedi              0.18.2
Jinja2            3.1.2
python-dateutil   2.8.2
pyzmq             25.0.2
six               1.16.0
Werkzeug          2.2.3

pip show

此命令顯示有關一個或多個已安裝包的資訊。輸出採用符合 RFC 的郵件頭格式。

語法

pip3 show package

示例

pip3 show flask
Name: Flask
Version: 2.2.3
Summary: A simple framework for building complex web applications.
Home-page: https://palletsprojects.com/p/flask
Author: Armin Ronacher
Author-email: armin.ronacher@active-4.com
License: BSD-3-Clause
Location: C:\Python311\Lib\site-packages
Requires: click, itsdangerous, Jinja2, Werkzeug
Required-by:

pip freeze

此命令以需求格式輸出已安裝的包。所有包都按不區分大小寫的排序順序列出。

語法

pip3 freeze

可以使用以下命令將此命令的輸出重定向到文字檔案:

pip3 freeze > requirements.txt

pip download

此命令從以下位置下載包:

  • 使用需求規範符的 PyPI(和其他索引)。

  • VCS 專案網址。

  • 本地專案目錄。

  • 本地或遠端源存檔。

實際上,`pip download` 執行與 `pip install` 相同的解析和下載操作,但它不會安裝依賴項,而是將下載的發行版收集到指定的目錄中(預設為當前目錄)。稍後可以將此目錄作為 `pip install --find-links` 的值,以方便離線或受限環境下的包安裝。

語法

pip3 download somepackage

`pip search`

此命令搜尋 PyPI 包,其名稱或摘要包含給定的查詢。

語法

pip3 search query

`pip config`

此命令用於管理本地和全域性配置。

子命令

  • list − 列出活動配置(或來自指定的檔案)。

  • edit − 在編輯器中編輯配置檔案。

  • get − 獲取與 command.option 關聯的值。

  • set − 設定 command.option=value。

  • unset − 取消與 command.option 關聯的值。

  • debug − 列出配置檔案及其下定義的值。

配置鍵應使用點分隔的命令和選項名稱,字首為 "global" 的鍵將影響所有命令。

示例

pip config set global.index-url https://example.org/

這將配置所有命令的索引 URL。

pip config set download.timeout 10

這將僅為 "pip download" 命令配置 10 秒的超時。

Python - 資料庫訪問

程式執行期間輸入和生成的資料儲存在 RAM 中。如果需要永久儲存,則需要將其儲存在資料庫表中。有多種關係資料庫管理系統 (RDBMS) 可供使用。

  • GadFly
  • MySQL
  • PostgreSQL
  • Microsoft SQL Server
  • Informix
  • Oracle
  • Sybase
  • SQLite
  • 等等…

本章我們將學習如何使用 Python 訪問資料庫,如何將 Python 物件的資料儲存到 SQLite 資料庫中,以及如何從 SQLite 資料庫中檢索資料並使用 Python 程式進行處理。

關係資料庫使用 SQL(結構化查詢語言)對資料庫表執行 INSERT/DELETE/UPDATE 操作。但是,SQL 的實現因資料庫型別而異。這會引發相容性問題。一個數據庫的 SQL 指令與另一個數據庫不匹配。

為了克服這種不相容性,PEP(Python 增強提案)249 中提出了一種通用介面。此提案稱為 DB-API,要求用於與 Python 互動的資料庫驅動程式必須符合 DB-API。

driver_interfaces

Python 的標準庫包含 sqlite3 模組,這是一個與 DB_API 相容的 SQLite3 資料庫驅動程式,它也是 DB-API 的參考實現。

由於所需的 DB-API 介面是內建的,我們可以輕鬆地將 SQLite 資料庫與 Python 應用程式一起使用。對於其他型別的資料庫,您需要安裝相關的 Python 包。

資料庫 Python 包
Oracle cx_oracle, pyodbc
SQL Server pymssql, pyodbc
PostgreSQL PostgreSQL
MySQL MySQL Connector/Python, pymysql

諸如 sqlite3 之類的 DB-API 模組包含連線和遊標類。連線物件透過提供所需的連線憑據(例如伺服器名稱和埠號,以及使用者名稱和密碼(如果適用))來使用 connect() 方法獲得。連線物件處理資料庫的開啟和關閉,以及提交或回滾事務的事務控制機制。

從連線物件獲得的遊標物件在執行所有 CRUD 操作時充當資料庫的控制代碼。

sqlite3 模組

SQLite 是一種無伺服器、基於檔案的輕量級事務關係資料庫。它不需要任何安裝,也不需要使用者名稱和密碼等憑據即可訪問資料庫。

Python 的 sqlite3 模組包含用於 SQLite 資料庫的 DB-API 實現。它由 Gerhard Häring 編寫的。讓我們學習如何使用 sqlite3 模組透過 Python 訪問資料庫。

讓我們從匯入 sqlite3 並檢查其版本開始。

>>> import sqlite3
>>> sqlite3.sqlite_version
'3.39.4'

連線物件

連線物件由 sqlite3 模組中的 connect() 函式設定。此函式的第一個位置引數是一個字串,表示 SQLite 資料庫檔案的路徑(相對或絕對)。該函式返回一個指向資料庫的連線物件。

>>> conn=sqlite3.connect('testdb.sqlite3')
>>> type(conn)
<class 'sqlite3.Connection'>

連線類中定義了多種方法。其中一種是 cursor() 方法,它返回一個遊標物件,我們將在下一節中瞭解它。事務控制是透過連線物件的 commit() 和 rollback() 方法實現的。連線類具有重要的方法來定義要在 SQL 查詢中使用的自定義函式和聚合。

遊標物件

接下來,我們需要從連線物件獲取遊標物件。在對資料庫執行任何 CRUD 操作時,它是資料庫的控制代碼。連線物件上的 cursor() 方法返回遊標物件。

>>> cur=conn.cursor()
>>> type(cur)
<class 'sqlite3.Cursor'>

現在,我們可以藉助其可用於遊標物件的 execute() 方法執行所有 SQL 查詢操作。此方法需要一個字串引數,該引數必須是有效的 SQL 語句。

建立資料庫表

我們現在將在新建立的 'testdb.sqlite3' 資料庫中新增 Employee 表。在下面的指令碼中,我們呼叫遊標物件的 execute() 方法,並向其提供一個包含 CREATE TABLE 語句的字串。

import sqlite3
conn=sqlite3.connect('testdb.sqlite3')
cur=conn.cursor()
qry='''
CREATE TABLE Employee (
EmpID INTEGER PRIMARY KEY AUTOINCREMENT,
FIRST_NAME TEXT (20),
LAST_NAME TEXT(20),
AGE INTEGER,
SEX TEXT(1),
INCOME FLOAT
);
'''
try:
   cur.execute(qry)
   print ('Table created successfully')
except:
   print ('error in creating table')
conn.close()

執行上述程式時,將在當前工作目錄中建立包含 Employee 表的資料庫。

我們可以透過在 SQLite 控制檯中列出此資料庫中的表來驗證。

sqlite> .open mydb.sqlite
sqlite> .tables
Employee

INSERT 操作

當您想將記錄建立到資料庫表中時,需要 INSERT 操作。

示例

以下示例執行 SQL INSERT 語句,以在 EMPLOYEE 表中建立一個記錄:

import sqlite3
conn=sqlite3.connect('testdb.sqlite3')
cur=conn.cursor()
qry="""INSERT INTO EMPLOYEE(FIRST_NAME,
   LAST_NAME, AGE, SEX, INCOME)
   VALUES ('Mac', 'Mohan', 20, 'M', 2000)"""
try:
   cur.execute(qry)
   conn.commit()
   print ('Record inserted successfully')
except:
   conn.rollback()
print ('error in INSERT operation')
conn.close()

您還可以使用引數替換技術來執行 INSERT 查詢,如下所示:

import sqlite3
conn=sqlite3.connect('testdb.sqlite3')
cur=conn.cursor()
qry="""INSERT INTO EMPLOYEE(FIRST_NAME,
   LAST_NAME, AGE, SEX, INCOME)
   VALUES (?, ?, ?, ?, ?)"""
try:
   cur.execute(qry, ('Makrand', 'Mohan', 21, 'M', 5000))
   conn.commit()
   print ('Record inserted successfully')
except Exception as e:
   conn.rollback()
   print ('error in INSERT operation')
conn.close()

READ 操作

任何資料庫上的 READ 操作都意味著從資料庫中提取一些有用的資訊。

一旦建立了資料庫連線,您就可以對該資料庫進行查詢了。您可以使用 fetchone() 方法提取單個記錄,也可以使用 fetchall() 方法從資料庫表中提取多個值。

  • fetchone() − 它提取查詢結果集的下一行。結果集是在使用遊標物件查詢表時返回的物件。

  • fetchall() − 它提取結果集中的所有行。如果結果集中的某些行已經被提取,那麼它將從結果集中檢索剩餘的行。

  • rowcount − 這是一個只讀屬性,返回受 execute() 方法影響的行數。

示例

在下面的程式碼中,遊標物件執行 SELECT * FROM EMPLOYEE 查詢。結果集使用 fetchall() 方法獲得。我們使用 for 迴圈列印結果集中的所有記錄。

import sqlite3
conn=sqlite3.connect('testdb.sqlite3')
cur=conn.cursor()
qry="SELECT * FROM EMPLOYEE"

try:
   # Execute the SQL command
   cur.execute(qry)
   # Fetch all the rows in a list of lists.
   results = cur.fetchall()
   for row in results:
      fname = row[1]
      lname = row[2]
      age = row[3]
      sex = row[4]
      income = row[5]
      # Now print fetched result
      print ("fname={},lname={},age={},sex={},income={}".format(fname, lname, age, sex, income ))
except Exception as e:
   print (e)
   print ("Error: unable to fecth data")

conn.close()

它將產生以下**輸出**:

fname=Mac,lname=Mohan,age=20,sex=M,income=2000.0
fname=Makrand,lname=Mohan,age=21,sex=M,income=5000.0

UPDATE 操作

任何資料庫上的 UPDATE 操作都意味著更新資料庫中已經存在的記錄。

以下過程更新所有 income=2000 的記錄。在這裡,我們將收入增加 1000。

import sqlite3
conn=sqlite3.connect('testdb.sqlite3')
cur=conn.cursor()
qry="UPDATE EMPLOYEE SET INCOME = INCOME+1000 WHERE INCOME=?"

try:
   # Execute the SQL command
   cur.execute(qry, (1000,))
   # Fetch all the rows in a list of lists.
   conn.commit()
   print ("Records updated")
except Exception as e:
   print ("Error: unable to update data")
conn.close()

DELETE 操作

當您想要從資料庫中刪除某些記錄時,需要 DELETE 操作。以下是刪除 EMPLOYEE 中 INCOME 小於 2000 的所有記錄的過程。

import sqlite3
conn=sqlite3.connect('testdb.sqlite3')
cur=conn.cursor()
qry="DELETE FROM EMPLOYEE WHERE INCOME<?"

try:
   # Execute the SQL command
   cur.execute(qry, (2000,))
   # Fetch all the rows in a list of lists.
   conn.commit()
   print ("Records deleted")
except Exception as e:
   print ("Error: unable to delete data")

conn.close()

執行事務

事務是一種確保資料一致性的機制。事務具有以下四個屬性:

  • 原子性 − 事務要麼完成,要麼什麼也不發生。

  • 一致性 − 事務必須從一致狀態開始,並使系統處於一致狀態。

  • 隔離性 − 事務的中間結果在當前事務之外不可見。

  • 永續性 − 一旦事務提交,其效果將是持久的,即使在系統故障之後也是如此。

Performing Transactions

Python DB API 2.0 提供兩種方法來提交或回滾事務。

示例

您已經知道如何實現事務。這是一個類似的示例:

# Prepare SQL query to DELETE required records
sql = "DELETE FROM EMPLOYEE WHERE AGE > ?"
try:
   # Execute the SQL command
   cursor.execute(sql, (20,))
   # Commit your changes in the database
   db.commit()
except:
   # Rollback in case there is any error
   db.rollback()

COMMIT 操作

Commit 是一種操作,它向資料庫發出訊號以完成更改,並且在此操作之後,無法撤銷任何更改。

這是一個呼叫 commit 方法的簡單示例。

db.commit()

ROLLBACK 操作

如果您對一個或多個更改不滿意,並且想要完全撤銷這些更改,則使用 rollback() 方法。

這是一個呼叫 rollback() 方法的簡單示例。

db.rollback()

PyMySQL 模組

PyMySQL 是一個從 Python 連線到 MySQL 資料庫伺服器的介面。它實現了 Python 資料庫 API v2.0,幷包含一個純 Python MySQL 客戶端庫。PyMySQL 的目標是成為 MySQLdb 的直接替代品。

安裝 PyMySQL

在繼續之前,請確保您的機器上已安裝 PyMySQL。只需在您的 Python 指令碼中鍵入以下內容並執行它:

import PyMySQL

如果它產生以下結果,則表示未安裝 MySQLdb 模組:

Traceback (most recent call last):
   File "test.py", line 3, in <module>
      Import PyMySQL
ImportError: No module named PyMySQL

最新的穩定版本可在 PyPI 上獲得,並可以使用 pip 安裝:

pip install PyMySQL

注意 − 確保您具有安裝上述模組的 root 許可權。

MySQL 資料庫連線

在連線到 MySQL 資料庫之前,請確保以下幾點:

  • 您已建立資料庫 TESTDB。

  • 您已在 TESTDB 中建立表 EMPLOYEE。

  • 此表包含欄位 FIRST_NAME、LAST_NAME、AGE、SEX 和 INCOME。

  • 已設定使用者 ID“testuser”和密碼“test123”以訪問 TESTDB。

  • 您的機器上已正確安裝 Python 模組 PyMySQL。

  • 您已閱讀 MySQL 教程以瞭解 MySQL 基礎知識。

示例

要在前面的示例中使用 MySQL 資料庫而不是 SQLite 資料庫,我們需要更改 connect() 函式,如下所示:

import PyMySQL
# Open database connection
db = PyMySQL.connect("localhost","testuser","test123","TESTDB" )

除了此更改之外,每個資料庫操作都可以順利執行。

處理錯誤

錯誤來源有很多。一些例子包括執行的 SQL 語句中的語法錯誤、連線失敗或為已取消或完成的語句控制代碼呼叫 fetch 方法。

DB API 定義了許多必須存在於每個資料庫模組中的錯誤。下表列出了這些異常。

序號 異常和描述
1

Warning

用於非致命性問題。必須是 StandardError 的子類。

2

Error

錯誤的基類。必須是 StandardError 的子類。

3

InterfaceError

用於資料庫模組中的錯誤,而不是資料庫本身。必須是 Error 的子類。

4

DatabaseError

用於資料庫中的錯誤。必須是 Error 的子類。

5

DataError

DatabaseError 的子類,指的是資料中的錯誤。

6

OperationalError

DatabaseError 的子類,指的是諸如與資料庫的連線丟失之類的錯誤。這些錯誤通常超出 Python 指令碼編寫者的控制範圍。

7

IntegrityError

DatabaseError 的子類,用於會破壞關係完整性的情況,例如唯一性約束或外部索引鍵。

8

InternalError

DatabaseError 的子類,指資料庫模組內部發生的錯誤,例如遊標不再處於活動狀態。

9

ProgrammingError

DatabaseError 的子類,指諸如表名錯誤以及其他可以歸咎於使用者的錯誤。

10

NotSupportedError

DatabaseError 的子類,指嘗試呼叫不受支援的功能。

Python - 弱引用

Python 在實現垃圾收集策略時使用引用計數機制。每當記憶體中的物件被引用時,計數器加 1。另一方面,當引用被移除時,計數器減 1。如果後臺執行的垃圾收集器發現任何計數為 0 的物件,它將被移除,並回收其佔用的記憶體。

弱引用是一種不會阻止物件被垃圾回收的引用。當需要為大型物件實現快取以及需要減少迴圈引用帶來的痛苦時,它非常重要。

為了建立弱引用,Python 提供了一個名為 weakref 的模組。

此模組中的 ref 類管理對物件的弱引用。呼叫時,它會檢索原始物件。

建立弱引用 -

weakref.ref(class())

示例

import weakref
class Myclass:
   def __del__(self):
      print('(Deleting {})'.format(self))
obj = Myclass()
r = weakref.ref(obj)

print('object:', obj)
print('reference:', r)
print('call r():', r())

print('deleting obj')
del obj
print('r():', r())

刪除被引用物件後呼叫引用物件將返回 None。

它將產生以下**輸出**:

object: <__main__.Myclass object at 0x00000209D7173290>
reference: <weakref at 0x00000209D7175940; to 'Myclass' at
0x00000209D7173290>
call r(): <__main__.Myclass object at 0x00000209D7173290>
deleting obj
(Deleting <__main__.Myclass object at 0x00000209D7173290>)
r(): None

回撥函式

ref 類的建構函式有一個可選引數,稱為回撥函式,在被引用物件被刪除時呼叫。

import weakref
class Myclass:
   def __del__(self):
      print('(Deleting {})'.format(self))
def mycallback(rfr):
   """called when referenced object is deleted"""
   print('calling ({})'.format(rfr))
obj = Myclass()
r = weakref.ref(obj, mycallback)

print('object:', obj)
print('reference:', r)
print('call r():', r())

print('deleting obj')
del obj
print('r():', r())

它將產生以下**輸出**:

object: <__main__.Myclass object at 0x000002A0499D3590>
reference: <weakref at 0x000002A0499D59E0; to 'Myclass' at
0x000002A0499D3590>
call r(): <__main__.Myclass object at 0x000002A0499D3590>
deleting obj
(Deleting <__main__.Myclass object at 0x000002A0499D3590>)
calling (<weakref at 0x000002A0499D59E0; dead>)
r(): None

物件終結

weakref 模組提供 finalize 類。當垃圾收集器收集物件時,將呼叫其物件。該物件將一直存在,直到引用物件被呼叫。

import weakref
class Myclass:
   def __del__(self):
      print('(Deleting {})'.format(self))

def finalizer(*args):
   print('Finalizer{!r})'.format(args))

obj = Myclass()
r = weakref.finalize(obj, finalizer, "Call to finalizer")

print('object:', obj)
print('reference:', r)
print('call r():', r())

print('deleting obj')
del obj
print('r():', r())

它將產生以下**輸出**:

object: <__main__.Myclass object at 0x0000021015103590>
reference: <finalize object at 0x21014eabe80; for 'Myclass' at
0x21015103590>
Finalizer('Call to finalizer',))
call r(): None
deleting obj
(Deleting <__main__.Myclass object at 0x0000021015103590>)
r(): None

weakref 模組提供 WeakKeyDictionary 和 WeakValueDictionary 類。它們不會像對映物件中那樣保持物件的存活。它們更適合於建立多個物件的快取。

WeakKeyDictionary

弱引用鍵的對映類。當不再有強引用指向鍵時,字典中的條目將被丟棄。

可以使用現有字典或不帶任何引數建立 WeakKeyDictionary 類的例項。其功能與普通字典相同,可以向其中新增和刪除對映條目。

在下面的程式碼中,建立了三個 Person 例項。然後,它使用一個字典建立一個 WeakKeyDictionary 例項,其中鍵是 Person 例項,值是 Person 的姓名。

我們呼叫 keyrefs() 方法來檢索弱引用。當對 Peron1 的引用被刪除時,再次列印字典鍵。一個新的 Person 例項被新增到具有弱引用鍵的字典中。最後,我們再次列印字典的鍵。

示例

import weakref

class Person:
   def __init__(self, person_id, name, age):
      self.emp_id = person_id
      self.name = name
      self.age = age

   def __repr__(self):
      return "{} : {} : {}".format(self.person_id, self.name, self.age)
Person1 = Person(101, "Jeevan", 30)
Person2 = Person(102, "Ramanna", 35)
Person3 = Person(103, "Simran", 28)
weak_dict = weakref.WeakKeyDictionary({Person1: Person1.name, Person2: Person2.name, Person3: Person3.name})
print("Weak Key Dictionary : {}\n".format(weak_dict.data))
print("Dictionary Keys : {}\n".format([key().name for key in weak_dict.keyrefs()]))
del Person1
print("Dictionary Keys : {}\n".format([key().name for key in weak_dict.keyrefs()]))
Person4 = Person(104, "Partho", 32)
weak_dict.update({Person4: Person4.name})

print("Dictionary Keys : {}\n".format([key().name for key in weak_dict.keyrefs()]))

它將產生以下**輸出**:

Weak Key Dictionary : {<weakref at 0x7f542b6d4180; to 'Person' at 0x7f542b8bbfd0>: 'Jeevan', <weakref at 0x7f542b6d5530; to 'Person' at 0x7f542b8bbeb0>: 'Ramanna', <weakref at 0x7f542b6d55d0; to 'Person' at 0x7f542b8bb7c0>: 'Simran'}

Dictionary Keys : ['Jeevan', 'Ramanna', 'Simran']

Dictionary Keys : ['Ramanna', 'Simran']

Dictionary Keys : ['Ramanna', 'Simran', 'Partho']

WeakValueDictionary

弱引用值的對映類。當不再有強引用指向值時,字典中的條目將被丟棄。

我們將演示如何使用 WeakValueDictionary 建立一個具有弱引用值的字典。

程式碼類似於前面的示例,但這次我們使用 Person 名稱作為鍵,Person 例項作為值。我們使用 valuerefs() 方法檢索字典的弱引用值。

示例

import weakref

class Person:
   def __init__(self, person_id, name, age):
      self.emp_id = person_id
      self.name = name
      self.age = age
   
   def __repr__(self):
      return "{} : {} : {}".format(self.person_id, self.name, self.age)

Person1 = Person(101, "Jeevan", 30)
Person2 = Person(102, "Ramanna", 35)
Person3 = Person(103, "Simran", 28)

weak_dict = weakref.WeakValueDictionary({Person1.name:Person1, Person2.name:Person2, Person3.name:Person3})
print("Weak Value Dictionary : {}\n".format(weak_dict.data))
print("Dictionary Values : {}\n".format([value().name for value in weak_dict.valuerefs()]))
del Person1
print("Dictionary Values : {}\n".format([value().name for value in weak_dict.valuerefs()]))
Person4 = Person(104, "Partho", 32)
weak_dict.update({Person4.name: Person4})
print("Dictionary Values : {}\n".format([value().name for value in weak_dict.valuerefs()]))

它將產生以下**輸出**:

Weak Value Dictionary : {'Jeevan': <weakref at 0x7f3af9fe4180; to 'Person' at 0x7f3afa1c7fd0>, 'Ramanna': <weakref at 0x7f3af9fe5530; to 'Person' at 0x7f3afa1c7eb0>, 'Simran': <weakref at 0x7f3af9fe55d0; to 'Person' at 0x7f3afa1c77c0>}

Dictionary Values : ['Jeevan', 'Ramanna', 'Simran']

Dictionary Values : ['Ramanna', 'Simran']

Dictionary Values : ['Ramanna', 'Simran', 'Partho']

Python - 序列化

術語“物件序列化”是指將物件的狀態轉換為位元組流的過程。建立後,此位元組流可以進一步儲存在檔案中或透過套接字等傳輸。另一方面,從位元組流重建物件稱為反序列化。

Python 中序列化和反序列化的術語分別是 pickling 和 unpickling。Python 標準庫中提供的 pickle 模組提供了序列化 (dump() 和 dumps()) 和反序列化 (load() 和 loads()) 函式。

pickle 模組使用非常 Python 特定的資料格式。因此,並非所有非 Python 編寫的程式都能正確反序列化編碼 (pickled) 資料。此外,從未經身份驗證的來源反序列化資料也不被認為是安全的。

Pickle 協議

協議是在將 Python 物件構造和解構到/從二進位制資料時使用的約定。目前,pickle 模組定義了 5 種不同的協議,如下所示:

序號 協議和說明
1

協議版本 0

原始的“人類可讀”協議,與早期版本向後相容。

2

協議版本 1

舊的二進位制格式,也與早期版本的 Python 相容。

3

協議版本 2

在 Python 2.3 中引入,提供了對新型類的有效 pickling。

4

協議版本 3

在 Python 3.0 中新增。當需要與其他 Python 3 版本相容時推薦使用。

5

協議版本 4

在 Python 3.4 中新增。它增加了對超大型物件的支援。

要了解 Python 安裝程式的最高和預設協議版本,請使用 pickle 模組中定義的以下常量:

>>> import pickle
>>> pickle.HIGHEST_PROTOCOL
4
>>> pickle.DEFAULT_PROTOCOL
3

pickle 模組的 dump() 和 load() 函式執行 Python 資料的 pickling 和 unpickling。dump() 函式將 pickled 物件寫入檔案,load() 函式將資料從檔案 unpickle 到 Python 物件。

dump() 和 load()

以下程式將字典物件 pickle 到二進位制檔案中。

import pickle
f=open("data.txt","wb")
dct={"name":"Ravi", "age":23, "Gender":"M","marks":75}
pickle.dump(dct,f)
f.close()

執行上述程式碼後,字典物件的位元組表示將儲存在 data.txt 檔案中。

要將資料從二進位制檔案 unpickle 或反序列化回字典,請執行以下程式。

import pickle
f=open("data.txt","rb")
d=pickle.load(f)
print (d)
f.close()

Python 控制檯顯示從檔案中讀取的字典物件。

{'age': 23, 'Gender': 'M', 'name': 'Ravi', 'marks': 75}

dumps() 和 loads()

pickle 模組還包含 dumps() 函式,該函式返回 pickled 資料的字串表示形式。

>>> from pickle import dump
>>> dct={"name":"Ravi", "age":23, "Gender":"M","marks":75}
>>> dctstring=dumps(dct)
>>> dctstring
b'\x80\x03}q\x00(X\x04\x00\x00\x00nameq\x01X\x04\x00\x00\x00Raviq\x02X\x03\x00\x00\x00ageq\x03K\x17X\x06\x00\x00\x00Genderq\x04X\x01\x00\x00\x00Mq\x05X\x05\x00\x00\x00marksq\x06KKu.'

使用 loads() 函式 unpickle 字串並獲得原始字典物件。

from pickle import load
dct=loads(dctstring)
print (dct)

它將產生以下**輸出**:

{'name': 'Ravi', 'age': 23, 'Gender': 'M', 'marks': 75}

Pickler 類

pickle 模組還定義了 Pickler 和 Unpickler 類。Pickler 類將 pickle 資料寫入檔案。Unpickler 類從檔案讀取二進位制資料並構造 Python 物件。

要寫入 Python 物件的 pickled 資料:

from pickle import pickler
f=open("data.txt","wb")
dct={'name': 'Ravi', 'age': 23, 'Gender': 'M', 'marks': 75}
Pickler(f).dump(dct)
f.close()

Unpickler 類

透過 unpickle 二進位制檔案讀取資料:

from pickle import Unpickler
f=open("data.txt","rb")
dct=Unpickler(f).load()
print (dct)
f.close()

所有 Python 標準資料型別的物件都是可 pickling 的。此外,自定義類的物件也可以被 pickle 和 unpickle。

from pickle import *
class person:
   def __init__(self):
      self.name="XYZ"
      self.age=22
   def show(self):
      print ("name:", self.name, "age:", self.age)
p1=person()
f=open("data.txt","wb")
dump(p1,f)
f.close()
print ("unpickled")
f=open("data.txt","rb")
p1=load(f)
p1.show()

Python 庫還具有 marshal 模組,用於 Python 物件的內部序列化。

Python - 模板

Python 提供不同的文字格式化功能。包括格式化運算子、Python 的 format() 函式和 f-string。此外,Python 的標準庫包含 string 模組,其中包含更多格式化選項。

string 模組中的 Template 類對於透過 PEP 292 中描述的替換技術動態地形成字串物件很有用。其更簡單的語法和功能使其比 Python 中其他內建字串格式化工具更容易進行國際化翻譯。

模板字串使用 $ 符號進行替換。該符號後緊跟一個識別符號,該識別符號遵循形成有效 Python 識別符號的規則。

語法

from string import Template

tempStr = Template('Hello $name')

Template 類定義了以下方法:

substitute()

此方法執行對 Template 物件中識別符號的值的替換。可以使用關鍵字引數或字典物件來對映模板中的識別符號。該方法返回一個新字串。

示例1

以下程式碼使用關鍵字引數作為 substitute() 方法。

from string import Template

tempStr = Template('Hello. My name is $name and my age is $age')
newStr = tempStr.substitute(name = 'Pushpa', age = 26)
print (newStr)

它將產生以下**輸出**:

Hello. My name is Pushpa and my age is 26

示例2

在下面的示例中,我們使用字典物件來對映模板字串中的替換識別符號。

from string import Template

tempStr = Template('Hello. My name is $name and my age is $age')
dct = {'name' : 'Pushpalata', 'age' : 25}
newStr = tempStr.substitute(dct)
print (newStr)

它將產生以下**輸出**:

Hello. My name is Pushpalata and my age is 25

示例3

如果 substitute() 方法未提供足夠的引數來與模板字串中的識別符號匹配,則 Python 將引發 KeyError。

from string import 

tempStr = Template('Hello. My name is $name and my age is $age')
dct = {'name' : 'Pushpalata'}
newStr = tempStr.substitute(dct)
print (newStr)

它將產生以下**輸出**:

Traceback (most recent call last):
File "C:\Users\user\example.py", line 5, in 
newStr = tempStr.substitute(dct)
^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Python311\Lib\string.py", line 121, in substitute
return self.pattern.sub(convert, self.template)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Python311\Lib\string.py", line 114, in convert
return str(mapping[named])
~~~~~~~^^^^^^^
KeyError: 'age'

safe_substitute()

此方法的行為類似於 substitute() 方法,但它不會在鍵不足或不匹配時引發錯誤。相反,原始佔位符將完好無損地出現在結果字串中。

示例 4

from string import Template
tempStr = Template('Hello. My name is $name and my age is $age')
dct = {'name' : 'Pushpalata'}
newStr = tempStr.safe_substitute(dct)
print (newStr)

它將產生以下**輸出**:

Hello. My name is Pushpalata and my age is $age

is_valid()

如果模板具有無效的佔位符(這將導致 substitute() 引發 ValueError),則返回 false。

get_identifiers()

返回模板中有效識別符號的列表,按其首次出現的順序排列,忽略任何無效識別符號。

示例5

from string import Template

tempStr = Template('Hello. My name is $name and my age is $23')
print (tempStr.is_valid())
tempStr = Template('Hello. My name is $name and my age is $age')
print (tempStr.get_identifiers())

它將產生以下**輸出**:

False

['name', 'age']

示例6

"$" 符號已被定義為替換字元。如果您需要字串中出現 "$" 本身,則必須對其進行轉義。換句話說,使用 $$ 在字串中使用它。

from string import Template

tempStr = Template('The symbol for Dollar is $$')
print (tempStr.substitute())

它將產生以下**輸出**:

The symbol for Dollar is $

示例 7

如果您希望使用除 "$" 之外的任何其他字元作為替換符號,請宣告 Template 類的子類並賦值:

from string import Template

class myTemplate(Template):
   delimiter = '#'
   
tempStr = myTemplate('Hello. My name is #name and my age is #age')
print (tempStr.substitute(name='Harsha', age=30))

Python - 輸出格式化

本章將討論不同的輸出格式化技術。

字串格式化運算子

Python 最酷的功能之一是字串格式化運算子 %。此運算子是字串獨有的,彌補了缺少 C 的 printf() 系列函式的不足。C 語言中使用的格式說明符號 (%d %c %f %s 等) 在字串中用作佔位符。

以下是一個簡單的示例:

print ("My name is %s and weight is %d kg!" % ('Zara', 21))

它將產生以下**輸出**:

My name is Zara and weight is 21 kg!

format() 方法

Python 3.0 引入了 format() 方法到 str 類中,以更有效地處理複雜的字串格式化。此方法此後已被反向移植到 Python 2.6 和 Python 2.7。

此內建字串類的方法提供了進行復雜的變數替換和值格式化的能力。這種新的格式化技術被認為更優雅。

語法

format() 方法的通用語法如下:

str.format(var1, var2,...)

返回值

該方法返回一個格式化的字串。

字串本身包含佔位符 {},變數的值將依次插入其中。

示例

name="Rajesh"
age=23
print ("my name is {} and my age is {} years".format(name, age))

它將產生以下**輸出**:

my name is Rajesh and my age is 23 years

您可以將變數作為關鍵字引數傳遞給 format() 方法,並將變數名用作字串中的佔位符。

print ("my name is {name} and my age is {age}
years".format(name="Rajesh", age=23))

您還可以指定 C 樣式的格式化符號。唯一的變化是使用 : 代替 %。例如,使用 {:s} 代替 %s,使用 {:d} 代替 %d。

name="Rajesh"
age=23
print ("my name is {:s} and my age is {:d} years".format(name, age))

f-strings

在 Python 中,f-strings 或文字字串插值是另一種格式化工具。使用此格式化方法,您可以在字串常量中使用嵌入式 Python 表示式。Python f-strings 更快、更易讀、更簡潔且錯誤更少。

字串以 'f' 字首開頭,並在其中插入一個或多個佔位符,其值將動態填充。

name = 'Rajesh'
age = 23

fstring = f'My name is {name} and I am {age} years old'
print (fstring)

它將產生以下**輸出**:

My name is Rajesh and I am 23 years old

模板字串

string 模組中的 Template 類提供了一種動態格式化字串的替代方法。Template 類的優點之一是可以自定義格式化規則。

有效的模板字串或佔位符由兩部分組成:“$” 符號後跟一個有效的 Python 識別符號。

您需要建立一個 Template 類的物件,並將模板字串作為引數傳遞給建構函式。

接下來,呼叫 Template 類的 substitute() 方法。它將作為引數提供的值放在模板字串的位置。

示例

from string import Template

temp_str = "My name is $name and I am $age years old"
tempobj = Template(temp_str)
ret = tempobj.substitute(name='Rajesh', age=23)
print (ret)

它將產生以下**輸出**:

My name is Rajesh and I am 23 years old

textwrap 模組

Python 的 textwrap 模組中的 wrap 類包含透過調整輸入段落中的換行符來格式化和換行純文字的功能。它有助於使文字格式良好且美觀。

textwrap 模組具有以下便捷函式:

textwrap.wrap(text, width=70)

將文字(字串)中的單個段落進行換行處理,使每行的字元數最多為 width 個。返回一個輸出行的列表,不包含最後的換行符。可選關鍵字引數對應於 TextWrapper 例項的屬性。width 預設值為 70。

textwrap.fill(text, width=70)

將文字中的單個段落進行換行處理,並返回包含換行後段落的單個字串。

兩種方法內部都會建立一個 TextWrapper 類物件並對其呼叫單個方法。由於例項不會被重用,因此建立您自己的 TextWrapper 物件效率更高。

示例

import textwrap

text = '''
Python is a high-level, general-purpose programming language. Its design philosophy emphasizes code readability with the use of significant indentation via the off-side rule.

Python is dynamically typed and garbage-collected. It supports multiple programming paradigms, including structured (particularly procedural), object-oriented and functional programming. It is often described as a "batteries included" language due to its comprehensive standard library.
'''

wrapper = textwrap.TextWrapper(width=40)
wrapped = wrapper.wrap(text = text)

# Print output
for element in wrapped:
   print(element)

它將產生以下**輸出**:

Python is a high-level, general-purpose
programming language. Its design
philosophy emphasizes code readability
with the use of significant indentation
via the off-side rule. Python is
dynamically typed and garbage-collected.
It supports multiple programming
paradigms, including structured
(particularly procedural), objectoriented and functional programming. It
is often described as a "batteries
included" language due to its
comprehensive standard library.

以下是 TextWrapper 物件定義的屬性:

  • width − (預設值:70) 換行後行的最大長度。

  • expand_tabs − (預設值:True) 如果為 True,則文字中的所有制表符都將使用 text 的 expandtabs() 方法展開為空格。

  • tabsize − (預設值:8) 如果 expand_tabs 為 True,則文字中的所有制表符都將展開為零個或多個空格,具體取決於當前列和給定的製表符大小。

  • replace_whitespace − (預設值:True) 如果為 True,則在製表符展開後但在換行之前,wrap() 方法會將每個空格字元替換為單個空格。

  • drop_whitespace − (預設值:True) 如果為 True,則每行開頭和結尾的空格(換行後但在縮排之前)將被刪除。但是,如果段落開頭有非空格字元,則段落開頭的空格不會被刪除。如果要刪除的空格佔用了整行,則整行都會被刪除。

  • initial_indent − (預設值:'') 將附加到換行輸出第一行的字串。

  • subsequent_indent − (預設值:'') 將附加到換行輸出除第一行之外的所有行的字串。

  • fix_sentence_endings − (預設值:False) 如果為 True,則 TextWrapper 嘗試檢測句子結尾,並確保句子之間始終用兩個空格隔開。對於等寬字型中的文字,這通常是需要的。

  • break_long_words − (預設值:True) 如果為 True,則長度超過 width 的單詞將被拆分,以確保沒有行的長度超過 width。如果為 False,則長單詞不會被拆分,並且某些行的長度可能超過 width。

  • break_on_hyphens − (預設值:True) 如果為 True,則換行優先在空格處以及複合詞中的連字元後進行,這在英語中是慣例。如果為 False,則只考慮空格作為潛在的換行位置。

shorten() 函式

摺疊並截斷給定的文字以適應給定的寬度。文字首先將其空格摺疊。如果然後它適合*寬度*,則按原樣返回。否則,儘可能多的單詞被連線起來,然後附加佔位符:

示例

import textwrap

python_desc = """Python is a general-purpose interpreted, interactive, object-oriented, and high-level programming language. It was created by Guido van Rossum during 1985- 1990. Like Perl, Python source code is also available under the GNU General Public License (GPL). This tutorial gives enough understanding on Python programming language."""

my_wrap = textwrap.TextWrapper(width = 40)

short_text = textwrap.shorten(text = python_desc, width=150)
print('\n\n' + my_wrap.fill(text = short_text))

它將產生以下**輸出**:

Python is a general-purpose interpreted,
interactive, object-oriented,and high
level programming language. It was 
created by Guido van Rossum [...]

pprint 模組

Python 標準庫中的 pprint 模組可以使 Python 資料結構的顯示更美觀。pprint 代表 pretty printer(漂亮印表機)。任何可以被 Python 直譯器正確解析的資料結構都會被優雅地格式化。

格式化後的表示式儘可能保持在一行中,但如果長度超過格式化的 width 引數,則會換行。pprint 輸出的一個獨特功能是字典在顯示錶示形式被格式化之前會自動排序。

PrettyPrinter 類

pprint 模組包含 PrettyPrinter 類的定義。其建構函式採用以下格式:

語法

pprint.PrettyPrinter(indent, width, depth, stream, compact)

引數

  • indent − 定義在每個遞迴級別上新增的縮排。預設為 1。

  • width − 預設值為 80。所需的輸出受此值限制。如果長度大於 width,則會換行。

  • depth − 控制要列印的級別數。

  • stream − 預設情況下為標準輸出(stdout)——預設輸出裝置。它可以接收任何流物件,例如檔案。

  • compact − 預設情況下設定為 False。如果為 True,則只顯示可在 width 內調整的資料。

PrettyPrinter 類定義了以下方法:

pprint() 方法

列印 PrettyPrinter 物件的格式化表示。

pformat() 方法

根據建構函式的引數返回物件的格式化表示。

示例

以下示例演示了 PrettyPrinter 類的簡單用法:

import pprint
students={"Dilip":["English", "Maths", "Science"],"Raju":{"English":50,"Maths":60, "Science":70},"Kalpana":(50,60,70)}
pp=pprint.PrettyPrinter()
print ("normal print output")
print (students)
print ("----")
print ("pprint output")
pp.pprint(students)

輸出顯示了普通列印和漂亮列印:

normal print output
{'Dilip': ['English', 'Maths', 'Science'], 'Raju': {'English': 50, 'Maths': 60, 'Science': 70}, 'Kalpana': (50, 60, 70)}
----
pprint output
{'Dilip': ['English', 'Maths', 'Science'],
 'Kalpana': (50, 60, 70),
 'Raju': {'English': 50, 'Maths': 60, 'Science': 70}}

pprint 模組還定義了與 PrettyPrinter 方法對應的便捷函式 pprint() 和 pformat()。下面的示例使用了 pprint() 函式。

from pprint import pprint
students={"Dilip":["English", "Maths", "Science"],
   "Raju":{"English":50,"Maths":60, "Science":70},
      "Kalpana":(50,60,70)}
print ("normal print output")
print (students)
print ("----")
print ("pprint output")
pprint (students)

示例

下一個示例使用 pformat() 方法和 pformat() 函式。要使用 pformat() 方法,首先要設定 PrettyPrinter 物件。在這兩種情況下,格式化的表示都使用普通的 print() 函式顯示。

import pprint
students={"Dilip":["English", "Maths", "Science"],
   "Raju":{"English":50,"Maths":60, "Science":70},
      "Kalpana":(50,60,70)}
print ("using pformat method")
pp=pprint.PrettyPrinter()
string=pp.pformat(students)
print (string)
print ('------')
print ("using pformat function")
string=pprint.pformat(students)
print (string)

以下是上述程式碼的輸出:

using pformat method
{'Dilip': ['English', 'Maths', 'Science'],
 'Kalpana': (50, 60, 70),
 'Raju': {'English': 50, 'Maths': 60, 'Science': 70}}
------
using pformat function
{'Dilip': ['English', 'Maths', 'Science'],
 'Kalpana': (50, 60, 70),
 'Raju': {'English': 50, 'Maths': 60, 'Science': 70}}

漂亮列印也可以與自定義類一起使用。在類中重寫了 __repr__() 方法。當使用 repr() 函式時,會呼叫 __repr__() 方法。它是 Python 物件的官方字串表示。當我們將物件作為引數傳遞給 print() 函式時,它會列印 repr() 函式的返回值。

示例

在這個例子中,__repr__() 方法返回 player 物件的字串表示:

import pprint
class player:
   def __init__(self, name, formats=[], runs=[]):
      self.name=name
      self.formats=formats
      self.runs=runs
   def __repr__(self):
      dct={}
      dct[self.name]=dict(zip(self.formats,self.runs))
      return (repr(dct))

l1=['Tests','ODI','T20']
l2=[[140, 45, 39],[15,122,36,67, 100, 49],[78,44, 12, 0, 23, 75]]
p1=player("virat",l1,l2)
pp=pprint.PrettyPrinter()
pp.pprint(p1)

以上程式碼的輸出為:

{'virat': {'Tests': [140, 45, 39], 'ODI': [15, 122, 36, 67, 100, 49],
'T20': [78, 44, 12, 0, 23, 75]}}

Python - 效能測量

一個給定的問題可以用多種不同的演算法來解決。因此,我們需要最佳化解決方案的效能。Python 的timeit 模組是一個用於衡量 Python 應用程式效能的有用工具。

此模組中的 timit() 函式測量 Python 程式碼的執行時間。

語法

timeit.timeit(stmt, setup, timer, number)

引數

  • stmt − 用於效能測量的程式碼片段。

  • setup − 要傳遞的引數或變數的設定詳細資訊。

  • timer − 使用預設計時器,因此可以跳過。

  • number − 程式碼將執行此次數。預設為 1000000。

示例

以下語句使用列表推導式返回從 0 到 100 的每個數字的 2 的倍數列表。

>>> [n*2 for n in range(100)]
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34,
36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68,
70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100,
102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126,
128, 130, 132, 134, 136, 138, 140, 142, 144, 146, 148, 150, 152,
154, 156, 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178,
180, 182, 184, 186, 188, 190, 192, 194, 196, 198]

為了測量上述語句的執行時間,我們使用 timeit() 函式,如下所示:

>>> from timeit import timeit
>>> timeit('[n*2 for n in range(100)]', number=10000)
0.0862189000035869

將執行時間與使用 for 迴圈附加數字的過程進行比較。

>>> string = '''
... numbers=[]
... for n in range(100):
... numbers.append(n*2)
... '''
>>> timeit(string, number=10000)
0.1010853999905521

結果表明列表推導式效率更高。

語句字串可以包含一個 Python 函式,可以將一個或多個引數作為設定程式碼傳遞給它。

我們將查詢並比較使用迴圈的階乘函式與其遞迴版本的執行時間。

使用 for 迴圈的普通函式為:

def fact(x):
   fact = 1
   for i in range(1, x+1):
      fact*=i
   return fact

遞迴階乘的定義。

def rfact(x):
   if x==1:
      return 1
   else:
      return x*fact(x-1)

測試這些函式以計算 10 的階乘。

print ("Using loop:",fact(10))
print ("Using Recursion",rfact(10))
Result
Using loop: 3628800
Using Recursion 3628800

現在我們將使用 timeit() 函式查詢它們的各自執行時間。

import timeit

setup1="""
from __main__ import fact
x = 10
"""

setup2="""
from __main__ import rfact
x = 10
"""

print ("Performance of factorial function with loop")
print(timeit.timeit(stmt = "fact(x)", setup=setup1, number=10000))

print ("Performance of factorial function with Recursion")
print(timeit.timeit(stmt = "rfact(x)", setup=setup2, number=10000))

輸出

Performance of factorial function with loop
0.00330029999895487
Performance of factorial function with Recursion
0.006506800003990065

遞迴函式比帶迴圈的函式慢。

這樣,我們可以對 Python 程式碼進行效能測量。

Python - 資料壓縮

Python 的標準庫包含豐富的用於資料壓縮和存檔的模組集合。可以選擇任何適合其工作的模組。

以下是與資料壓縮相關的模組:

序號 模組和說明

1

zlib

與 gzip 相容的壓縮。

2

gzip

支援 gzip 檔案。

3

bz2

支援 bz2 壓縮。

4

lzma

使用 LZMA 演算法進行壓縮。

5

zipfile

處理 ZIP 檔案。

6

tarfilev

讀取和寫入 tar 歸檔檔案。

Python - CGI 程式設計

公共閘道器介面(CGI)是一套標準,定義瞭如何在 Web 伺服器和自定義指令碼之間交換資訊。CGI 規範目前由 NCSA 維護。

什麼是 CGI?

  • 公共閘道器介面(CGI)是外部閘道器程式與資訊伺服器(例如 HTTP 伺服器)互動的標準。

  • 當前版本為 CGI/1.1,CGI/1.2 正在開發中。

網頁瀏覽

為了理解 CGI 的概念,讓我們看看當我們點選超連結來瀏覽特定的網頁或 URL 時會發生什麼。

  • 您的瀏覽器聯絡 HTTP Web 伺服器並請求 URL,即檔名。

  • Web 伺服器解析 URL 並查詢檔名。如果找到該檔案,則將其傳送回瀏覽器,否則傳送錯誤訊息,指示您請求的檔案錯誤。

  • Web 瀏覽器接收來自 Web 伺服器的響應,並顯示接收到的檔案或錯誤訊息。

但是,可以設定 HTTP 伺服器,以便每當請求某個目錄中的檔案時,該檔案不會被髮送回;而是將其作為程式執行,並且該程式輸出的內容將被髮送回以供您的瀏覽器顯示。此功能稱為公共閘道器介面或 CGI,程式稱為 CGI 指令碼。這些 CGI 程式可以是 Python 指令碼、PERL 指令碼、Shell 指令碼、C 或 C++ 程式等。

CGI 架構圖

Cgi Architecture Diagram

Web 伺服器支援和配置

在繼續進行 CGI 程式設計之前,請確保您的 Web 伺服器支援 CGI 並且已配置為處理 CGI 程式。所有要由 HTTP 伺服器執行的 CGI 程式都儲存在預配置的目錄中。此目錄稱為 CGI 目錄,按照慣例,其名稱為 /var/www/cgi-bin。按照慣例,CGI 檔案的副檔名為 .cgi,但您也可以將檔案保留為 python 副檔名.py

預設情況下,Linux 伺服器配置為僅執行 /var/www 中 cgi-bin 目錄中的指令碼。如果要指定其他目錄來執行 CGI 指令碼,請在 httpd.conf 檔案中註釋以下幾行:

<Directory "/var/www/cgi-bin">
   AllowOverride None
   Options ExecCGI
   Order allow,deny
   Allow from all
</Directory>

<Directory "/var/www/cgi-bin">
Options All
</Directory>

還應為 apache 伺服器新增以下行,以將 .py 檔案視為 cgi 指令碼。

AddHandler cgi-script .py

在這裡,我們假設您的 Web 伺服器已成功啟動並執行,並且您可以執行其他 CGI 程式,例如 Perl 或 Shell 等。

第一個 CGI 程式

這是一個簡單的連結,它連結到名為 hello.py 的 CGI 指令碼。此檔案儲存在 /var/www/cgi-bin 目錄中,其內容如下。在執行 CGI 程式之前,請確保已使用chmod 755 hello.py UNIX 命令更改檔案的模式以使其可執行。

print ("Content-type:text/html\r\n\r\n")
print ('<html>')
print ('<head>')
print ('<title>Hello Word - First CGI Program</title>')
print ('</head>')
print ('<body>')
print ('<h2>Hello Word! This is my first CGI program</h2>')
print ('</body>')
print ('</html>')

注意 - 指令碼中的第一行必須是 Python 可執行檔案的路徑。它在 Python 程式中顯示為註釋,但它被稱為 Shebang 行。

在 Linux 中,它應該是 #!/usr/bin/python3。

在 Windows 中,它應該是 #!c:/python311/python.exd。

在瀏覽器中輸入以下 URL:

https:///cgi-bin/hello.py

Hello Word! This is my first CGI program

這個 hello.py 指令碼是一個簡單的 Python 指令碼,它將其輸出寫入 STDOUT 檔案,即螢幕。有一個重要且額外的功能可用,即要列印的第一行Content-type:text/html\r\n\r\n。此行傳送回瀏覽器,它指定要顯示在瀏覽器螢幕上的內容型別。

到目前為止,您一定已經瞭解了 CGI 的基本概念,並且可以使用 Python 編寫許多複雜的 CGI 程式。此指令碼還可以與任何其他外部系統互動以交換資訊,例如 RDBMS。

HTTP 標頭

Content-type:text/html\r\n\r\n是 HTTP 標頭的一部分,傳送到瀏覽器以理解內容。所有 HTTP 標頭都將採用以下形式:

HTTP Field Name: Field Content

For Example
Content-type: text/html\r\n\r\n

還有一些其他重要的 HTTP 標頭,您將在 CGI 程式設計中經常使用。

序號 標頭和說明
1

Content-type

定義返回檔案的格式的 MIME 字串。例如 Content-type:text/html

2

Expires: Date

資訊失效日期。瀏覽器使用此日期判斷頁面是否需要重新整理。有效的日期字串格式為 01 Jan 1998 12:00:00 GMT。

3

位置:URL

返回的 URL,而不是請求的 URL。您可以使用此欄位將請求重定向到任何檔案。

4

上次修改:日期

資源上次修改的日期。

5

內容長度:N

返回資料的長度(以位元組為單位)。瀏覽器使用此值報告檔案的預計下載時間。

6

Set-Cookie:字串

設定透過字串傳遞的 Cookie。

CGI 環境變數

所有 CGI 程式都可以訪問以下環境變數。這些變數在編寫任何 CGI 程式時都起著重要作用。

序號 變數名稱和描述
1

CONTENT_TYPE

內容的資料型別。當客戶端向伺服器傳送附加內容時使用,例如檔案上傳。

2

CONTENT_LENGTH

查詢資訊的長度。僅對 POST 請求可用。

3

HTTP_COOKIE

以鍵值對的形式返回設定的 Cookie。

4

HTTP_USER_AGENT

User-Agent 請求頭欄位包含有關發起請求的使用者代理的資訊。它是 web 瀏覽器的名稱。

5

PATH_INFO

CGI 指令碼的路徑。

6

QUERY_STRING

使用 GET 方法請求傳送的 URL 編碼資訊。

7

REMOTE_ADDR

發出請求的遠端主機的 IP 地址。這對於日誌記錄或身份驗證很有用。

8

REMOTE_HOST

發出請求的主機的完全限定名稱。如果此資訊不可用,則可以使用 REMOTE_ADDR 獲取 IP 地址。

9

REQUEST_METHOD

用於發出請求的方法。最常見的方法是 GET 和 POST。

10

SCRIPT_FILENAME

CGI 指令碼的完整路徑。

11

SCRIPT_NAME

CGI 指令碼的名稱。

12

SERVER_NAME

伺服器的主機名或 IP 地址。

13

SERVER_SOFTWARE

伺服器正在執行的軟體的名稱和版本。

這是一個列出所有 CGI 變數的小型 CGI 程式。點選此連結檢視結果 獲取環境變數

import os

print ("Content-type: text/html\r\n\r\n");
print ("<font size=+1>Environment</font><\br>");
for param in os.environ.keys():
   print ("<b>%20s</b>: %s<\br>" % (param, os.environ[param]))

GET 和 POST 方法

您一定遇到過許多需要將某些資訊從瀏覽器傳遞到 web 伺服器,最終傳遞到您的 CGI 程式的情況。最常見的是,瀏覽器使用兩種方法將此資訊傳遞到 web 伺服器。這些方法是 GET 方法和 POST 方法。

使用 GET 方法傳遞資訊

GET 方法傳送附加到頁面請求的編碼使用者資訊。頁面和編碼資訊由 ? 字元分隔,如下所示:

http://www.test.com/cgi-bin/hello.py?key1=value1&key2=value2
  • GET 方法是從瀏覽器向 web 伺服器傳遞資訊的預設方法,它會生成一個長字串,顯示在瀏覽器的位址列中。

  • 如果您需要傳遞密碼或其他敏感資訊到伺服器,請勿使用 GET 方法。

  • GET 方法有大小限制:請求字串中只能傳送 1024 個字元。

  • GET 方法使用 QUERY_STRING 頭部發送資訊,並且可以透過 QUERY_STRING 環境變數在您的 CGI 程式中訪問。

您可以透過簡單地連線鍵值對以及任何 URL 來傳遞資訊,也可以使用 HTML <FORM> 標記使用 GET 方法傳遞資訊。

簡單的 URL 示例:GET 方法

這是一個簡單的 URL,它使用 GET 方法將兩個值傳遞給 hello_get.py 程式。

/cgi-bin/hello_get.py?first_name=Malhar&last_name=Lathkar

下面是處理 web 瀏覽器提供的輸入的 hello_get.py 指令碼。我們將使用 cgi 模組,它使訪問傳遞的資訊變得非常容易:

# Import modules for CGI handling
import cgi, cgitb

# Create instance of FieldStorage
form = cgi.FieldStorage()

# Get data from fields
first_name = form.getvalue('first_name')
last_name = form.getvalue('last_name')

print ("Content-type:text/html")
print()
print ("<html>")
print ('<head>')
print ("<title>Hello - Second CGI Program</title>")
print ('</head>')
print ('<body>')
print ("<h2>Hello %s %s</h2>" % (first_name, last_name))
print ('</body>')
print ('</html>')

這將生成以下結果:

Hello Malhar Lathkar

簡單的表單示例:GET 方法

此示例使用 HTML 表單和提交按鈕傳遞兩個值。我們使用相同的 CGI 指令碼 hello_get.py 來處理此輸入。

<form action = "/cgi-bin/hello_get.py" method = "get">
   First Name: <input type = "text" name = "first_name">  <br />

   Last Name: <input type = "text" name = "last_name" />
   <input type = "submit" value = "Submit" />
</form>

這是上面表單的實際輸出,您輸入名字和姓氏,然後點選提交按鈕檢視結果。

名字
姓氏

使用 POST 方法傳遞資訊

將資訊傳遞到 CGI 程式的一種通常更可靠的方法是 POST 方法。此方法以與 GET 方法完全相同的方式打包資訊,但它不是在 URL 中的 ? 後面傳送為文字字串,而是將其作為單獨的訊息傳送。此訊息以標準輸入的形式進入 CGI 指令碼。

以下是處理 GET 和 POST 方法的相同 hello_get.py 指令碼。

# Import modules for CGI handling 
import cgi, cgitb 

# Create instance of FieldStorage 
form = cgi.FieldStorage() 

# Get data from fields
first_name = form.getvalue('first_name')
last_name  = form.getvalue('last_name')

print "Content-type:text/html\r\n\r\n"
print "<html>"
print "<head>"
print "<title>Hello - Second CGI Program</title>"
print "</head>"
print "<body>"
print "<h2>Hello %s %s</h2>" % (first_name, last_name)
print "</body>"
print "</html>"

讓我們再次採用與上面相同的示例,該示例使用 HTML 表單和提交按鈕傳遞兩個值。我們使用相同的 CGI 指令碼 hello_get.py 來處理此輸入。

<form action = "/cgi-bin/hello_get.py" method = "post">
First Name: <input type = "text" name = "first_name"><br />
Last Name: <input type = "text" name = "last_name" />

<input type = "submit" value = "Submit" />
</form>

這是上面表單的實際輸出。您輸入名字和姓氏,然後點選提交按鈕檢視結果。

名字
姓氏

將複選框資料傳遞到 CGI 程式

當需要選擇多個選項時,使用複選框。

這是一個帶有兩個複選框的表單的示例 HTML 程式碼:

<form action = "/cgi-bin/checkbox.cgi" method = "POST" target = "_blank">
   <input type = "checkbox" name = "maths" value = "on" /> Maths
   <input type = "checkbox" name = "physics" value = "on" /> Physics
   <input type = "submit" value = "Select Subject" />
</form>

此程式碼的結果是以下表單:

數學物理

以下是處理 web 瀏覽器為複選按鈕提供的輸入的 checkbox.cgi 指令碼:

# Import modules for CGI handling 
import cgi, cgitb 

# Create instance of FieldStorage 
form = cgi.FieldStorage() 

# Get data from fields
if form.getvalue('maths'):
   math_flag = "ON"
else:
   math_flag = "OFF"

if form.getvalue('physics'):
   physics_flag = "ON"
else:
   physics_flag = "OFF"

print "Content-type:text/html\r\n\r\n"
print "<html>"
print "<head>"
print "<title>Checkbox - Third CGI Program</title>"
print "</head>"
print "<body>"
print "<h2> CheckBox Maths is : %s</h2>" % math_flag
print "<h2> CheckBox Physics is : %s</h2>" % physics_flag
print "</body>"
print "</html>"

將單選按鈕資料傳遞到 CGI 程式

當只需要選擇一個選項時,使用單選按鈕。

這是一個帶有兩個單選按鈕的表單的示例 HTML 程式碼:

<form action = "/cgi-bin/radiobutton.py" method = "post" target = "_blank">
   <input type = "radio" name = "subject" value = "maths" /> Maths
   <input type = "radio" name = "subject" value = "physics" /> Physics
   <input type = "submit" value = "Select Subject" />
</form>

此程式碼的結果是以下表單:

數學物理

以下是處理 web 瀏覽器為單選按鈕提供的輸入的 radiobutton.py 指令碼:

# Import modules for CGI handling 
import cgi, cgitb 

# Create instance of FieldStorage 
form = cgi.FieldStorage() 

# Get data from fields
if form.getvalue('subject'):
   subject = form.getvalue('subject')
else:
   subject = "Not set"

print "Content-type:text/html\r\n\r\n"
print "<html>"
print "<head>"
print "<title>Radio - Fourth CGI Program</title>"
print "</head>"
print "<body>"
print "<h2> Selected Subject is %s</h2>" % subject
print "</body>"
print "</html>"

將文字區域資料傳遞到 CGI 程式

當需要將多行文字傳遞到 CGI 程式時,使用 TEXTAREA 元素。

這是一個帶有 TEXTAREA 框的表單的示例 HTML 程式碼:

<form action = "/cgi-bin/textarea.py" method = "post" target = "_blank">
   <textarea name = "textcontent" cols = "40" rows = "4">
      Type your text here...
   </textarea>
   <input type = "submit" value = "Submit" />
</form>

此程式碼的結果是以下表單:

以下是處理 web 瀏覽器提供的輸入的 textarea.cgi 指令碼:

# Import modules for CGI handling 
import cgi, cgitb 

# Create instance of FieldStorage 
form = cgi.FieldStorage() 

# Get data from fields
if form.getvalue('textcontent'):
   text_content = form.getvalue('textcontent')
else:
   text_content = "Not entered"

print "Content-type:text/html\r\n\r\n"
print "<html>"
print "<head>";
print "<title>Text Area - Fifth CGI Program</title>"
print "</head>"
print "<body>"
print "<h2> Entered Text Content is %s</h2>" % text_content
print "</body>"

將下拉框資料傳遞到 CGI 程式

當有很多選項可用但只選擇一兩個時,使用下拉框。

這是一個帶有一個下拉框的表單的示例 HTML 程式碼:

<form action = "/cgi-bin/dropdown.py" method = "post" target = "_blank">
   <select name = "dropdown">
      <option value = "Maths" selected>Maths</option>
      <option value = "Physics">Physics</option>
   </select>
   <input type = "submit" value = "Submit"/>
</form>

此程式碼的結果是以下表單:

以下是處理 web 瀏覽器提供的輸入的 dropdown.py 指令碼。

# Import modules for CGI handling 
import cgi, cgitb 

# Create instance of FieldStorage 
form = cgi.FieldStorage() 

# Get data from fields
if form.getvalue('dropdown'):
   subject = form.getvalue('dropdown')
else:
   subject = "Not entered"

print "Content-type:text/html\r\n\r\n"
print "<html>"
print "<head>"
print "<title>Dropdown Box - Sixth CGI Program</title>"
print "</head>"
print "<body>"
print "<h2> Selected Subject is %s</h2>" % subject
print "</body>"
print "</html>"

在 CGI 中使用 Cookie

HTTP 協議是無狀態協議。對於商業網站,需要在不同的頁面之間維護會話資訊。例如,一個使用者註冊在完成許多頁面後結束。如何跨所有網頁維護使用者的會話資訊?

在許多情況下,使用 Cookie 是記住和跟蹤偏好、購買、佣金以及其他提高訪客體驗或網站統計資訊所需資訊的最高效方法。

工作原理?

您的伺服器以 Cookie 的形式向訪問者的瀏覽器傳送一些資料。瀏覽器可能會接受 Cookie。如果是這樣,它將作為純文字記錄儲存在訪問者的硬碟驅動器上。現在,當訪問者到達您網站上的另一個頁面時,Cookie 可供檢索。檢索後,您的伺服器就知道/記住儲存的內容。

Cookie 是 5 個可變長度欄位的純文字資料記錄:

  • 過期 - Cookie 將過期的日期。如果為空,則 Cookie 將在訪問者退出瀏覽器時過期。

  • 域名 - 您網站的域名。

  • 路徑 - 設定 Cookie 的目錄或網頁的路徑。如果您想從任何目錄或頁面檢索 Cookie,則可以為空。

  • 安全 - 如果此欄位包含單詞“安全”,則 Cookie 只能使用安全伺服器檢索。如果此欄位為空,則不存在此類限制。

  • 名稱 = 值 - Cookie 以鍵值對的形式設定和檢索。

設定 Cookie

將 Cookie 傳送到瀏覽器非常容易。這些 Cookie 與 HTTP 頭一起傳送到 Content-type 欄位之前。假設您想設定 UserID 和 Password 作為 Cookie。設定 Cookie 的方法如下:

print "Set-Cookie:UserID = XYZ;\r\n"
print "Set-Cookie:Password = XYZ123;\r\n"
print "Set-Cookie:Expires = Tuesday, 31-Dec-2007 23:12:40 GMT;\r\n"
print "Set-Cookie:Domain = www.tutorialspoint.com;\r\n"
print "Set-Cookie:Path = /perl;\n"
print "Content-type:text/html\r\n\r\n"
...........Rest of the HTML Content....

從這個例子中,您必須已經瞭解如何設定 Cookie。我們使用 Set-Cookie HTTP 頭來設定 Cookie。

可以根據需要設定 Cookie 屬性,例如 Expires、Domain 和 Path。值得注意的是,Cookie 是在傳送神奇行 "Content-type:text/html\r\n\r\n" 之前設定的。

檢索 Cookie

檢索所有已設定的 Cookie 非常容易。Cookie 儲存在 CGI 環境變數 HTTP_COOKIE 中,它們將具有以下形式:

key1 = value1;key2 = value2;key3 = value3....

這是一個關於如何檢索 Cookie 的示例。

# Import modules for CGI handling 
from os import environ
import cgi, cgitb

if environ.has_key('HTTP_COOKIE'):
   for cookie in map(strip, split(environ['HTTP_COOKIE'], ';')):
      (key, value ) = split(cookie, '=');
      if key == "UserID":
         user_id = value

      if key == "Password":
         password = value

print "User ID  = %s" % user_id
print "Password = %s" % password

這將為上面指令碼設定的 Cookie 生成以下結果:

User ID = XYZ
Password = XYZ123

檔案上傳示例

要上傳檔案,HTML 表單必須將 enctype 屬性設定為 multipart/form-data。帶有檔案型別的輸入標記會建立一個“瀏覽”按鈕。

<html>
   <body>
      <form enctype = "multipart/form-data" action = "save_file.py" method = "post">
      <p>File: <input type = "file" name = "filename" /></p>
      <p><input type = "submit" value = "Upload" /></p>
      </form>
   </body>
</html>

此程式碼的結果是以下表單:

檔案

為了避免使用者向我們的伺服器上傳檔案,以上示例已被故意停用,但您可以在您的伺服器上嘗試以上程式碼。

以下是處理檔案上傳的指令碼 save_file.py

import cgi, os
import cgitb; cgitb.enable()

form = cgi.FieldStorage()

# Get filename here.
fileitem = form['filename']

# Test if the file was uploaded
if fileitem.filename:
   # strip leading path from file name to avoid 
   # directory traversal attacks
   fn = os.path.basename(fileitem.filename)
   open('/tmp/' + fn, 'wb').write(fileitem.file.read())

   message = 'The file "' + fn + '" was uploaded successfully'
   
else:
   message = 'No file was uploaded'
   
print """\
Content-Type: text/html\n
<html>
   <body>
      <p>%s</p>
   </body>
</html>
""" % (message,)

如果您在 Unix/Linux 上執行以上指令碼,則需要注意替換檔案分隔符,否則在您的 Windows 機器上,以上 open() 語句應該可以正常工作。

fn = os.path.basename(fileitem.filename.replace("\\", "/" ))

如何顯示“檔案下載”對話方塊?

有時,您可能希望提供一個選項,使用者可以點選一個連結,它會向用戶彈出一個“檔案下載”對話方塊,而不是顯示實際內容。這非常容易實現,可以透過 HTTP 頭實現。此 HTTP 頭與上一節中提到的頭不同。

例如,如果您想使 FileName 檔案可以透過給定的連結下載,則其語法如下:

# HTTP Header
print "Content-Type:application/octet-stream; name = \"FileName\"\r\n";
print "Content-Disposition: attachment; filename = \"FileName\"\r\n\n";

# Actual File Content will go here.
fo = open("foo.txt", "rb")

str = fo.read();
print str

# Close opend file
fo.close()

Python - XML 處理

XML 是一種可移植的開源語言,允許程式設計師開發其他應用程式可以讀取的應用程式,而不管作業系統和/或開發語言如何。

什麼是 XML?

可擴充套件標記語言 (XML) 是一種類似於 HTML 或 SGML 的標記語言。這是全球資訊網聯盟推薦的開放標準。

XML 對於跟蹤少量到中等數量的資料非常有用,而無需基於 SQL 的後端。

XML 解析器架構和 API。

Python 標準庫提供了一組最小但有用的介面來處理 XML。所有用於 XML 處理的子模組都位於 xml 包中。

  • xml.etree.ElementTree − ElementTree API,一個簡單輕量級的 XML 處理器

  • xml.dom − DOM API 定義。

  • xml.dom.minidom − 最小化的 DOM 實現。

  • xml.dom.pulldom − 支援構建部分 DOM 樹。

  • xml.sax − SAX2 基類和便捷函式。

  • xml.parsers.expat − Expat 解析器繫結。

處理 XML 資料最基本和最廣泛使用的兩個 API 是 SAX 和 DOM 介面。

  • 可擴充套件標記語言簡單 API (SAX) − 在這裡,您為感興趣的事件註冊回撥函式,然後讓解析器處理文件。當您的文件很大或記憶體有限時,這很有用,它在從磁碟讀取檔案時進行解析,並且整個檔案永遠不會儲存在記憶體中。

  • 文件物件模型 (DOM) − 這是全球資訊網聯盟的一項建議,其中整個檔案被讀入記憶體並存儲在分層(基於樹)的形式中,以表示 XML 文件的所有特性。

在處理大型檔案時,SAX 的處理速度顯然不如 DOM 快。另一方面,僅使用 DOM 可能會嚴重消耗您的資源,尤其是在處理許多小檔案時。

SAX 是隻讀的,而 DOM 允許更改 XML 檔案。由於這兩個不同的 API 實際上是互補的,因此您沒有理由不能將它們都用於大型專案。

對於我們所有的 XML 程式碼示例,讓我們使用一個簡單的 XML 檔案movies.xml作為輸入−

<collection shelf="New Arrivals">
<movie title="Enemy Behind">
   <type>War, Thriller</type>
   <format>DVD</format>
   <year>2003</year>
   <rating>PG</rating>
   <stars>10</stars>
   <description>Talk about a US-Japan war</description>
</movie>
<movie title="Transformers">
   <type>Anime, Science Fiction</type>
   <format>DVD</format>
   <year>1989</year>
   <rating>R</rating>
   <stars>8</stars>
   <description>A schientific fiction</description>
</movie>
   <movie title="Trigun">
   <type>Anime, Action</type>
   <format>DVD</format>
   <episodes>4</episodes>
   <rating>PG</rating>
   <stars>10</stars>
   <description>Vash the Stampede!</description>
</movie>
   <movie title="Ishtar">
   <type>Comedy</type>
   <format>VHS</format>
   <rating>PG</rating>
   <stars>2</stars>
   <description>Viewable boredom</description>
</movie>
</collection>

使用 SAX API 解析 XML

SAX 是用於事件驅動的 XML 解析的標準介面。使用 SAX 解析 XML 通常需要您透過子類化 xml.sax.ContentHandler 來建立自己的 ContentHandler。

您的 ContentHandler 處理您所用 XML 型別(s) 的特定標籤和屬性。ContentHandler 物件提供方法來處理各種解析事件。它的擁有者解析器在解析 XML 檔案時呼叫 ContentHandler 方法。

startDocument 和 endDocument 方法分別在 XML 檔案的開始和結束時被呼叫。characters(text) 方法透過引數 text 傳遞 XML 檔案的字元資料。

在每個元素的開始和結束時都會呼叫 ContentHandler。如果解析器不是名稱空間模式,則會呼叫 startElement(tag, attributes) 和 endElement(tag) 方法;否則,將呼叫相應的 startElementNS 和 endElementNS 方法。這裡,tag 是元素標籤,attributes 是 Attributes 物件。

以下是繼續之前需要了解的其他重要方法−

make_parser 方法

以下方法建立一個新的解析器物件並將其返回。建立的解析器物件將是系統找到的第一個解析器型別。

xml.sax.make_parser( [parser_list] )

以下是引數的詳細資訊−

  • parser_list − 可選引數,包含一個要使用的解析器列表,這些解析器都必須實現 make_parser 方法。

parse 方法

以下方法建立一個 SAX 解析器並使用它來解析文件。

xml.sax.parse( xmlfile, contenthandler[, errorhandler])

以下是引數的詳細資訊−

  • xmlfile − 這是要從中讀取的 XML 檔案的名稱。

  • contenthandler − 這必須是一個 ContentHandler 物件。

  • errorhandler − 如果指定,errorhandler 必須是 SAX ErrorHandler 物件。

parseString 方法

還有一個方法可以建立一個 SAX 解析器並解析指定的 XML 字串。

xml.sax.parseString(xmlstring, contenthandler[, errorhandler])

以下是引數的詳細資訊−

  • xmlstring − 這是要從中讀取的 XML 字串的名稱。

  • contenthandler − 這必須是一個 ContentHandler 物件。

  • errorhandler − 如果指定,errorhandler 必須是 SAX ErrorHandler 物件。

示例

import xml.sax
class MovieHandler( xml.sax.ContentHandler ):
   def __init__(self):
      self.CurrentData = ""
      self.type = ""
      self.format = ""
      self.year = ""
      self.rating = ""
      self.stars = ""
      self.description = ""

   # Call when an element starts
   def startElement(self, tag, attributes):
      self.CurrentData = tag
      if tag == "movie":
         print ("*****Movie*****")
         title = attributes["title"]
         print ("Title:", title)

   # Call when an elements ends
   def endElement(self, tag):
      if self.CurrentData == "type":
         print ("Type:", self.type)
      elif self.CurrentData == "format":
         print ("Format:", self.format)
      elif self.CurrentData == "year":
         print ("Year:", self.year)
      elif self.CurrentData == "rating":
         print ("Rating:", self.rating)
      elif self.CurrentData == "stars":
         print ("Stars:", self.stars)
      elif self.CurrentData == "description":
         print ("Description:", self.description)
      self.CurrentData = ""

   # Call when a character is read
   def characters(self, content):
      if self.CurrentData == "type":
         self.type = content
      elif self.CurrentData == "format":
         self.format = content
      elif self.CurrentData == "year":
         self.year = content
      elif self.CurrentData == "rating":
         self.rating = content
      elif self.CurrentData == "stars":
         self.stars = content
      elif self.CurrentData == "description":
         self.description = content

if ( __name__ == "__main__"):

   # create an XMLReader
   parser = xml.sax.make_parser()
   
   # turn off namepsaces
   parser.setFeature(xml.sax.handler.feature_namespaces, 0)
   
   # override the default ContextHandler
   Handler = MovieHandler()
   parser.setContentHandler( Handler )
   
   parser.parse("movies.xml")

這將產生以下結果−

*****Movie*****
Title: Enemy Behind
Type: War, Thriller
Format: DVD
Year: 2003
Rating: PG
Stars: 10
Description: Talk about a US-Japan war
*****Movie*****
Title: Transformers
Type: Anime, Science Fiction
Format: DVD
Year: 1989
Rating: R
Stars: 8
Description: A schientific fiction
*****Movie*****
Title: Trigun
Type: Anime, Action
Format: DVD
Rating: PG
Stars: 10
Description: Vash the Stampede!
*****Movie*****
Title: Ishtar
Type: Comedy
Format: VHS
Rating: PG
Stars: 2
Description: Viewable boredom

有關 SAX API 文件的完整詳細資訊,請參閱標準Python SAX API

使用 DOM API 解析 XML

文件物件模型 (“DOM”) 是全球資訊網聯盟 (W3C) 提供的一個跨語言 API,用於訪問和修改 XML 文件。

DOM 對於隨機訪問應用程式非常有用。SAX 只允許您一次檢視文件的一小部分。如果您正在檢視一個 SAX 元素,則無法訪問其他元素。

以下是如何快速載入 XML 文件並使用 xml.dom 模組建立 minidom 物件的最簡單方法。minidom 物件提供了一個簡單的解析器方法,可以快速從 XML 檔案建立 DOM 樹。

示例短語呼叫 minidom 物件的 parse(file [,parser]) 函式來解析 XML 檔案,該檔案由 file 指定為 DOM 樹物件。

from xml.dom.minidom import parse
import xml.dom.minidom

# Open XML document using minidom parser
DOMTree = xml.dom.minidom.parse("movies.xml")
collection = DOMTree.documentElement
if collection.hasAttribute("shelf"):
   print ("Root element : %s" % collection.getAttribute("shelf"))

# Get all the movies in the collection
movies = collection.getElementsByTagName("movie")

# Print detail of each movie.
for movie in movies:
   print ("*****Movie*****")
   if movie.hasAttribute("title"):
      print ("Title: %s" % movie.getAttribute("title"))

   type = movie.getElementsByTagName('type')[0]
   print ("Type: %s" % type.childNodes[0].data)
   format = movie.getElementsByTagName('format')[0]
   print ("Format: %s" % format.childNodes[0].data)
   rating = movie.getElementsByTagName('rating')[0]
   print ("Rating: %s" % rating.childNodes[0].data)
   description = movie.getElementsByTagName('description')[0]
   print ("Description: %s" % description.childNodes[0].data)

這將產生以下輸出

Root element : New Arrivals
*****Movie*****
Title: Enemy Behind
Type: War, Thriller
Format: DVD
Rating: PG
Description: Talk about a US-Japan war
*****Movie*****
Title: Transformers
Type: Anime, Science Fiction
Format: DVD
Rating: R
Description: A schientific fiction
*****Movie*****
Title: Trigun
Type: Anime, Action
Format: DVD
Rating: PG
Description: Vash the Stampede!
*****Movie*****
Title: Ishtar
Type: Comedy
Format: VHS
Rating: PG
Description: Viewable boredom

有關 DOM API 文件的完整詳細資訊,請參閱標準Python DOM API

ElementTree XML API

xml 包有一個 ElementTree 模組。這是一個簡單輕量級的 XML 處理器 API。

XML 是一種類似樹的分層資料格式。此模組中的“ElementTree”將整個 XML 文件視為一棵樹。“Element”類表示此樹中的單個節點。對 XML 檔案的讀寫操作是在 ElementTree 級別進行的。與單個 XML 元素及其子元素的互動是在 Element 級別進行的。

建立 XML 檔案

樹是從根開始,然後是其他元素的元素的分層結構。每個元素都是使用此模組的 Element() 函式建立的。

import xml.etree.ElementTree as et
e=et.Element('name')

每個元素都具有一個標籤和一個 attrib 屬性,它是一個 dict 物件。對於樹的起始元素,attrib 是一個空字典。

>>> root=xml.Element('employees')
>>> root.tag
'employees'
>>> root.attrib
{}

您現在可以設定一個或多個子元素新增到根元素下。每個子元素可能具有一個或多個子元素。使用 SubElement() 函式新增它們並定義其文字屬性。

child=xml.Element("employee")
nm = xml.SubElement(child, "name")
nm.text = student.get('name')
age = xml.SubElement(child, "salary")
age.text = str(student.get('salary'))

每個子元素都透過 append() 函式新增到根元素中,如下所示:−

root.append(child)

新增所需數量的子元素後,使用 elementTree() 函式構造一個樹物件−

tree = et.ElementTree(root)

整個樹結構透過樹物件的 write() 函式寫入二進位制檔案−

f=open('employees.xml', "wb")
tree.write(f)

示例

在此示例中,樹是由一系列字典項構建的。每個字典項都包含描述學生資料結構的鍵值對。因此構建的樹被寫入“myfile.xml”

import xml.etree.ElementTree as et
employees=[{'name':'aaa','age':21,'sal':5000},{'name':xyz,'age':22,'sal':6000}]
root = et.Element("employees")
for employee in employees:
   child=xml.Element("employee")
   root.append(child)
   nm = xml.SubElement(child, "name")
   nm.text = student.get('name')
   age = xml.SubElement(child, "age")
   age.text = str(student.get('age'))
   sal=xml.SubElement(child, "sal")
   sal.text=str(student.get('sal'))
tree = et.ElementTree(root)
with open('employees.xml', "wb") as fh:
   tree.write(fh)

“myfile.xml”儲存在當前工作目錄中。

<employees><employee><name>aaa</name><age>21</age><sal>5000</sal></employee><employee><name>xyz</name><age>22</age><sal>60</sal></employee></employee>

解析 XML 檔案

現在讓我們讀取上面示例中建立的“myfile.xml”。為此,將使用 ElementTree 模組中的以下函式−

ElementTree() − 此函式被過載為將元素的分層結構讀取到樹物件中。

tree = et.ElementTree(file='students.xml')

getroot() − 此函式返回樹的根元素。

root = tree.getroot()

您可以獲取元素下一級別子元素的列表。

children = list(root)

在下面的示例中,“myfile.xml”的元素和子元素被解析成一系列字典項。

示例

import xml.etree.ElementTree as et
tree = et.ElementTree(file='employees.xml')
root = tree.getroot()
employees=[]
   children = list(root)
for child in children:
   employee={}
   pairs = list(child)
   for pair in pairs:
      employee[pair.tag]=pair.text
   employees.append(employee)
print (employees)

它將產生以下**輸出**:

[{'name': 'aaa', 'age': '21', 'sal': '5000'}, {'name': 'xyz', 'age':'22', 'sal': '6000'}]

修改 XML 檔案

我們將使用 Element 的 iter() 函式。它為給定標籤建立一個樹迭代器,當前元素作為根。迭代器按文件(深度優先)順序迭代此元素及其下面的所有元素。

讓我們為所有“marks”子元素構建迭代器,並將每個 sal 標籤的文字增加 100。

import xml.etree.ElementTree as et
tree = et.ElementTree(file='students.xml')
root = tree.getroot()
for x in root.iter('sal'):
   s=int (x.text)
   s=s+100
   x.text=str(s)
with open("employees.xml", "wb") as fh:
   tree.write(fh)

我們的“employees.xml”現在將相應地修改。我們還可以使用 set() 來更新某個鍵的值。

x.set(marks, str(mark))

Python - GUI 程式設計

Python 提供了各種開發圖形使用者介面 (GUI) 的選項。最重要的功能如下所示。

  • Tkinter − Tkinter 是 Python 對隨 Python 一起提供的 Tk GUI 工具包的介面。我們將在本章中介紹此選項。

  • wxPython − 這是一個用於 wxWidgets GUI 工具包的開源 Python 介面。您可以在此處找到有關 WxPython 的完整教程這裡

  • PyQt − 這也是一個流行的跨平臺 Qt GUI 庫的 Python 介面。TutorialsPoint 有一個關於 PyQt5 的非常好的教程這裡

  • PyGTK − PyGTK 是一組用 Python 和 C 編寫的 GTK + GUI 庫包裝器。完整的 PyGTK 教程可在這裡找到。

  • PySimpleGUI − PySimpleGui 是一個開源的跨平臺 Python GUI 庫。它旨在為基於 Python 的 Tkinter、PySide 和 WxPython 工具包建立桌面 GUI 提供統一的 API。有關 PySimpleGUI 教程的詳細資訊,請單擊這裡

  • Pygame − Pygame 是一個流行的 Python 庫,用於開發影片遊戲。它是一個免費的、開源的、跨平臺的 Simple DirectMedia Library (SDL) 包裝器。有關 Pygame 的全面教程,請訪問此連結。

  • Jython − Jython 是 Java 的 Python 移植版本,它使 Python 指令碼可以無縫訪問本地機器上的 Java 類庫http: //www.jython.org

還有許多其他可用的介面,您可以在網上找到它們。

Tkinter 程式設計

Tkinter 是 Python 的標準 GUI 庫。Python 與 Tkinter 結合使用,提供了一種快速簡便的建立 GUI 應用程式的方法。Tkinter 為 Tk GUI 工具包提供了一個強大的面向物件介面。

tkinter 包包含以下模組−

  • Tkinter − 主 Tkinter 模組。

  • tkinter.colorchooser − 用於讓使用者選擇顏色的對話方塊。

  • tkinter.commondialog − 此處列出的其他模組中定義的對話方塊的基類。

  • tkinter.filedialog − 常用對話方塊,允許使用者指定要開啟或儲存的檔案。

  • tkinter.font − 有助於處理字型的實用程式。

  • tkinter.messagebox − 訪問標準 Tk 對話方塊。

  • tkinter.scrolledtext − 帶有內建垂直捲軸的文字小部件。

  • tkinter.simpledialog − 基本對話方塊和便捷函式。

  • tkinter.ttk − Tk 8.5 中引入的主題小部件集,為主 tkinter 模組中的許多經典小部件提供了現代替代方案。

使用 Tkinter 建立 GUI 應用程式是一項簡單的任務。您只需執行以下步驟即可。

  • 匯入 Tkinter 模組。

  • 建立 GUI 應用程式主視窗。

  • 將上述一個或多個小部件新增到 GUI 應用程式。

  • 進入主事件迴圈以對使用者觸發的每個事件採取行動。

示例

# note that module name has changed from Tkinter in Python 2
# to tkinter in Python 3

import tkinter
top = tkinter.Tk()

# Code to add widgets will go here...
top.mainloop()

這將建立一個如下視窗−

Tkinter Programming

當程式變得更復雜時,使用面向物件程式設計方法可以使程式碼更有條理。

import tkinter as tk
class App(tk.Tk):
   def __init__(self):
      super().__init__()

app = App()
app.mainloop()

Tkinter 小部件

Tkinter 提供各種控制元件,例如按鈕、標籤和文字框,這些控制元件用於 GUI 應用程式。這些控制元件通常稱為小部件。

Tkinter 目前有 15 種小部件。我們在下表中介紹了這些小部件以及簡要說明−

序號 運算子 & 說明
1 按鈕

Button 小部件用於在應用程式中顯示按鈕。

2 畫布

Canvas 小部件用於在應用程式中繪製形狀,例如線條、橢圓、多邊形和矩形。

3 複選框

複選框部件用於以複選框的形式顯示多個選項。使用者可以同時選擇多個選項。

4 Entry(文字輸入框)

Entry部件用於顯示單行文字欄位,用於接收使用者的輸入值。

5 Frame(框架)

Frame部件用作容器部件,用於組織其他部件。

6 Label(標籤)

Label部件用於為其他部件提供單行標題。它也可以包含影像。

7 Listbox(列表框)

Listbox部件用於向用戶提供選項列表。

8 Menubutton(選單按鈕)

Menubutton部件用於在應用程式中顯示選單。

9 Menu(選單)

Menu部件用於向用戶提供各種命令。這些命令包含在Menubutton中。

10 Message(訊息框)

Message部件用於顯示多行文字欄位,用於接收使用者的輸入值。

11 Radiobutton(單選按鈕)

Radiobutton部件用於以單選按鈕的形式顯示多個選項。使用者一次只能選擇一個選項。

12 Scale(滑塊)

Scale部件用於提供一個滑塊部件。

13 Scrollbar(捲軸)

Scrollbar部件用於為各種部件(例如列表框)新增滾動功能。

14 Text(文字框)

Text部件用於顯示多行文字。

15 Toplevel(頂級視窗)

Toplevel部件用於提供一個單獨的視窗容器。

16 Spinbox(旋轉框)

Spinbox部件是標準Tkinter Entry部件的一個變體,可用於從固定數量的值中進行選擇。

17 PanedWindow(窗格視窗)

PanedWindow是一個容器部件,可以包含任意數量的窗格,這些窗格可以水平或垂直排列。

18 LabelFrame(標籤框架)

LabelFrame是一個簡單的容器部件。其主要目的是充當複雜窗口布局的間隔符或容器。

19 tkMessageBox(訊息框)

此模組用於在應用程式中顯示訊息框。

讓我們詳細研究這些部件。

標準屬性

讓我們看看如何指定一些常用屬性,例如大小、顏色和字型。

讓我們簡要地學習它們——

幾何管理

所有Tkinter部件都可以訪問特定的幾何管理方法,這些方法的目的是在父部件區域中組織部件。Tkinter公開了以下幾何管理器類:pack、grid和place。

  • pack()方法——這個幾何管理器在將部件放置到父部件之前,將部件組織成塊。

  • grid()方法——這個幾何管理器以表格結構的方式在父部件中組織部件。

  • place()方法——這個幾何管理器透過將部件放置在父部件中的特定位置來組織部件。

讓我們簡要地學習幾何管理方法——

SimpleDialog(簡單對話方塊)

tkinter包中的simpledialog模組包含一個對話方塊類和一些便捷函式,用於透過模態對話方塊接收使用者輸入。它包含一個標籤、一個輸入部件和兩個按鈕“確定”和“取消”。這些函式是——

  • askfloat(title, prompt, **kw)——接受浮點數。

  • askinteger(title, prompt, **kw)——接受整數輸入。

  • askstring(title, prompt, **kw)——接受使用者的文字輸入。

以上三個函式提供的對話方塊會提示使用者輸入所需型別的數值。如果按下“確定”,則返回輸入;如果按下“取消”,則返回None。

askinteger

from tkinter.simpledialog import askinteger
from tkinter import *
from tkinter import messagebox
top = Tk()

top.geometry("100x100")
def show():
   num = askinteger("Input", "Input an Integer")
   print(num)
   
B = Button(top, text ="Click", command = show)
B.place(x=50,y=50)

top.mainloop()

它將產生以下**輸出**:

SimpleDialog

askfloat

from tkinter.simpledialog import askfloat
from tkinter import *
top = Tk()

top.geometry("100x100")
def show():
   num = askfloat("Input", "Input a floating point number")
   print(num)
   
B = Button(top, text ="Click", command = show)
B.place(x=50,y=50)

top.mainloop()

它將產生以下**輸出**:

askfloat

askstring

from tkinter.simpledialog import askstring
from tkinter import *

top = Tk()

top.geometry("100x100")
def show():
   name = askstring("Input", "Enter you name")
   print(name)
   
B = Button(top, text ="Click", command = show)
B.place(x=50,y=50)

top.mainloop()

它將產生以下**輸出**:

askstring

FileDialog模組(檔案對話方塊)

Tkinter包中的filedialog模組包含一個FileDialog類。它還定義了方便使用者執行開啟檔案、儲存檔案和開啟目錄操作的便捷函式。

  • filedialog.asksaveasfilename()
  • filedialog.asksaveasfile()
  • filedialog.askopenfilename()
  • filedialog.askopenfile()
  • filedialog.askdirectory()
  • filedialog.askopenfilenames()
  • filedialog.askopenfiles()

askopenfile

此函式允許使用者從檔案系統中選擇所需的檔案。檔案對話方塊視窗具有“開啟”和“取消”按鈕。按下“確定”時返回檔名及其路徑,按下“取消”時返回None。

from tkinter.filedialog import askopenfile
from tkinter import *

top = Tk()

top.geometry("100x100")
def show():
   filename = askopenfile()
   print(filename)
   
B = Button(top, text ="Click", command = show)
B.place(x=50,y=50)

top.mainloop()

它將產生以下**輸出**:

askopenfile

ColorChooser(顏色選擇器)

tkinter包中包含的colorchooser模組具有允許使用者透過顏色對話方塊選擇所需顏色物件的特性。askcolor()函式顯示顏色對話方塊,其中包含預定義的顏色樣本以及透過設定RGB值來選擇自定義顏色的功能。該對話方塊返回所選顏色的RGB值元組及其十六進位制值。

from tkinter.colorchooser import askcolor
from tkinter import *

top = Tk()

top.geometry("100x100")
def show():
   color = askcolor()
   print(color)
   
B = Button(top, text ="Click", command = show)
B.place(x=50,y=50)

top.mainloop()

它將產生以下**輸出**:

ColorChooser
((0, 255, 0), '#00ff00')

ttk模組

ttk代表Tk主題部件。ttk模組從Tk 8.5開始引入。它提供了額外的優勢,包括在X11下進行抗鋸齒字型渲染和視窗透明度。它為Tkinter提供了主題和樣式支援。

ttk模組捆綁了18個部件,其中12個部件已經存在於Tkinter中。匯入ttk會用新的部件覆蓋這些部件,這些部件旨在在所有平臺上都具有更好、更現代的外觀。

ttk中的6個新部件是:Combobox、Separator、Sizegrip、Treeview、Notebook和ProgressBar。

要覆蓋基本的Tk部件,匯入應遵循Tk匯入——

from tkinter import *
from tkinter.ttk import *

原始的Tk部件將自動被tkinter.ttk部件替換。它們是Button、Checkbutton、Entry、Frame、Label、LabelFrame、Menubutton、PanedWindow、Radiobutton、Scale和Scrollbar。

新的部件在跨平臺方面提供了更好的外觀和感覺;但是,替換的部件並不完全相容。主要區別在於,諸如“fg”、“bg”以及其他與部件樣式相關的部件選項不再存在於Ttk部件中。而是使用ttk.Style類來獲得改進的樣式效果。

ttk模組中的新部件是——

  • Notebook(筆記本)——此部件管理一系列“選項卡”,您可以在這些選項卡之間切換,從而更改當前顯示的視窗。

  • ProgressBar(進度條)——此部件用於透過使用動畫來顯示進度或載入過程。

  • Separator(分隔符)——使用分隔線來分隔不同的部件。

  • Treeview(樹形檢視)——此部件用於以樹狀層次結構將專案組合在一起。每個專案都有一個文字標籤、一個可選影像和一個可選資料值列表。

  • Combobox(組合框)——用於建立下拉選項列表,使用者可以從中選擇一個選項。

  • Sizegrip(大小調整器)——在螢幕的右下角建立一個小的把手,可用於調整視窗大小。

Combobox部件(組合框)

Python ttk Combobox顯示下拉選項列表,並一次顯示一個選項。它是Entry部件的子類。因此,它繼承了Entry類的許多選項和方法。

語法

from tkinter import ttk

Combo = ttk.Combobox(master, values.......)

get()函式用於檢索Combobox的當前值。

示例

from tkinter import *
from tkinter import ttk

top = Tk()
top.geometry("200x150")

frame = Frame(top)
frame.pack()

langs = ["C", "C++", "Java",
   "Python", "PHP"]
   
Combo = ttk.Combobox(frame, values = langs)
Combo.set("Pick an Option")
Combo.pack(padx = 5, pady = 5)
top.mainloop()

它將產生以下**輸出**:

Combobox Widget

Progressbar(進度條)

ttk ProgressBar部件及其如何用於建立載入螢幕或顯示當前任務的進度。

語法

ttk.Progressbar(parent, orient, length, mode)

引數

  • Parent(父容器)——放置ProgressBar的容器,例如root或Tkinter框架。

  • Orient(方向)——定義ProgressBar的方向,可以是垂直或水平。

  • Length(長度)——透過接收整數數值來定義ProgressBar的寬度。

  • Mode(模式)——此引數有兩個選項:確定和不確定。

示例

下面給出的程式碼建立了一個進度條,其中包含三個按鈕,這些按鈕與三個不同的函式連結。

第一個函式將進度條中的“值”或“進度”增加20。這是透過step()函式完成的,該函式接收一個整數數值來更改進度量。(預設為1.0)

第二個函式將進度條中的“值”或“進度”減少20。

第三個函式打印出進度條中的當前進度級別。

import tkinter as tk
from tkinter import ttk

root = tk.Tk()
frame= ttk.Frame(root)
def increment():
   progressBar.step(20)
   
def decrement():
   progressBar.step(-20)
   
def display():
   print(progressBar["value"])

progressBar= ttk.Progressbar(frame, mode='determinate')
progressBar.pack(padx = 10, pady = 10)

button= ttk.Button(frame, text= "Increase", command= increment)
button.pack(padx = 10, pady = 10, side = tk.LEFT)

button= ttk.Button(frame, text= "Decrease", command= decrement)
button.pack(padx = 10, pady = 10, side = tk.LEFT)
button= ttk.Button(frame, text= "Display", command= display)
button.pack(padx = 10, pady = 10, side = tk.LEFT)

frame.pack(padx = 5, pady = 5)
root.mainloop()

它將產生以下**輸出**:

Progressbar

Notebook(筆記本)

Tkinter ttk模組有一個名為Notebook的有用新部件。它是一組容器(例如框架),這些容器內部包含許多部件作為子部件。

每個“選項卡”或“視窗”都有一個與其關聯的選項卡ID,用於確定要切換到哪個選項卡。

您可以像在常規文字編輯器中一樣在這些容器之間切換。

語法

notebook = ttk.Notebook(master, *options)

示例

在這個示例中,我們將以兩種不同的方式將3個視窗新增到我們的Notebook部件中。第一種方法涉及add()函式,該函式只是將一個新選項卡附加到末尾。另一種方法是insert()函式,它可以用來將選項卡新增到特定位置。

add()函式需要一個必需引數,即要新增的容器部件,其餘引數是可選引數,例如text(顯示為選項卡標題的文字)、image和compound。

insert()函式需要一個tab_id,它定義了應該插入它的位置。tab_id可以是索引值,也可以是字串文字,例如“end”,它會將其附加到末尾。

import tkinter as tk
from tkinter import ttk

root = tk.Tk()
nb = ttk.Notebook(root)

# Frame 1 and 2
frame1 = ttk.Frame(nb)
frame2 = ttk.Frame(nb)

label1 = ttk.Label(frame1, text = "This is Window One")
label1.pack(pady = 50, padx = 20)
label2 = ttk.Label(frame2, text = "This is Window Two")
label2.pack(pady = 50, padx = 20)

frame1.pack(fill= tk.BOTH, expand=True)
frame2.pack(fill= tk.BOTH, expand=True)
nb.add(frame1, text = "Window 1")
nb.add(frame2, text = "Window 2")

frame3 = ttk.Frame(nb)
label3 = ttk.Label(frame3, text = "This is Window Three")
label3.pack(pady = 50, padx = 20)
frame3.pack(fill= tk.BOTH, expand=True)
nb.insert("end", frame3, text = "Window 3")
nb.pack(padx = 5, pady = 5, expand = True)

root.mainloop()

它將產生以下**輸出**:

Notebook

Treeview(樹形檢視)

Treeview部件用於以表格或層次結構的方式顯示專案。它支援建立專案行和列的功能,並且還允許專案具有子專案,從而形成層次結構。

語法

tree = ttk.Treeview(container, **options)

選項

序號 選項&描述
1

columns

列名列表

2

displaycolumns

列識別符號列表(符號或整數索引),指定顯示哪些資料列以及它們的顯示順序,或者字串“#all”。

3

height

可見的行數。

4

padding

指定部件的內部填充。可以是整數或4個值的列表。

5

selectmode

“extended”、“browse”或“none”之一。如果設定為“extended”(預設值),則可以選擇多個專案。如果設定為“browse”,則一次只能選擇一個專案。如果設定為“none”,則使用者無法更改選擇。

6

show

包含零個或多個以下值的列表,指定要顯示的樹的哪些元素。預設為“tree headings”,即顯示所有元素。

示例

在這個示例中,我們將建立一個簡單的Treeview ttk部件,並將一些資料填充到其中。我們已經將一些資料儲存在一個列表中,這些資料將在我們的read_data()函式中讀取並新增到Treeview部件中。

我們首先需要定義一個列名列表/元組。我們省略了列“Name”,因為已經存在一個名稱為空的(預設)列。

然後,我們將該列表/元組分配給Treeview中的columns選項,然後定義“headings”,其中列是實際的列,而標題只是顯示部件時出現的列標題。我們為每個列命名。“#0”是預設列的名稱。

tree.insert()函式具有以下引數——

  • Parent(父項)——如果沒有父項,則保留為空字串。

  • Position(位置)——我們想要新增新專案的位置。要追加,請使用tk.END

  • Iid(專案ID)——用於稍後跟蹤相關專案的專案ID。

  • Text(文字)——我們將為此分配列表中的第一個值(名稱)。

我們將傳遞從列表中獲得的其他兩個值。

完整程式碼

import tkinter as tk
import tkinter.ttk as ttk
from tkinter import simpledialog

root = tk.Tk()
data = [
   ["Bobby",26,20000],
   ["Harrish",31,23000],
   ["Jaya",18,19000],
   ["Mark",22, 20500],
]
index=0
def read_data():
   for index, line in enumerate(data):
      tree.insert('', tk.END, iid = index,
         text = line[0], values = line[1:])
columns = ("age", "salary")

tree= ttk.Treeview(root, columns=columns ,height = 20)
tree.pack(padx = 5, pady = 5)

tree.heading('#0', text='Name')
tree.heading('age', text='Age')
tree.heading('salary', text='Salary')

read_data()
root.mainloop()

它將產生以下**輸出**:

Treeview

Sizegrip(大小調整器)

Sizegrip部件基本上是一個小的箭頭狀把手,通常放置在螢幕的右下角。在螢幕上拖動Sizegrip也會調整其附加到的容器的大小。

語法

sizegrip = ttk.Sizegrip(parent, **options)

示例

import tkinter as tk
import tkinter.ttk as ttk

root = tk.Tk()
root.geometry("100x100")

frame = ttk.Frame(root)
label = ttk.Label(root, text = "Hello World")
label.pack(padx = 5, pady = 5)
sizegrip = ttk.Sizegrip(frame)
sizegrip.pack(expand = True, fill = tk.BOTH, anchor = tk.SE)
frame.pack(padx = 10, pady = 10, expand = True, fill = tk.BOTH)

root.mainloop()

它將產生以下**輸出**:

Sizegrip

Separator(分隔符)

ttk Separator部件是一個非常簡單的部件,它只有一個用途,那就是透過在部件之間繪製一條線來幫助將部件“分隔”成組/分割槽。我們可以將這條線(分隔符)的方向更改為水平或垂直,並更改其長度/高度。

語法

separator = ttk.Separator(parent, **options)

“orient” 屬性可以是 tk.VERTICAL 或 tk.HORIZONTAL,分別表示垂直和水平分隔符。

示例

這裡我們建立了兩個 Label 元件,然後在它們之間建立了一個水平分隔符。

import tkinter as tk
import tkinter.ttk as ttk

root = tk.Tk()
root.geometry("200x150")

frame = ttk.Frame(root)

label = ttk.Label(frame, text = "Hello World")
label.pack(padx = 5)

separator = ttk.Separator(frame,orient= tk.HORIZONTAL)
separator.pack(expand = True, fill = tk.X)

label = ttk.Label(frame, text = "Welcome To TutorialsPoint")
label.pack(padx = 5)

frame.pack(padx = 10, pady = 50, expand = True, fill = tk.BOTH)

root.mainloop()

它將產生以下**輸出**:

Separator

Python - 命令列引數

要執行 Python 程式,我們在作業系統的命令提示符終端執行以下命令。例如,在 Windows 中,在 Windows 命令提示符終端輸入以下命令。

command line

命令提示符 C:\>(或 Linux 作業系統中的 $)前面的行稱為命令列。

如果程式需要接受使用者的輸入,則使用 Python 的 input() 函式。當從命令列執行程式時,使用者輸入將從命令終端接受。

示例

name = input("Enter your name: ")
print ("Hello {}. How are you?".format(name))

程式從命令提示符終端執行,如下所示:

command prompt

很多時候,您可能需要將程式要使用的資料放在命令列本身,並在程式內部使用它。在命令列中提供資料的示例可以是 Windows 或 Linux 中的任何 DOS 命令。

在 Windows 中,您可以使用以下 DOS 命令將檔案 hello.py 重新命名為 hi.py。

C:\Python311>ren hello.py hi.py

在 Linux 中,您可以使用 mv 命令:

$ mv hello.py hi.py

這裡 ren 或 mv 是需要舊檔名和新檔名的命令。由於它們與命令一起放在一行中,因此它們被稱為命令列引數。

您可以從命令列向 Python 程式傳遞值。Python 將引數收集到列表物件中。Python 的 sys 模組透過 sys.argv 變數提供對任何命令列引數的訪問。sys.argv 是命令列引數列表,sys.argv[0] 是程式,即指令碼名稱。

hello.py 指令碼使用 input() 函式在指令碼執行後接受使用者輸入。讓我們將其更改為從命令列接受輸入。

import sys
print ('argument list', sys.argv)
name = sys.argv[1]
print ("Hello {}. How are you?".format(name))

從命令列執行程式,如下圖所示:

command-line

輸出如下所示:

C:\Python311>python hello.py Rajan
argument list ['hello.py', 'Rajan']
Hello Rajan. How are you?

命令列引數始終儲存在字串變數中。要將它們用作數字,可以使用型別轉換函式適當地轉換它們。

在下面的示例中,兩個數字作為命令列引數輸入。在程式內部,我們使用 int() 函式將它們解析為整型變數。

import sys
print ('argument list', sys.argv)
first = int(sys.argv[1])
second = int(sys.argv[2])
print ("sum = {}".format(first+second))

它將產生以下**輸出**:

C:\Python311>python hello.py 10 20
argument list ['hello.py', '10', '20']
sum = 30

Python 的標準庫包含幾個有用的模組來解析命令列引數和選項:

  • getopt - C 風格的命令列選項解析器。

  • argparse - 用於命令列選項、引數和子命令的解析器。

getopt 模組

Python 提供了一個 getopt 模組,可幫助您解析命令列選項和引數。此模組提供兩個函式和一個異常來啟用命令列引數解析。

getopt.getopt 方法

此方法解析命令列選項和引數列表。以下是此方法的簡單語法:

getopt.getopt(args, options, [long_options])

以下是引數的詳細資訊−

  • args - 這是要解析的引數列表。

  • options - 這是指令碼要識別的選項字母字串,需要引數的選項後面應跟一個冒號 (:)。

  • long_options - 這是一個可選引數,如果指定,必須是包含長選項名稱的字串列表,這些選項應受支援。需要引數的長選項後面應跟一個等號 (=)。要僅接受長選項,options 應為空字串。

此方法返回一個包含兩個元素的值:第一個是 (選項,值) 對的列表,第二個是剝離選項列表後剩餘的程式引數列表。

返回的每個選項值對都將選項作為其第一個元素,短選項 (例如,'-x') 字首為一個連字元,長選項 (例如,'--long-option') 字首為兩個連字元。

異常 getopt.GetoptError

當在引數列表中找到無法識別的選項,或者當需要引數的選項未給出任何引數時,將引發此異常。

異常的引數是指示錯誤原因的字串。屬性 msg 和 opt 給出錯誤訊息和相關選項。

示例

假設我們想透過命令列傳遞兩個檔名,並且我們還想提供一個選項來檢查指令碼的使用情況。指令碼的使用情況如下:

usage: test.py -i <inputfile> -o <outputfile>

以下是測試指令碼 test.py:

import sys, getopt
def main(argv):
   inputfile = ''
   outputfile = ''
   try:
      opts, args = getopt.getopt(argv,"hi:o:",["ifile=","ofile="])
   except getopt.GetoptError:
      print ('test.py -i <inputfile> -o <outputfile>')
      sys.exit(2)
   for opt, arg in opts:
      if opt == '-h':
         print ('test.py -i <inputfile> -o <outputfile>')
         sys.exit()
      elif opt in ("-i", "--ifile"):
         inputfile = arg
      elif opt in ("-o", "--ofile"):
         outputfile = arg
   print ('Input file is "', inputfile)
   print ('Output file is "', outputfile)
if __name__ == "__main__":
   main(sys.argv[1:])

現在,按如下方式執行上述指令碼:

$ test.py -h
usage: test.py -i <inputfile> -o <outputfile>
$ test.py -i BMP -o
usage: test.py -i <inputfile> -o <outputfile>
$ test.py -i inputfile -o outputfile
Input file is " inputfile
Output file is " outputfile

argparse 模組

argparse 模組提供了編寫非常易於使用的命令列介面的工具。它處理如何解析收集在 sys.argv 列表中的引數,自動生成幫助資訊,並在給出無效選項時發出錯誤訊息。

設計命令列介面的第一步是設定解析器物件。這是透過 argparse 模組中的 ArgumentParser() 函式完成的。該函式可以將解釋性字串作為 description 引數。

首先,我們的指令碼將在沒有任何引數的情況下從命令列執行。仍然使用解析器物件的 parse_args() 方法,因為它沒有給出任何引數,所以什麼也不做。

import argparse
parser=argparse.ArgumentParser(description="sample argument parser")
args=parser.parse_args()

執行上述指令碼時:

C:\Python311>python parser1.py
C:\Python311>python parser1.py -h
usage: parser1.py [-h]
sample argument parser
options:
   -h, --help show this help message and exit

第二個命令列用法給出 -help 選項,它會生成如下所示的幫助訊息。-help 引數預設可用。

現在讓我們定義一個引數,該引數對於指令碼執行是必需的,如果沒有給出,指令碼應該丟擲錯誤。這裡我們透過 add_argument() 方法定義引數 'user'。

import argparse
parser=argparse.ArgumentParser(description="sample argument parser")
parser.add_argument("user")
args=parser.parse_args()
if args.user=="Admin":
   print ("Hello Admin")
else:
   print ("Hello Guest")

此指令碼的幫助資訊現在以 'user' 的形式顯示一個位置引數。程式檢查其值是否為 'Admin',並列印相應的郵件。

C:\Python311>python parser2.py --help
usage: parser2.py [-h] user
sample argument parser
positional arguments:
   user
options:
   -h, --help show this help message and exit

使用以下命令:

C:\Python311>python parser2.py Admin
Hello Admin

但以下用法顯示 Hello Guest 訊息。

C:\Python311>python parser2.py Rajan
Hello Guest

add_argument() 方法

我們可以在 add_argument() 方法中為引數分配預設值。

import argparse
parser=argparse.ArgumentParser(description="sample argument parser")
parser.add_argument("user", nargs='?',default="Admin")
args=parser.parse_args()
if args.user=="Admin":
   print ("Hello Admin")
else:
   print ("Hello Guest")

這裡 nargs 是應該使用的命令列引數的數量。'?'。如果可能,將從命令列使用一個引數,並作為一個專案生成。如果沒有命令列引數,則將生成來自 default 的值。

預設情況下,所有引數都將被視為字串。要明確提及引數的型別,請在 add_argument() 方法中使用 type 引數。所有 Python 資料型別都是 type 的有效值。

import argparse
parser=argparse.ArgumentParser(description="add numbers")
parser.add_argument("first", type=int)
parser.add_argument("second", type=int)
args=parser.parse_args()
x=args.first
y=args.second
z=x+y
print ('addition of {} and {} = {}'.format(x,y,z))

它將產生以下**輸出**:

C:\Python311>python parser3.py 10 20
addition of 10 and 20 = 30

在上面的示例中,引數是必需的。要新增可選引數,請在其名稱前加上雙破折號 --。在以下情況下,surname 引數是可選的,因為它以雙破折號 (--surname) 為字首。

import argparse
parser=argparse.ArgumentParser()
parser.add_argument("name")
parser.add_argument("--surname")
args=parser.parse_args()
print ("My name is ", args.name, end=' ')
if args.surname:
   print (args.surname)

以單破折號為字首的一個字母引數名稱充當短名稱選項。

C:\Python311>python parser3.py Anup
My name is Anup
C:\Python311>python parser3.py Anup --surname Gupta
My name is Anup Gupta

如果需要引數的值僅來自定義列表,則將其定義為 choices 引數。

import argparse
parser=argparse.ArgumentParser()
parser.add_argument("sub", choices=['Physics', 'Maths', 'Biology'])
args=parser.parse_args()
print ("My subject is ", args.sub)

請注意,如果引數的值不在列表中,則會顯示無效的選擇錯誤。

C:\Python311>python parser3.py Physics
My subject is Physics
C:\Python311>python parser3.py History
usage: parser3.py [-h] {Physics,Maths,Biology}
parser3.py: error: argument sub: invalid choice: 'History' (choose from
'Physics', 'Maths', 'Biology')

Python - 文件字串

在 Python 中,文件字串是一個字串字面量,用作不同 Python 物件(例如函式、模組、類及其方法和包)的文件。它是所有這些構造定義中的第一行,併成為 __doc__ 屬性的值。

函式的文件字串

def addition(x, y):
   '''This function returns the sum of two numeric arguments'''
   return x+y
print ("Docstring of addition function:", addition.__doc__)

它將產生以下**輸出**:

Docstring of addition function: This function returns the sum of two numeric arguments

文件字串可以用單引號、雙引號或三引號編寫。但是,大多數情況下您可能需要描述性文字作為文件,因此使用三引號是可取的。

所有內建模組和函式都具有 __doc__ 屬性,該屬性返回其文件字串。

math 模組的文件字串

import math

print ("Docstring of math module:", math.__doc__)

它將產生以下**輸出**:

Docstring of math module: This module provides access to the mathematical functions
 defined by the C standard.

內建函式的文件字串

以下程式碼顯示 random 模組中 abs() 函式和 randint() 函式的文件字串。

print ("Docstring of built-in abs() function:", abs.__doc__)
import random

print ("Docstring of random.randint() function:",
random.randint.__doc__)

它將產生以下輸出:

Docstring of built-in abs() function: Return the absolute value of the
argument.

Docstring of random.randint() function: Return random integer in range
[a, b], including both end points.

內建類的文件字串

內建類的文件字串通常更具解釋性,因此文字包含多行。下面,我們檢查內建 dict 類的文件字串

print ("Docstring of built-in dict class:", dict.__doc__)

它將產生以下**輸出**:

Docstring of built-in dict class: dict() -> new empty dictionary
dict(mapping) -> new dictionary initialized from a mapping object's
   (key, value) pairs
dict(iterable) -> new dictionary initialized as if via:
   d = {}
   for k, v in iterable:
      d[k] = v
dict(**kwargs) -> new dictionary initialized with the name=value pairs in the keyword argument list. For example: dict(one=1, two=2)

Template 類的文件字串

Template 類在 Python 標準庫的 string 模組中定義。其文件字串如下:

from string import Template

print ("Docstring of Template class:", Template.__doc__)

它將產生以下**輸出**:

Docstring of Template class: A string class for supporting $- substitutions.

幫助系統中的文件字串

文件字串也由 Python 的內建幫助服務使用。例如,檢查 Python 直譯器中 abs() 函式的幫助:

>>> help (abs)
Help on built-in function abs in module builtins:
abs(x, /)
   Return the absolute value of the argument.

同樣,在直譯器終端中定義一個函式並執行 help 命令。

>>> def addition(x,y):
... '''addtion(x,y)
... Returns the sum of x and y
... '''
... return x+y
...
>>> help (addition)
Help on function addition in module __main__:
addition(x, y)
   addtion(x,y)
   Returns the sum of x and y

文件字串還被 IDE 用於在編輯程式碼時提供有用的型別提示資訊。

docstring

文件字串作為註釋

出現在這些物件(函式、方法、類、模組或包)之外的字串字面量會被直譯器忽略,因此它們類似於註釋(以 # 符號開頭)。

# This is a comment
print ("Hello World")
'''This is also a comment'''
print ("How are you?")

Python - JSON

JSON 代表 JavaScript 物件表示法。它是一種輕量級的資料交換格式。它類似於 pickle。但是,pickle 序列化是 Python 特定的,而 JSON 格式由多種語言實現。Python 標準庫中的 json 模組實現了類似於 pickle 和 marshal 模組的物件序列化功能。

就像 pickle 模組一樣,json 模組也提供 dumps() 和 loads() 函式,用於將 Python 物件序列化為 JSON 編碼的字串,以及 dump() 和 load() 函式,用於將序列化後的 Python 物件寫入/讀取到檔案。

  • dumps() - 此函式將物件轉換為 JSON 格式。

  • loads() - 此函式將 JSON 字串轉換回 Python 物件。

以下示例演示了這些函式的基本用法:

示例1

import json

data=['Rakesh',{'marks':(50,60,70)}]
s=json.dumps(data)
print (s, type(s))

data = json.loads(s)
print (data, type(data))

它將產生以下**輸出**:

["Rakesh", {"marks": [50, 60, 70]}] <class 'str'>
['Rakesh', {'marks': [50, 60, 70]}] <class 'list'>

dumps() 函式可以採用可選的 sort_keys 引數。預設情況下為 False。如果設定為 True,則字典鍵將按排序順序出現在 JSON 字串中。

data=['Rakesh',{'marks':(50,60,70)}]
s=json.dumps(data, sort_keys=True)

示例2

dumps() 函式還有一個可選引數,稱為 indent,它採用數字作為值。它決定 JSON 字串格式化表示的每個段的長度,類似於 pprint 輸出。

import json
data=['Rakesh',{'marks':(50,60,70)}]
s=json.dumps(data, indent = 2)
print (s) 

它將產生以下輸出:

[
  "Rakesh",
  {
    "marks": [
      50,
      60,
      70
    ]
  }
]

json 模組還具有與上述函式對應的面向物件 API。模組中定義了兩個類:JSONEncoder 和 JSONDecoder。

JSONEncoder 類

此類的物件是 Python 資料結構的編碼器。每個 Python 資料型別都將轉換為相應的 JSON 型別,如下表所示:

Python JSON
Dict object
list, tuple array
Str string
int, float, int- & float-derived Enums number
True true
False false
None null

JSONEncoder 類由 JSONEncoder() 建構函式例項化。編碼器類中定義了以下重要方法:

  • encode() - 將 Python 物件序列化為 JSON 格式。

  • iterencode() - 編碼物件並返回一個迭代器,生成物件中每個專案的編碼形式。

  • indent - 確定編碼字串的縮排級別。

  • sort_keys - 為 true 或 false,使鍵按排序順序出現或不出現。

  • check_circular - 如果為 True,則檢查容器型別物件中的迴圈引用。

以下示例編碼 Python 列表物件。

示例

import json

data=['Rakesh',{'marks':(50,60,70)}]
e=json.JSONEncoder()

使用 iterencode() 方法,編碼字串的每個部分如下所示:

import json
data=['Rakesh',{'marks':(50,60,70)}]
e=json.JSONEncoder()
for obj in e.iterencode(data):
   print (obj)

它將產生以下輸出:

["Rakesh"
, 
{
"marks"
: 
[50
, 60
, 70
]
}
]

JSONDEcoder 類

此類的物件有助於將 json 字串解碼回 Python 資料結構。此類中的主要方法是 decode()。以下示例程式碼從前面步驟中編碼的字串中檢索 Python 列表物件。

示例

import json
data=['Rakesh',{'marks':(50,60,70)}]
e=json.JSONEncoder()
s = e.encode(data)
d=json.JSONDecoder()
obj = d.decode(s)
print (obj, type(obj))

它將產生以下**輸出**:

['Rakesh', {'marks': [50, 60, 70]}] <class 'list'>

JSON 與檔案/流

json 模組定義了 load() 和 dump() 函式,用於將 JSON 資料寫入檔案類物件(可能是磁碟檔案或位元組流)並從中讀取資料。

dump() 函式

此函式將 Python 物件資料編碼為 JSON 格式,並將其寫入檔案。該檔案必須具有寫入許可權。

示例

import json
data=['Rakesh', {'marks': (50, 60, 70)}]
fp=open('json.txt','w')
json.dump(data,fp)
fp.close()

此程式碼將在當前目錄中建立 'json.txt' 檔案。其內容如下所示:

["Rakesh", {"marks": [50, 60, 70]}]

load() 函式

此函式從檔案中載入 JSON 資料,並從中構建 Python 物件。該檔案必須以讀取許可權開啟。

示例

import json
fp=open('json.txt','r')
ret=json.load(fp)
print (ret) 

Python - 傳送郵件

在網際網路上處理和傳遞電子郵件的應用程式稱為“郵件伺服器”。簡單郵件傳輸協議 (SMTP) 是一種協議,用於處理傳送電子郵件和郵件伺服器之間的電子郵件路由。它是電子郵件傳輸的網際網路標準。

Python 提供 smtplib 模組,該模組定義了一個 SMTP 客戶端會話物件,可用於將郵件傳送到任何具有 SMTP 或 ESMTP 監聽守護程式的網際網路計算機。

smtplib.SMTP() 函式

要傳送電子郵件,需要使用以下函式獲取 SMTP 類的物件:

import smtplib

smtpObj = smtplib.SMTP( [host [, port [, local_hostname]]] )

以下是引數的詳細資訊−

  • host − 這是執行 SMTP 伺服器的主機。您可以指定主機的 IP 地址或域名,例如 tutorialspoint.com。這是一個可選引數。

  • port − 如果您提供了 host 引數,則需要指定 SMTP 伺服器正在偵聽的埠。通常此埠為 25。

  • local_hostname − 如果您的 SMTP 伺服器正在您的本地計算機上執行,則可以只指定 localhost 作為選項。

SMTP 物件具有以下方法:

  • connect(host, port, source_address) − 此方法建立與給定埠上的主機的連線。

  • login(user, password) − 登入需要身份驗證的 SMTP 伺服器。

  • quit() − 終止 SMTP 會話。

  • data(msg) − 將訊息資料傳送到伺服器。

  • docmd(cmd, args) − 傳送命令並返回其響應程式碼。

  • ehlo(name) − 用於標識自身的 hostname。

  • starttls() − 將與 SMTP 伺服器的連線置於 TLS 模式。

  • getreply() − 獲取伺服器響應程式碼組成的伺服器回覆。

  • putcmd(cmd, args) − 向伺服器傳送命令。

  • send_message(msg, from_addr, to_addrs) − 將訊息轉換為位元組字串並將其傳遞給 sendmail。

smtpd 模組

Python 預裝的 smtpd 模組具有本地 SMTP 除錯伺服器。您可以透過啟動它來測試電子郵件功能。它不會實際將電子郵件傳送到指定的地址,而是將其丟棄並將內容列印到控制檯。執行本地除錯伺服器意味著無需處理訊息加密或使用憑據登入到電子郵件伺服器。

您可以在命令提示符中鍵入以下內容來啟動本地 SMTP 除錯伺服器:

python -m smtpd -c DebuggingServer -n localhost:1025

示例

以下程式使用 smtplib 功能傳送測試電子郵件。

import smtplib

def prompt(prompt):
   return input(prompt).strip()
   
fromaddr = prompt("From: ")
toaddrs = prompt("To: ").split()
print("Enter message, end with ^D (Unix) or ^Z (Windows):")

# Add the From: and To: headers at the start!
msg = ("From: %s\r\nTo: %s\r\n\r\n"
   % (fromaddr, ", ".join(toaddrs)))
while True:
   try:
      line = input()
   except EOFError:
      break
   if not line:
      break
   msg = msg + line
   
print("Message length is", len(msg))
server = smtplib.SMTP('localhost', 1025)
server.set_debuglevel(1)
server.sendmail(fromaddr, toaddrs, msg)
server.quit()

基本上,我們使用 sendmail() 方法,指定三個引數:

  • 發件人 − 包含發件人地址的字串。

  • 收件人 − 字串列表,每個收件人一個。

  • 郵件內容 − 根據各種 RFC 中指定的格式編寫的字串訊息。

我們已經啟動了 SMTP 除錯伺服器。執行此程式。系統會提示使用者輸入發件人 ID、收件人和郵件內容。

python example.py
From: abc@xyz.com
To: xyz@abc.com
Enter message, end with ^D (Unix) or ^Z (Windows):
Hello World
^Z

控制檯會顯示以下日誌:

From: abc@xyz.com
reply: retcode (250); Msg: b'OK'
send: 'rcpt TO:<xyz@abc.com>\r\n'
reply: b'250 OK\r\n'
reply: retcode (250); Msg: b'OK'
send: 'data\r\n'
reply: b'354 End data with <CR><LF>.<CR><LF>\r\n'
reply: retcode (354); Msg: b'End data with <CR><LF>.<CR><LF>'
data: (354, b'End data with <CR><LF>.<CR><LF>')
send: b'From: abc@xyz.com\r\nTo: xyz@abc.com\r\n\r\nHello
World\r\n.\r\n'
reply: b'250 OK\r\n'
reply: retcode (250); Msg: b'OK'
data: (250, b'OK')
send: 'quit\r\n'
reply: b'221 Bye\r\n'
reply: retcode (221); Msg: b'Bye'

執行 SMTPD 伺服器的終端顯示以下 輸出

---------- MESSAGE FOLLOWS ----------
b'From: abc@xyz.com'
b'To: xyz@abc.com'
b'X-Peer: ::1'
b''
b'Hello World'
------------ END MESSAGE ------------

使用 gmail SMTP

讓我們看一下下面的指令碼,該指令碼使用 Google 的 smtp 郵件伺服器傳送電子郵件。

首先,使用 gmail 的 smtp 伺服器和 527 埠設定 SMTP 物件。然後,SMTP 物件透過呼叫 ehlo() 命令來標識自身。我們還將傳輸層安全啟用到傳出的郵件訊息中。

接下來,透過將憑據作為引數傳遞給它來呼叫 login() 命令。最後,透過附加預定格式的標頭來組裝郵件訊息,並使用 sendmail() 方法傳送。之後關閉 SMTP 物件。

import smtplib
content="Hello World"
mail=smtplib.SMTP('smtp.gmail.com', 587)
mail.ehlo()
mail.starttls()
sender='mvl@gmail.com'
recipient='tester@gmail.com'
mail.login('mvl@gmail.com','******')
header='To:'+receipient+'\n'+'From:' \
+sender+'\n'+'subject:testmail\n'
content=header+content
mail.sendmail(sender, recipient, content)
mail.close()

在執行上述指令碼之前,必須將發件人的 gmail 帳戶配置為允許“安全性較低的應用”。訪問以下連結。

https://myaccount.google.com/lesssecureapps 將顯示的切換按鈕設定為 ON。

toggle button

如果一切順利,請執行上述指令碼。郵件應傳送到收件人的收件箱。

Python - 擴充套件

您可以將使用任何編譯語言(如 C、C++ 或 Java)編寫的任何程式碼整合或匯入到另一個 Python 指令碼中。此程式碼被認為是“擴充套件”。

Python 擴充套件模組只不過是一個普通的 C 庫。在 Unix 機器上,這些庫通常以 .so(共享物件)結尾。在 Windows 機器上,您通常會看到 .dll(動態連結庫)。

編寫擴充套件的先決條件

要開始編寫擴充套件,您將需要 Python 標頭檔案。

  • 在 Unix 機器上,這通常需要安裝特定於開發人員的軟體包。

  • Windows 使用者在使用二進位制 Python 安裝程式時,會將這些標頭檔案作為軟體包的一部分獲得。

此外,假設您精通 C 或 C++,才能使用 C 程式設計編寫任何 Python 擴充套件。

首先了解 Python 擴充套件

要首次瞭解 Python 擴充套件模組,需要將程式碼分成四個部分:

  • 標頭檔案 Python.h

  • 您要公開為模組介面的 C 函式。

  • 一個表,將您的函式名稱(Python 開發人員看到的)對映到擴充套件模組內的 C 函式。

  • 一個初始化函式。

標頭檔案 Python.h

您需要在 C 原始檔中包含 Python.h 標頭檔案,這使您可以訪問用於將模組掛接到直譯器的內部 Python API。

確保在任何其他可能需要的標頭檔案之前包含 Python.h。您需要在要從 Python 呼叫的函式之後遵循包含項。

C 函式

C 函式實現的簽名始終採用以下三種形式之一:

static PyObject *MyFunction(PyObject *self, PyObject *args);
static PyObject *MyFunctionWithKeywords(PyObject *self,
   PyObject *args,
   PyObject *kw);
static PyObject *MyFunctionWithNoArgs(PyObject *self);

前面每個宣告都返回一個 Python 物件。Python 中沒有像 C 中那樣的 void 函式。如果您不希望函式返回值,則返回 Python 的 None 值的 C 等效值。Python 標頭檔案定義了一個宏 Py_RETURN_NONE,它可以為我們做到這一點。

您的 C 函式名稱可以是任何您喜歡的名稱,因為它們永遠不會在擴充套件模組之外可見。它們被定義為 static 函式。

您的 C 函式通常透過組合 Python 模組和函式名稱來命名,如下所示:

static PyObject *module_func(PyObject *self, PyObject *args) {
   /* Do your stuff here. */
   Py_RETURN_NONE;
}

這是一個名為 module 模組內的 func 的 Python 函式。您將把 C 函式的指標放入模組的方法表中,該表通常位於原始碼的下一部分。

方法對映表

此方法表是一個簡單的 PyMethodDef 結構陣列。該結構看起來像這樣:

struct PyMethodDef {
   char *ml_name;
   PyCFunction ml_meth;
   int ml_flags;
   char *ml_doc;
};

以下是此結構成員的描述:

  • ml_name − 這是 Python 直譯器在 Python 程式中使用時呈現的函式名稱。

  • ml_meth − 這是具有上一節中描述的任何一個簽名的函式的地址。

  • ml_flags − 這告訴直譯器 ml_meth 使用哪三個簽名。

    • 此標誌通常值為 METH_VARARGS。

    • 如果要允許關鍵字引數進入您的函式,則此標誌可以與 METH_KEYWORDS 進行按位 OR 運算。

    • 它也可以具有 METH_NOARGS 值,這表示您不想接受任何引數。

  • mml_doc − 這是函式的文件字串,如果您不想編寫文件字串,則可以為 NULL。

此表需要以哨兵結束,該哨兵為相應的成員包含 NULL 和 0 值。

示例

對於上述定義的函式,我們有以下方法對映表:

static PyMethodDef module_methods[] = {
   { "func", (PyCFunction)module_func, METH_NOARGS, NULL },
   { NULL, NULL, 0, NULL }
};

初始化函式

擴充套件模組的最後一部分是初始化函式。載入模組時,Python 直譯器會呼叫此函式。函式必須命名為 initModule,其中 Module 是模組的名稱。

初始化函式需要從您將要構建的庫中匯出。Python 標頭檔案定義 PyMODINIT_FUNC 以包含適當的咒語,以便在編譯的特定環境中發生這種情況。您所要做的就是在定義函式時使用它。

您的 C 初始化函式通常具有以下總體結構:

PyMODINIT_FUNC initModule() {
   Py_InitModule3(func, module_methods, "docstring...");
}

以下是 Py_InitModule3 函式的描述:

  • func − 這是要匯出的函式。

  • module_methods − 這是上面定義的對映表名稱。

  • docstring − 這是您要在擴充套件中提供的註釋。

將所有這些放在一起,看起來像這樣:

#include <Python.h>
static PyObject *module_func(PyObject *self, PyObject *args) {
   /* Do your stuff here. */
   Py_RETURN_NONE;
}
static PyMethodDef module_methods[] = {
   { "func", (PyCFunction)module_func, METH_NOARGS, NULL },
   { NULL, NULL, 0, NULL }
};
PyMODINIT_FUNC initModule() {
   Py_InitModule3(func, module_methods, "docstring...");
}

示例

一個使用上述所有概念的簡單示例:

#include <Python.h>
static PyObject* helloworld(PyObject* self)
{
   return Py_BuildValue("s", "Hello, Python extensions!!");
}
static char helloworld_docs[] =
   "helloworld( ): Any message you want to put here!!\n";
static PyMethodDef helloworld_funcs[] = {
   {"helloworld", (PyCFunction)helloworld,
   METH_NOARGS, helloworld_docs},
   {NULL}
};
void inithelloworld(void)
{
   Py_InitModule3("helloworld", helloworld_funcs,
      "Extension module example!");
}

這裡使用 Py_BuildValue 函式來構建 Python 值。將上述程式碼儲存在 hello.c 檔案中。我們將看到如何編譯和安裝此模組以便從 Python 指令碼呼叫。

構建和安裝擴充套件

distutils 包使以標準方式分發 Python 模組(純 Python 和擴充套件模組)變得非常容易。模組以原始碼形式分發,通常透過名為 setup.py 的安裝指令碼進行構建和安裝。

對於上述模組,您需要準備以下 setup.py 指令碼:

from distutils.core import setup, Extension
setup(name='helloworld', version='1.0', \
   ext_modules=[Extension('helloworld', ['hello.c'])])

現在,使用以下命令,該命令將執行所有必要的編譯和連結步驟,使用正確的編譯器和連結器命令和標誌,並將生成的動態庫複製到適當的目錄:

$ python setup.py install

在基於 Unix 的系統上,您很可能需要以 root 使用者身份執行此命令,才能有權寫入 site-packages 目錄。這在 Windows 上通常不是問題。

匯入擴充套件

安裝擴充套件後,您將能夠像下面這樣在 Python 指令碼中匯入和呼叫該擴充套件:

import helloworld
print helloworld.helloworld()

這將產生以下輸出

Hello, Python extensions!!

傳遞函式引數

由於您很可能希望定義接受引數的函式,因此您可以為 C 函式使用其他簽名之一。例如,以下接受一些引數的函式將這樣定義:

static PyObject *module_func(PyObject *self, PyObject *args) {
   /* Parse args and do something interesting here. */
   Py_RETURN_NONE;
}

包含新函式條目的方法表將如下所示:

static PyMethodDef module_methods[] = {
   { "func", (PyCFunction)module_func, METH_NOARGS, NULL },
   { "func", module_func, METH_VARARGS, NULL },
   { NULL, NULL, 0, NULL }
};

您可以使用 API PyArg_ParseTuple 函式從傳遞到 C 函式的一個 PyObject 指標中提取引數。

PyArg_ParseTuple 的第一個引數是 args 引數。這是您將要解析的物件。第二個引數是一個格式字串,用於描述您期望引數出現的形式。每個引數在格式字串中都由一個或多個字元表示,如下所示。

static PyObject *module_func(PyObject *self, PyObject *args) {
   int i;
   double d;
   char *s;
   if (!PyArg_ParseTuple(args, "ids", &i, &d, &s)) {
      return NULL;
   }

   /* Do something interesting here. */
   Py_RETURN_NONE;
}

編譯模組的新版本並匯入它使您可以使用任意數量的任意型別引數來呼叫新函式:

module.func(1, s="three", d=2.0)
module.func(i=1, d=2.0, s="three")
module.func(s="three", d=2.0, i=1)

您可能會想出更多變化。

PyArg_ParseTuple 函式

這是 PyArg_ParseTuple 函式的標準簽名:

int PyArg_ParseTuple(PyObject* tuple,char* format,...)

此函式對於錯誤返回 0,對於成功返回非 0 值。Tuple 是作為 C 函式的第二個引數的 PyObject*。這裡的 format 是一個 C 字串,用於描述必需引數和可選引數。

以下是 PyArg_ParseTuple 函式的格式程式碼列表:

程式碼 C 型別 含義
c char 長度為 1 的 Python 字串將成為 C char。
d double Python float 將成為 C double。
f float Python float 將成為 C float。
i int Python int 將成為 C int。
l long Python int 將成為 C long。
L long long Python 的 int 型別轉換為 C 語言的 long long 型別。
O PyObject* 獲取指向 Python 引數的非空借用引用。
S char* 將不含嵌入空字元的 Python 字串轉換為 C 語言的 char*。
s# char*+int 將任意 Python 字串轉換為 C 語言的地址和長度。
t# char*+int 將只讀單段緩衝區轉換為 C 語言的地址和長度。
u Py_UNICODE* 將不含嵌入空字元的 Python Unicode 字串轉換為 C 語言的 Py_UNICODE*。
u# Py_UNICODE*+int 將任意 Python Unicode 字串轉換為 C 語言的地址和長度。
w# char*+int 將讀寫單段緩衝區轉換為 C 語言的地址和長度。
z char* 類似於 s,也接受 None(將 C 語言的 char* 設定為 NULL)。
z# char*+int 類似於 s#,也接受 None(將 C 語言的 char* 設定為 NULL)。
(...) 根據…… Python 序列被視為每個專案一個引數。
| 以下引數是可選的。
: 格式結束,後跟用於錯誤訊息的函式名。
; 格式結束,後跟完整的錯誤訊息文字。

返回值

Py_BuildValue 使用的格式字串與 PyArg_ParseTuple 非常相似。與其傳入要構建的值的地址,不如傳入實際的值。以下是一個實現加法函式的示例。

static PyObject *foo_add(PyObject *self, PyObject *args) {
   int a;
   int b;
   if (!PyArg_ParseTuple(args, "ii", &a, &b)) {
      return NULL;
   }
   return Py_BuildValue("i", a + b);
}

如果用 Python 實現,它將如下所示:

def add(a, b):
   return (a + b)

您可以從函式中返回兩個值。這將在 Python 中使用列表捕獲。

static PyObject *foo_add_subtract(PyObject *self, PyObject *args) {
   int a;
   int b;
   if (!PyArg_ParseTuple(args, "ii", &a, &b)) {
      return NULL;
   }
   return Py_BuildValue("ii", a + b, a - b);
}

如果用 Python 實現,它將如下所示:

def add_subtract(a, b):
   return (a + b, a - b)

Py_BuildValue 函式

以下是Py_BuildValue 函式的標準簽名:

PyObject* Py_BuildValue(char* format,...)

這裡的 format 是一個 C 字串,它描述了要構建的 Python 物件。Py_BuildValue 的後續引數是用於構建結果的 C 值。PyObject* 結果是一個新引用。

下表列出了常用的程式碼字串,其中零個或多個程式碼字串連線成一個格式字串。

程式碼 C 型別 含義
c char C 語言的 char 型別轉換為長度為 1 的 Python 字串。
d double C 語言的 double 型別轉換為 Python 的 float 型別。
f float C 語言的 float 型別轉換為 Python 的 float 型別。
i int C 語言的 int 型別轉換為 Python 的 int 型別。
l long C 語言的 long 型別轉換為 Python 的 int 型別。
N PyObject* 傳遞一個 Python 物件並竊取一個引用。
O PyObject* 傳遞一個 Python 物件並像平常一樣增加其引用計數 (INCREF)。
O& convert+void* 任意轉換
s char* 將 C 語言的以 null 結尾的 char* 轉換為 Python 字串,或將 NULL 轉換為 None。
s# char*+int 將 C 語言的 char* 和長度轉換為 Python 字串,或將 NULL 轉換為 None。
u Py_UNICODE* 將 C 語言的以 null 結尾的字串轉換為 Python Unicode 字串,或將 NULL 轉換為 None。
u# Py_UNICODE*+int 將 C 語言的字串和長度轉換為 Python Unicode 字串,或將 NULL 轉換為 None。
w# char*+int 將讀寫單段緩衝區轉換為 C 語言的地址和長度。
z char* 類似於 s,也接受 None(將 C 語言的 char* 設定為 NULL)。
z# char*+int 類似於 s#,也接受 None(將 C 語言的 char* 設定為 NULL)。
(...) 根據…… 從 C 值構建 Python 元組。
[...] 根據…… 從 C 值構建 Python 列表。
{...} 根據…… 從 C 值構建 Python 字典,鍵值交替出現。

程式碼 {...} 從偶數個 C 值構建字典,鍵值交替出現。例如,Py_BuildValue("{issi}",23,"zig","zag",42) 返回一個類似於 Python 的 {23:'zig','zag':42} 的字典。

Python - 工具/實用程式

標準庫包含許多模組,這些模組既可以用作模組,也可以用作命令列實用程式。

dis 模組

dis 模組是 Python 反彙編器。它將位元組碼轉換為更適合人類閱讀的格式。

示例

import dis
def sum():
   vara = 10
   varb = 20

   sum = vara + varb
   print ("vara + varb = %d" % sum)

# Call dis function for the function.
dis.dis(sum)

這將產生以下結果−

  3           0 LOAD_CONST               1 (10)
              2 STORE_FAST               0 (vara)

  4           4 LOAD_CONST               2 (20)
              6 STORE_FAST               1 (varb)

  6           8 LOAD_FAST                0 (vara)
             10 LOAD_FAST                1 (varb)
             12 BINARY_ADD
             14 STORE_FAST               2 (sum)

  7          16 LOAD_GLOBAL              0 (print)
             18 LOAD_CONST               3 ('vara + varb = %d')
             20 LOAD_FAST                2 (sum)
             22 BINARY_MODULO
             24 CALL_FUNCTION            1
             26 POP_TOP
             28 LOAD_CONST               0 (None)
             30 RETURN_VALUE

pdb 模組

pdb 模組是標準的 Python 偵錯程式。它基於 bdb 偵錯程式框架。

您可以從命令列執行偵錯程式(鍵入 n [或 next] 轉到下一行,鍵入 help 獲取可用命令列表):

示例

在嘗試執行pdb.py之前,請將您的路徑正確設定為 Python 庫目錄。讓我們嘗試上面的示例 sum.py:

$pdb.py sum.py
> /test/sum.py(3)<module>()
-> import dis
(Pdb) n
> /test/sum.py(5)<module>()
-> def sum():
(Pdb) n
>/test/sum.py(14)<module>()
-> dis.dis(sum)
(Pdb) n
  6           0 LOAD_CONST               1 (10)
              3 STORE_FAST               0 (vara)

  7           6 LOAD_CONST               2 (20)
              9 STORE_FAST               1 (varb)

  9          12 LOAD_FAST                0 (vara)
             15 LOAD_FAST                1 (varb)
             18 BINARY_ADD
             19 STORE_FAST               2 (sum)

  10         22 LOAD_CONST               3 ('vara + varb = %d')
             25 LOAD_FAST                2 (sum)
             28 BINARY_MODULO               
             29 PRINT_ITEM
             30 PRINT_NEWLINE            
             31 LOAD_CONST               0 (None)   
             34 RETURN_VALUE                         
--Return--
> /test/sum.py(14)<module>()->None
-v dis.dis(sum)
(Pdb) n
--Return--
> <string>(1)<module>()->None
(Pdb)

profile 模組

profile 模組是標準的 Python 效能分析器。您可以從命令列執行效能分析器:

示例

讓我們嘗試分析以下程式:

vara = 10
varb = 20
sum = vara + varb
print "vara + varb = %d" % sum

現在,嘗試使用cProfile.py執行此檔案sum.py,如下所示:

$cProfile.py sum.py
vara + varb = 30
   4 function calls in 0.000 CPU seconds
   Ordered by: standard name
ncalls   tottime  percall  cumtime  percall filename:lineno
 1       0.000    0.000    0.000    0.000 <string>:1(<module>)
 1       0.000    0.000    0.000    0.000 sum.py:3(<module>)
 1       0.000    0.000    0.000    0.000 {execfile}
 1       0.000    0.000    0.000    0.000 {method ......}

tabnanny 模組

tabnanny 模組檢查 Python 原始檔是否存在歧義縮排。如果檔案以某種方式混合使用製表符和空格,從而擾亂縮排,無論您使用什麼製表符大小,nanny 都會抱怨。

示例

讓我們嘗試分析以下程式:

vara = 10
varb = 20

sum = vara + varb
print "vara + varb = %d" % sum

如果您嘗試使用 tabnanny.py 執行一個正確的檔案,它就不會抱怨,如下所示:

$tabnanny.py -v sum.py
'sum.py': Clean bill of health.

Python - GUIs

在本章中,您將學習一些流行的 Python IDE(整合開發環境)以及如何使用 IDE 進行程式開發。

要使用 Python 的指令碼模式,您需要將 Python 指令序列儲存在文字檔案中,並以.py副檔名儲存。您可以使用作業系統上提供的任何文字編輯器。每當直譯器遇到錯誤時,都需要反覆編輯和執行原始碼。為了避免這種繁瑣的方法,可以使用 IDE。IDE 是一個一站式解決方案,用於鍵入、編輯原始碼、檢測錯誤和執行程式。

IDLE

Python 的標準庫包含IDLE模組。IDLE 代表整合開發和學習環境。顧名思義,它在學習階段非常有用。它包括一個 Python 互動式 shell 和一個程式碼編輯器,定製以滿足 Python 語言結構的需求。它的一些重要功能包括語法高亮、自動完成、可自定義介面等。

要編寫 Python 指令碼,請從“檔案”選單開啟一個新的文字編輯器視窗。

idle_module

將開啟一個新的編輯器視窗,您可以在其中輸入 Python 程式碼。儲存並使用“執行”選單執行它。

new_window

Jupyter Notebook

Jupyter Notebook 最初是作為 IPython 的 Web 介面開發的,它支援多種語言。名稱本身來源於受支援語言名稱中的字母——Julia、PYThon 和R。Jupyter notebook 是一個客戶端伺服器應用程式。伺服器在 localhost 上啟動,瀏覽器充當其客戶端。

使用 PIP 安裝 Jupyter notebook:

pip3 install jupyter

從命令列呼叫。

C:\Users\Acer>jupyter notebook

伺服器在 localhost 的 8888 埠啟動。

server_launched

系統的預設瀏覽器將開啟連結https://:8888/tree以顯示儀表板。

jupyter

開啟一個新的 Python notebook。它顯示 IPython 風格的輸入單元格。輸入 Python 指令和執行單元格。

python_notebook

Jupyter notebook 是一款多功能工具,資料科學家廣泛使用它來顯示內聯資料視覺化。notebook 可以方便地轉換為 PDF、HTML 或 Markdown 格式並分發。

VS Code

Microsoft 開發了一個名為 VS Code(Visual Studio Code)的原始碼編輯器,它支援多種語言,包括 C++、Java、Python 等。它提供語法高亮、自動完成、偵錯程式和版本控制等功能。

VS Code 是一個免費軟體。可以從https://vscode.com.tw/下載和安裝。

從開始選單(在 Windows 中)啟動 VS Code。

vs_code_window

您也可以從命令列啟動 VS Code:

C:\test>code .

除非安裝了相應的語言擴充套件,否則無法使用 VS Code。VS Code 的擴充套件市場上有許多用於語言編譯器和其他實用程式的擴充套件。從“擴充套件”選項卡(Ctrl+Shift+X)搜尋 Python 擴充套件並安裝它。

VS_Code_Extensions

啟用 Python 擴充套件後,您需要設定 Python 直譯器。按 Ctrl+Shift+P 並選擇 Python 直譯器。

select_interpreter

開啟一個新的文字檔案,輸入 Python 程式碼並儲存檔案。

python_code_file

開啟命令提示符終端並執行程式。

command_prompt_terminal

PyCharm

PyCharm 是另一個流行的 Python IDE。它是由捷克軟體公司 JetBrains 開發的。其功能包括程式碼分析、圖形偵錯程式、與版本控制系統的整合等。PyCharm 支援使用 Django 進行 Web 開發。

可以從https://www.jetbrains.com/pycharm/download下載社群版和專業版。

下載並安裝最新版本:2022.3.2 並開啟 PyCharm。歡迎螢幕如下所示:

welcome_to_pycharm

當您啟動新專案時,PyCharm 會根據您選擇的資料夾位置和選擇的 Python 直譯器版本為其建立一個虛擬環境。

new_project

您現在可以新增專案所需的一個或多個 Python 指令碼。在這裡,我們在 main.py 檔案中新增一個示例 Python 程式碼。

python_project

要執行程式,請從“執行”選單中選擇,或使用 Shift+F10 快捷鍵。

run_the_program

輸出將顯示在控制檯視窗中,如下所示:

output_displayed
廣告