Python3極簡教程(一小時學完)上

開始 Python 之旅

本教程基于?Python for you and me?教程翻譯制作,其中參考了?Python tutorial?和 _The Python Standard Library_,并對原教程的內容進行了改進與補充。

相關鏈接地址如下:

  • _Python tutorial_:Python 入門指南 — Python tutorial 3.6.3 documentation
  • _Python for you and me_:Welcome to Python for you and me — Python for you and me 0.5.beta1 documentation
  • _The Python Standard Library_:The Python Standard Library — Python 3.12.4 documentation

Python for you and me?的法律聲明有如下內容:

Permission is granted to copy, distribute, and/or modify this document under the terms of the Open Publication Licence, Version 1.0, or any later version.

知識點
  • 使用交互模式的 Python3 解釋器
  • 簡單使用 vim 編寫 Python3 腳本
  • 執行 Python3 腳本
  • Python3 代碼風格建議
  • Python3 中使用注釋
  • 認識 Python3 模塊
實驗環境
  • Python 3.5
  • Xfce 終端
  • Vim
適合人群

本教程屬于初級級別課程,不僅適用于那些有其它語言基礎的同學,對沒有編程經驗的同學也非常友好。

解釋器

Python 是一個腳本語言,你可以在 Python 解釋器中直接寫代碼或者將代碼寫到一個文件里,然后執行這個文件(即腳本文件)。

首先,我們從使用解釋器開始,打開 Xfce 終端,鍵入python3?并回車。這個時候解釋器便工作于交互模式

1-2-1

1-2-2

作為我們第一個 Python 代碼,我們將打印經典的 "Hello World!",輸入python3,如下所示:

>>> print("Hello World!")
Hello World!

1-2-3

欣賞完自己的杰作后,按快捷鍵?Ctrl + D?即可退出解釋器,你也可以鍵入?exit()?然后敲回車來退出解釋器。

腳本文件

作為正式的程序員,你可能想要將上述的代碼寫到一個源文件。那么我們來創建一個 helloworld.py 文件,用你喜歡的任何編輯器來創建這個文件,我使用 Vim ,你可以使用基于 GUI 的工具,如實驗樓環境桌面上的 gedit。

我們建議使用 Vim,在這里我們簡單的使用它,你可以在實驗樓的課程?Vim 編輯器?里深入學習或者通過這張?vi(vim)鍵盤圖幫助你記憶:

1-3-1

(原圖來自:www.viemu.com)

首先,創建的文件會放在?/home/shiyanlou?目錄下,打開 Xfce 終端,鍵入?vim helloworld.py?來啟動 Vim 并編輯 helloworld.py,啟動后不要亂按鍵。

1-3-2

然后按?i?鍵進入插入模式,此時你可以看到左下角有 “插入” 兩個字,現在你可以鍵入下面的代碼了。

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

其中第一行的前兩個字符?#!?稱為?Shebang?,目的是告訴 shell 使用 Python 解釋器執行其下面的代碼。

1-3-3

然后按?Esc?鍵退出插入模式,再鍵入?:wq?回車,Vim 就會保存文件并退出。

要運行腳本文件?helloworld.py,還要為文件添加可執行權限(否則會出現權限不足的錯誤):

chmod +x helloworld.py

在這里使用到了 linux 下的 chmod 命令來變更文件或目錄的權限,+x代表賦予了其可執行的權限。

點擊此處快速掌握常用 Unix/Linux 常用命令查看。

然后執行腳本文件:

./helloworld.py

1-3-4

這里需要注意如果程序中沒有?#!/usr/bin/env python3?的話,應該使用?python3 helloworld.py?來執行,否則使用?./helloworld.py?程序會被當作 bash 腳本來執行,最終報錯。

代碼風格建議

在 Python 中,空格很重要,我們使用空格將標識符區分開,行開始處的空格我們稱之為縮進,如果你的縮進是錯誤的,Python 解釋器會拋出錯誤。例如下面情形:

>>> a = 12
>>>   a = 12File "<stdin>", line 1a = 12^
IndentationError: unexpected indent

這是因為第二行開始處出現了多余的空格,所以需要經常檢查代碼的縮進。

如果你在代碼中混用制表符和空格,這種縮進錯誤會很常見。

所以如果是用空格,就一直用空格縮進,不要使用制表符。

建議遵守以下約定:

  • 使用 4 個空格來縮進
  • 永遠不要混用空格和制表符
  • 在函數之間空一行
  • 在類之間空兩行
  • 字典,列表,元組以及參數列表中,在?,?后添加一個空格。對于字典,:?后面也添加一個空格
  • 在賦值運算符和比較運算符周圍要有空格(參數列表中除外),但是括號里則不加空格:a = f(1, 2) + g(3, 4)

注釋

注釋是一些文本用來解釋此處代碼是做什么的,寫注釋是為了使他人更容易理解代碼。

Python 的注釋以?#?字符開始的,在?#?字符到行尾之間的所有東西都被程序忽略為注釋,也就說對程序沒有任何影響。

>>> # 這是一個注釋
>>> # 下面這一行是求兩數之和
>>> a = 12 + 34
>>> print(a) # 這里也是注釋 :)

注釋主要面向的人群是開發人員和維護代碼庫的人員,所以如果你寫了一些復雜代碼,你應該寫足夠的注釋在里面,以便讓其他任何人能夠通過你的注釋讀懂代碼。你應該總是在?#?后跟一個空格,然后再寫注釋。你也可以做一些標準的注釋,像下面這樣。

# FIXME -- fix these code later
# TODO -- in future you have to do this

模塊

模塊是包含了我們能復用的代碼的文件,包含了不同的函數定義,變量。模塊文件通常以 .py 為擴展名。

Python 本身在默認安裝時就帶有大量的模塊。我們之后將會用到其中的一部分。在使用模塊前先導入它。

>>> import math    # 導入math模塊
>>> print(math.e)
2.71828182846

我們會在模塊這個實驗里學習更多有關模塊的知識。

總結

完成本實驗后,應當明白如何使用交互模式的 Python3 解釋器,如何簡單使用 vim 編寫腳本文件并執行這個腳本文件。

要特別注意的是,Python 使用縮進來定義語句塊,縮進是 Python 語法的一部分,這與其它大多數語言不同。

代碼風格在本課程的實驗?PEP8 代碼風格指南?有更為詳細的講述。注釋的話,能使用英文建議使用英文。模塊同樣會在之后的實驗里深入學習。

變量和數據類型

本節實驗內容主要包括 Python 基本的數據類型和變量。

知識點
  • python 關鍵字
  • 變量的定義與賦值
  • input() 函數
  • 字符串的格式化

關鍵字和標識符

每一種編程語言都有它們自己的語法規則,就像我們所說的外語。

下列的標識符是 Python3 的關鍵字,并且不能用于通常的標識符。關鍵字必須完全按照下面拼寫:

False               def                 if                  raise
None                del                 import              return
True                elif                in                  try
and                 else                is                  while
as                  except              lambda              with
assert              finally             nonlocal            yield
break               for                 not
class               from                or
continue            global              pass

這些內容可以在 Python3 解釋器中得到:

2-1-1關鍵字

在 Python 中 我們不需要為變量指定數據類型。所以你可以直接寫出?abc = 1?,這樣變量?abc?就是整數類型。如果你寫出?abc = 1.0?,那么變量?abc?就是浮點類型。

>>> a = 13
>>> b = 23
>>> a + b
36

通過上面的例子你應該理解了如何在 Python 中定義變量,也就是只需要輸入變量名和值就行了。Python 也能操作字符串,它們用單引號或雙引號括起來,就像下面這樣。

>>> 'ShiYanLou'
'ShiYanLou'
>>> 'ShiYanLou\'s best'
"ShiYanLou's best"
>>> "Hello World!"
'Hello World!'

從鍵盤讀取輸入

通常情況下,Python 的代碼中是不需要從鍵盤讀取輸入的。不過我們還是可以在 Python 中使用函數?input()?來做到這一點,input()?有一個用于打印在屏幕上的可選字符串參數,返回用戶輸入的字符串。

我們來寫一個程序,它將會從鍵盤讀取一個數字并且檢查這個數字是否小于 100。這個程序名稱是?/home/shiyanlou/testhundred.py。還記得如何使用 Vim 嗎?忘了的話可以看看下面的動圖,打開 Xfce 終端,使用 Vim 開始編寫代碼:

2-3-1

在終端中輸入:

vim testhundred.py

輸入i后,編寫以下代碼,注意縮進:

#!/usr/bin/env python3
number = int(input("Enter an integer: "))
if number <= 100:print("Your number is less than or equal to 100")
else:print("Your number is greater than 100")

接著按?ESC?鍵并輸入?:wq?退出 Vim。

該段代碼的含義如下:

如果?number?小于等于 100,輸出 “Your number is less than or equal to 100”,如果大于 100,輸出 “Your number is greater than 100”。

在執行程序前,別忘了為文件添加可執行權限:

chmod +x testhundred.py

程序運行起來就像這樣:

./testhundred.py
Enter an integer: 13
Your number is less than or equal to 100
./testhundred.py
Enter an integer: 123
Your number is greater than 100

后續程序中將會用到之后實驗將學到的 while 循環語句,這里先簡單介紹下。

while 是使用一個表達式作為判斷的條件,如果條件不能夠達成則停止循環:

w = 20
while w > 1:print(w)w -= 1

這個循環中判斷條件為?w > 1,當條件不滿足的時候就停止循環。當 w 的值小于等于 1 的時候,循環退出。這里要注意?w -= 1,等同于?w = w - 1

下一個程序我們寫入?/home/shiyanlou/investment.py,來計算投資,使用 Vim 輸入以下代碼:

#!/usr/bin/env python3
amount = float(input("Enter amount: "))  # 輸入數額
inrate = float(input("Enter Interest rate: "))  # 輸入利率
period = int(input("Enter period: "))  # 輸入期限
value = 0
year = 1
while year <= period:value = amount + (inrate * amount)print("Year {} Rs. {:.2f}".format(year, value))amount = valueyear = year + 1

運行程序:

cd /home/shiyanlou
chmod +x investment.py
./investment.py
Enter amount: 10000
Enter Interest rate: 0.14
Enter period: 5
Year 1 Rs. 11400.00
Year 2 Rs. 12996.00
Year 3 Rs. 14815.44
Year 4 Rs. 16889.60
Year 5 Rs. 19254.15

while year <= period:?的意思是,當?year?的值小于等于?period?的值時,下面的語句將會一直循環執行下去,直到?year?大于?period?時停止循環。

Year {} Rs. {:.2f}".format(year, value)?稱為字符串格式化,大括號和其中的字符會被替換成傳入?str.format()?的參數,也即?year?和?value。其中?{:.2f}?的意思是替換為 2 位精度的浮點數。

代碼示例

一些關于變量和數據類型的代碼實例。下面的例子程序請都寫在?/home/shiyanlou?目錄下。

本部分包括下面的幾個實例:

  1. 求 N 個數字的平均值
  2. 華氏溫度到攝氏溫度轉換程序

請按照指定目錄完成每個程序,并理解每個程序中每行代碼的含義。

求 N 個數字的平均值

下面的程序用來求 N 個數字的平均值。請將程序代碼寫入到文件?/home/shiyanlou/averagen.py?中,程序中將需要輸入 10 個數字,最后計算 10 個 數字的平均值。

代碼內容,請理解每一行代碼含義:

#!/usr/bin/env python3
N = 10
sum = 0
count = 0
print("please input 10 numbers:")
while count < N:number = float(input())sum = sum + numbercount = count + 1
average = sum / N
print("N = {}, Sum = {}".format(N, sum))
print("Average = {:.2f}".format(average))

運行程序過程,需要輸入 10 個數字:

cd /home/shiyanlou
chmod +x averagen.py
./averagen.py
1.2
3.4
3.5
33.2
2
4
6
2.4
4
5.5
N = 10, Sum = 65.2
Average = 6.52
溫度轉換

在下面的程序里,我們使用公式 C = (F - 32) / 1.8 將華氏溫度轉為攝氏溫度。

#!/usr/bin/env python3
fahrenheit = 0
print("Fahrenheit Celsius")
while fahrenheit <= 250:celsius = (fahrenheit - 32) / 1.8 # 轉換為攝氏度print("{:5d} {:7.2f}".format(fahrenheit , celsius))fahrenheit = fahrenheit + 25

{:5d}?的意思是替換為 5 個字符寬度的整數,寬度不足則使用空格填充。?{:7.2f}的意思是替換為為 7 個字符寬度的保留兩位的小數,小數點也算一個寬度,寬度不足則使用空格填充。其中7指寬度為 7,.2f指保留兩位小數。

運行程序:

cd /home/shiyanlou
chmod +x temperature.py
./temperature.py
Fahrenheit Celsius0  -17.7825   -3.8950   10.0075   23.89100   37.78125   51.67150   65.56175   79.44200   93.33225  107.22250  121.11

單行定義多個變量或賦值

你甚至可以在一行內將多個值賦值給多個變量。

在終端中輸入:

python3

進入到 python3 交互式界面:

>>> a , b = 45, 54
>>> a
45
>>> b
54

這個技巧用來交換兩個數的值非常方便。

>>> a, b = b , a
>>> a
54
>>> b
45

要明白這是怎么工作的,你需要學習元組(_tuple_)這個數據類型。我們是用逗號創建元組。在賦值語句的右邊我們創建了一個元組,我們稱這為元組封裝(_tuple packing_),賦值語句的左邊我們則做的是元組拆封 (_tuple unpacking_)。

下面是另一個元組拆封的例子:

>>> data = ("shiyanlou", "China", "Python")
>>> name, country, language = data
>>> name
'shiyanlou'
>>> country
'China'
>>> language
'Python'

總結

完成這個實驗我們應該了解到以下的內容:

  1. Python3 關鍵字有哪些(在這里不要求全部記住)
  2. 變量如何賦值變量
  3. Python3 怎樣從鍵盤讀取輸入
  4. Python3 字符串的格式化
  5. 元組封裝和拆封

在這里可以了解更多有關字符串格式化的信息:string — Common string operations — Python 3.12.4 documentation。

運算符和表達式

在 Python 中你會寫大量的表達式。

表達式由運算符和操作數組成,像?2+3?就是一個表達式,其中 2 和 3 是操作數,加號是運算符。

本節實驗中我們將學習運算符和表達式的基本用法。

知識點
  • 關系/邏輯運算
  • 表達式
  • 類型轉換

運算符

運算符是一些符號,它告訴 Python 解釋器去做一些數學或邏輯操作。一些基本的數學操作符如下所示:

>>> 2 + 3
5
>>> 23.0 - 3
20.0
>>> 22 / 12
1.8333333333333333

只要有任意一個操作數是浮點數,結果就會是浮點數。

進行除法運算時若是除不盡,結果將會是小數,這很自然,如果要進行整除,使用?//?運算符,它將返回商的整數部分。

%?是求余運算符:

>>> 14 % 3
2

整數運算示例

整數運算符比較容易理解,代碼如下:

#!/usr/bin/env python3
days = int(input("Enter days: "))
months = days // 30
days = days % 30
print("Months = {} Days = {}".format(months, days))

在終端里使用 Vim 輸入上述代碼后,用chmod命令賦予可執行權限,最后運行程序:

3-2.1-1

Enter days:后獲得用戶輸入的天數,然后獲得月份數和天數,最后把這些數打印出來。你可以使用更容易的辦法:

#!/usr/bin/env python3
days = int(input("Enter days: "))
print("Months = {} Days = {}".format(*divmod(days, 30)))

divmod(num1, num2)?返回一個元組,這個元組包含兩個值,第一個是 num1 和 num2 相整除得到的值,第二個是 num1 和 num2 求余得到的值,然后我們用?*?運算符拆封這個元組,得到這兩個值。

關系運算符

你可以使用下面的運算符實現關系運算。

關系運算符

OperatorMeaning
<Is less than
<=Is less than or equal to
>Is greater than
>=Is greater than or equal to
==Is equal to
!=Is not equal to

在終端里輸入python3進入交互頁面,試一試以下一些例子:

>>> 1 < 2
True
>>> 3 > 34
False
>>> 23 == 45
False
>>> 34 != 323
True

邏輯運算符

對于邏輯 與,或,非,我們使用?andornot?這幾個關鍵字。

邏輯運算符?and?和?or?也稱作短路運算符:它們的參數從左向右解析,一旦結果可以確定就停止。例如,如果?A?和?C?為真而?B?為假,A and B and C?不會解析?C?。作用于一個普通的非邏輯值時,短路運算符的返回值通常是能夠最先確定結果的那個操作數。

關系運算可以通過邏輯運算符?and?和?or?組合,比較的結果可以用?not?來取反意。邏輯運算符的優先級又低于關系運算符,在它們之中,not?具有最高的優先級,or?優先級最低,所以?A and not B or C?等于?(A and (notB)) or C。當然,括號也可以用于比較表達式。

下面是一些例子:

>>> 5 and 4   # 首先判斷5,肯定為true,那么最終的結果就取決于 and 后面那個的布爾值,4 的布爾值為 true,這樣就可以確定整個表達式的值為 true 了,所以返回 4
4
>>> 0 and 4   # 首先判斷0,因為 0 的布爾值為 false,那么不管 and 后面那個的布爾值是什么,整個表達式的布爾值都應該為 false 了,這個時候就不需要判斷 4 了,直接返回最先確定結果的那個數也就是0
0
>>> False or 3 or 0
3
>>> 2 > 1 and not 3 > 5 or 4
True

簡寫運算符

x op= expression?為簡寫運算的語法形式。其等價于?x = x op expression?,舉例如下:

>>> a = 12
>>> a += 13
>>> a
25
>>> a /= 3
>>> a
8.333333333333334
>>> a += (26 * 32)
>>> a
840.3333333333334

/home/shiyanlou/shorthand.py?示例,輸入quit()退出 python 交互頁面,用 Vim 寫入以下代碼:

#!/usr/bin/env python3
N = 100
a = 2
while a < N:print(str(a))a *= a

運行程序:

cd /home/shiyanlou
chmod +x shorthand.py
./shorthand.py
2
4
16

表達式

通常我們書寫表達式的時候,會在每一個運算符左右都放一個空格,這樣使代碼更可讀,如:

a = 234 * (45 - 56 / 34)

一個用于展示表達式的例子,注意其中運算符的優先級。

#!/usr/bin/env python3
a = 9
b = 12
c = 3
x = a - b / 3 + c * 2 - 1
y = a - b / (3 + c) * (2 - 1)
z = a - (b / (3 + c) * 2) - 1
print("X = ", x)
print("Y = ", y)
print("Z = ", z)

運行程序:

cd /home/shiyanlou
chmod +x evaluationexp.py
./evaluationexp.py
X = 10.0
Y = 7.0
Z = 4.0

第一個計算的是 _x_,步驟如下:

9 - 12 / 3 + 3 * 2 -1
9 - 4 + 3 * 2 - 1
9 - 4 + 6 - 1
5 + 6 - 1
11 - 1
10

由于括號的存在,y?和?z?的計算方式不同,你可以自己去驗證它們。

類型轉換

我們可以手動的執行類型轉換。

類型轉換函數轉換路徑
float(string)字符串 -> 浮點值
int(string)字符串 -> 整數值
str(integer)整數值 -> 字符串
str(float)浮點值 -> 字符串
>>> a = 8.126768
>>> str(a)
'8.126768'

可以分別嘗試下前面的四個類型轉換函數。

程序示例

evaluateequ.py

這個程序計算數列?1/x+1/(x+1)+1/(x+2)+ ... +1/n,我們設 x = 1,n = 10。

使用 Vim 寫入以下代碼:

#!/usr/bin/env python3
sum = 0
for i in range(1, 11):sum += 1.0 / iprint("{:2d} {:6.4f}".format(i , sum))

編寫完成后運行?chmod +x evaluateequ.py?給文件增加運行權限。

運行程序:

3-2.7-1

quadraticequation.py

這個程序的名稱為?quadratic equation?組合,是二次方程的英文詞組。

這個程序用來求解二次方程式:

#!/usr/bin/env python3
import math
a = int(input("Enter value of a: "))
b = int(input("Enter value of b: "))
c = int(input("Enter value of c: "))
d = b * b - 4 * a * c
if d < 0:print("ROOTS are imaginary")
else:root1 = (-b + math.sqrt(d)) / (2 * a)root2 = (-b - math.sqrt(d)) / (2 * a)print("Root 1 = ", root1)print("Root 2 = ", root2)

編寫完成后運行?chmod +x quadraticequation.py?給文件增加運行權限。

運行程序:

3-2.7-2

salesmansalary.py

這個程序計算一位數碼相機銷售人員的工資。他的基本工資是 1500,每售出一臺相機他可以得到 200 并且獲得 2% 的抽成。程序要求輸入相機數量及單價。

#!/usr/bin/env python3
basic_salary = 1500
bonus_rate = 200
commission_rate = 0.02
numberofcamera = int(input("Enter the number of inputs sold: "))
price = float(input("Enter the price of camera: "))
bonus = (bonus_rate * numberofcamera)
commission = (commission_rate * price * numberofcamera)
print("Bonus        = {:6.2f}".format(bonus))
print("Commission   = {:6.2f}".format(commission))
print("Gross salary = {:6.2f}".format(basic_salary + bonus + commission))

編寫完成后運行?chmod +x salesmansalary.py?給文件增加運行權限,然后運行程序。

運行效果如下:

圖片描述

總結

本節實驗知識點回顧:

  • 關系/邏輯運算
  • 表達式
  • 類型轉換

除了數值運算,關系和邏輯運算也是程序的重要組成部分。另外 Python 是強類型語言,所以必要的時候需要手動進行類型轉換。

挑戰:圓的面積

介紹

我們通過實驗已經學習了基本的 Python 3 語法。現在我們就來用一個挑戰來鞏固一下我們的實驗效果。

本挑戰中,我們將實現一個程序用來計算半徑為 2 的圓的面積并打印輸出。

目標

在?/home/shiyanlou/Code?創建一個 Python 腳本?CircleArea.py

cd /home/shiyanlou/Code
touch CircleArea.py

CircleArea.py 能夠計算出一個半徑為 2 的圓的面積,并且把面積打印出來,保留小數點后 10 位。

不要使用 input 等方法獲得輸入,程序不需要輸入任何參數,程序執行如下,直接輸出半徑為 2 的圓的面積:

python3 /home/shiyanlou/Code/CircleArea.py

提示語

  • import math
  • 使用?format?可以控制輸出的小數位數,可以使用?'{:.10f}'.format()?來進行格式化輸出保留 10 位小數
  • 注意代碼文件的路徑必須是?/home/shiyanlou/Code/CircleArea.py
  • 不要使用 input 獲取輸入,程序執行不需要任何輸入的參數

知識點

  • 導入模塊
  • 打印輸出
  • 運算符和表達式

參考代碼

注意:請務必先獨立思考獲得 PASS 之后再查看參考代碼,直接拷貝代碼收獲不大。

/home/shiyanlou/Code/CircleArea.py?參考代碼:

參考答案:

import math
# 計算圓的面積
area = 2 * 2 * math.pi
# 格式化輸出圓的面積,保留10位小數
print("{:.10f}".format(area))

控制流 If-else

我們處理現實生活中的問題時會做出決定,就像決定買哪種相機或者怎樣更好的打籃球。

同樣我們寫計算機程序的時候也要做相同的事情。

我們通過?if-else?語句來做決定,我們使用它來改變程序運行的流程。

知識點
  • if 語句
  • else 語句
  • 真值檢測

If 語句

語法如下:

if expression:do this

如果表達式?expression?的值為真(不為零的任何值都為真),程序將執行縮進后的內容。務必要使用正確的縮進,在表達式為真的情況將會執行縮進的所有行。

一個簡單的例子,使用vim寫入文件?/home/shiyanlou/number100.py,程序接受用戶輸入的一個數并且檢查這個數是否小于 100。

#!/usr/bin/env python3
number = int(input("Enter a number: "))
if number < 100:print("The number is less than 100")

然后我們運行它:

cd /home/shiyanlou
chmod +x number100.py
./number100.py

操作截圖:

5-2-1

Else 語句

在上面的例子中,我們想要這樣做:如果輸入數大于 100 則打印 "Greater than"。我們使用?else?語句來做到這一點,它將在?if?語句未滿足的情況時工作。

#!/usr/bin/env python3
number = int(input("Enter a number: "))
if number < 100:print("The number is less than 100")
else:print("The number is greater than 100")

運行它:

此處輸入圖片的描述

另一個非常基礎的例子:

>>> x = int(input("Please enter an integer: "))
>>> if x < 0:
...      x = 0
...      print('Negative changed to zero')
... elif x == 0:
...      print('Zero')
... elif x == 1:
...      print('Single')
... else:
...      print('More')

在上面的例子中,elif?是?else if?的縮寫。

真值檢測

檢測真值的優雅方式是這樣的:

if x:pass

不要像下面這樣做:

if x == True:pass

總結

這個實驗非常簡單,這里只是提一句,Python 中的很多值是具有布爾意義的,所以有時候我們可以寫的更優雅一點。

同時也要注意下?if?elif?else?的基本語法結構。

循環

在以前的例子里,有些時候我們需要多次執行相同的任務,我們使用一個計數器來檢查代碼需要執行的次數。這個技術被稱為循環。

實驗知識點
  • while 循環
  • print() 函數的 end 參數
  • 列表
    • 索引
    • 切片
  • for 循環
  • range() 函數
  • continue 關鍵字
  • for 循環中的 else 關鍵字

while 循環

while?語句的語法如下:

while condition:statement1statement2

????????想要多次執行的代碼必須以正確的縮進放在?while?語句下面。在表達式?condition?為真的時候它們才會執行。同?if-else?一樣,非零值為真。啟動 python3 交互頁面,讓我們寫一個簡單的代碼,它按順序打印 0 到 10 的數字:

>>> n = 0
>>> while n < 11:
...     print(n)
...     n += 1
...
0
1
2
3
4
5
6
7
8
9
10

????????在第一行我們使?n = 0,然后在?while?語句中把條件設置為?n < 11,這意味著在?while?語句下面縮進的所有行將會被執行,直到?n?的值大于等于 11。在循環里我們只是打印 n 的值然后令它增一。

????????想想如果沒有循環語句,你想要打印 0 到 10 的所有數字,那你得手動打印 11 次!

斐波那契(Fibonacci)數列

我們來試試打印斐波那契數列。這個數列前兩項為 1,之后的每一個項都是前兩項之和。所以這個數列看起來就像這樣:?1,1,2,3,5,8,13,...

#!/usr/bin/env python3
a, b = 0, 1
while b < 100:print(b)a, b = b, a + b

運行程序:

此處輸入圖片的描述

第一行代碼中我們初始化?a?和?b。當?b?的值小于 100 的時候,循環執行代碼。循環里我們首先打印?b?的值,然后在下一行將?a + b?的值賦值給?bb?的值賦值給?a

學習其他語言的同學在這里可能有些困惑,你可以這樣理解,Python 中賦值語句執行時會先對賦值運算符右邊的表達式求值,然后將這個值賦值給左邊的變量。

默認情況下,print()?除了打印你提供的字符串之外,還會打印一個換行符,所以每調用一次?print()?就會換一次行,如同上面一樣。

你可以通過?print()?的另一個參數?end?來替換這個換行符,就像下面這樣,下面的程序寫入?/home/shiyanlou/fibonacci2.py

#!/usr/bin/env python3
a, b = 0, 1
while b < 100:print(b, end=' ')a, b = b, a + b
print()

運行程序:

cd /home/shiyanlou
chmod +x fibonacci2.py
./fibonacci2.py

此處輸入圖片的描述

冪級數

我們來寫一個程序計算冪級數:e^x = 1 + x + x^2 / 2! + x^3 / 3! + ... + x^n / n!?(0 < x < 1)。

該程序寫入代碼文件?/home/shiyanlou/powerseries.py

#!/usr/bin/env python3
x = float(input("Enter the value of x: "))
n = term = 1
result = 1.0
while n <= 100:term *= x / nresult += termn += 1if term < 0.0001:break
print("No of Times= {} and Sum= {}".format(n, result))

運行程序:

此處輸入圖片的描述

在這個程序里我們介紹一個新的關鍵字?break,它可以終止最里面的循環。這個例子里我們在?if?語句里使用?break

if term < 0.0001:break

這意味著如果?term?的值小于?0.0001,那么終止循環。

乘法表

這個例子里我們打印 10 以內的乘法表。寫入代碼文件?/home/shiyanlou/multiplication.py

#!/usr/bin/env python3
i = 1
print("-" * 50)
while i < 11:n = 1while n <= 10:print("{:4d}".format(i * n), end=' ')n += 1print()i += 1
print("-" * 50)

運行如下:

此處輸入圖片的描述

這里我們在?while?循環里使用了另一個?while?循環,這被稱為嵌套循環。你應該已經看到一條有趣的語句:

print("-" * 50)

字符串若是乘上整數 n,將返回由 n 個此字符串拼接起來的新字符串。

下面是一些例子:

>>> 's' * 10
'ssssssssss'
>>> print("*" * 10)
**********
>>> print("#" * 20)
####################
>>> print("--" * 20)
----------------------------------------
>>> print("-" * 40)
----------------------------------------

一些打印星號的例子

這里是一些你可以在大學的實驗報告里經常看到的例子。

設計 1
#!/usr/bin/env python3
row = int(input("Enter the number of rows: "))
n = row
while n >= 0:x =  "*" * nprint(x)n -= 1

運行這個程序:

此處輸入圖片的描述

設計 2
#!/usr/bin/env python3
n = int(input("Enter the number of rows: "))
i = 1
while i <= n:print("*" * i)i += 1

運行這個程序:

此處輸入圖片的描述

設計 3
#!/usr/bin/env python3
row = int(input("Enter the number of rows: "))
n = row
while n >= 0:x = "*" * ny = " " * (row - n)print(y + x)n -= 1

運行這個程序:

此處輸入圖片的描述

?列表

在繼續學習循環之前,我們先學習一個叫做列表的數據結構。它可以寫作中括號之間的一列逗號分隔的值。列表的元素不必是同一類型:

>>> a = [ 1, 342, 223, 'India', 'Fedora']
>>> a
[1, 342, 223, 'India', 'Fedora']

你可以將上面的列表想象為一堆有序的盒子,盒子包含有上面提到的值,每個盒子都有自己的編號(紅色的數字),編號從零開始,你可以通過編號訪問每一個盒子里面的值。對于列表,這里的編號稱為索引。

6-3-1

我們像下面這樣通過索引來訪問列表中的每一個值:

>>> a[0]
1
>>> a[4]
'Fedora'

如果我們使用負數的索引,那將會從列表的末尾開始計數,像下面這樣:

>>> a[-1]
'Fedora'

你甚至可以把它切成不同的部分,這個操作稱為切片,例子在下面給出:

>>> a[0:-1]
[1, 342, 223, 'India']
>>> a[2:-2]
[223]

切片并不會改變正在操作的列表,切片操作返回其子列表,這意味著下面的切片操作返回列表一個新的(棧)拷貝副本:

>>> a[:]
[1, 342, 223, 'India', 'Fedora']

切片的索引有非常有用的默認值;省略的第一個索引默認為零,省略的第二個索引默認為切片的索引的大小。如果是字符串,則為字符串大小。

>>> a[:-2]
[1, 342, 223]
>>> a[-2:]
['India', 'Fedora']

有個辦法可以很容易地記住切片的工作方式:切片時的索引是在兩個元素之間 。左邊第一個元素的索引為 0,而長度為 n 的列表其最后一個元素的右界索引為 n。例如:

 +---+-----+-----+---------+----------+| 1 | 342 | 223 | 'India' | 'Fedora' |+---+-----+-----+---------+----------+0    1     2       3        4          5-5   -4    -3      -2       -1

上面的第一行數字給出列表中的索引點 0...5。第二行給出相應的負索引。切片是從 i 到 j 兩個數值表示的邊界之間的所有元素。

對于非負索引,如果上下都在邊界內,切片長度就是兩個索引之差。例如?a[2:4]?是 2。

Python 中有關下標的集合都滿足左閉右開原則,切片中也是如此,也就是說集合左邊界值能取到,右邊界值不能取到。

對上面的列表,?a[0:5]?用數學表達式可以寫為?[0,5)?,其索引取值為?0,1,2,3,4,所以能將a中所有值獲取到。 你也可以用a[:5], 效果是一樣的。

a[-5:-1],因為左閉右開原則,其取值為?-5,-4,-3,-2?是不包含?-1?的。

為了取到最后一個值,你可以使用?a[-5:]?,它代表了取該列表最后 5 個值。

試圖使用太大的索引會導致錯誤:

>>> a[32]
Traceback (most recent call last):File "<stdin>", line 1, in <module>
IndexError: list index out of range
>>> a[-10]
Traceback (most recent call last):File "<stdin>", line 1, in <module>
IndexError: list index out of range

Python 能夠優雅地處理那些沒有意義的切片索引:一個過大的索引值(即大于列表實際長度)將被列表實際長度所代替,當上邊界比下邊界大時(即切片左值大于右值)就返回空列表:

>>> a[2:32]
[223, 'India', 'Fedora']
>>> a[32:]
[]

切片操作還可以設置步長,就像下面這樣:

>>> a[1::2]
[342, 'India']

它的意思是,從切片索引 1 到列表末尾,每隔兩個元素取值。

列表也支持連接這樣的操作,它返回一個新的列表:

>>> a + [36, 49, 64, 81, 100]
[1, 342, 223, 'India', 'Fedora', 36, 49, 64, 81, 100]

列表允許修改元素:

>>> cubes = [1, 8, 27, 65, 125]
>>> cubes[3] = 64
>>> cubes
[1, 8, 27, 64, 125]

也可以對切片賦值,此操作可以改變列表的尺寸,或清空它:

>>> letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
>>> letters
['a', 'b', 'c', 'd', 'e', 'f', 'g']
>>> # 替換某些值
>>> letters[2:5] = ['C', 'D', 'E']
>>> letters
['a', 'b', 'C', 'D', 'E', 'f', 'g']
>>> # 現在移除他們
>>> letters[2:5] = []
>>> letters
['a', 'b', 'f', 'g']
>>> # 通過替換所有元素為空列表來清空這個列表
>>> letters[:] = []
>>> letters
[]

細心的同學可能發問了,前面不是說過切片操作不改變列表么?嚴格來說,這里并不算真正的切片操作,只是上面代碼中賦值運算符左邊的這種操作與切片操作形式一樣而已。

要檢查某個值是否存在于列表中,你可以這樣做:

>>> a = ['ShiYanLou', 'is', 'cool']
>>> 'cool' in a
True
>>> 'Linux' in a
False

這意味著我們可以將上面的語句使用在?if?子句中的表達式。通過內建函數?len()?我們可以獲得列表的長度:

>>> len(a)
3

如果你想要檢查列表是否為空,請這樣做:

if list_name: # 列表不為空pass
else: # 列表為空pass

列表是允許嵌套的(創建一個包含其它列表的列表),例如:

>>> a = ['a', 'b', 'c']
>>> n = [1, 2, 3]
>>> x = [a, n]
>>> x
[['a', 'b', 'c'], [1, 2, 3]]
>>> x[0]
['a', 'b', 'c']
>>> x[0][1]
'b'

for 循環

通過?for?語句我們可以使用 for 循環。Python 里的 for 循環與 C 語言中的不同。這里的 for 循環遍歷任何序列(比如列表和字符串)中的每一個元素。下面給出示例:

>>> a = ['ShiYanLou', 'is', 'powerful']
>>> for x in a:
...     print(x)
...
ShiYanLou
is
powerful

我們也能這樣做:

>>> a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> for x in a[::2]:
...     print(x)
1
3
5
7
9
range() 函數

如果你需要一個數值序列,內置函數 ?range()? 會很方便,它生成一個等差數列(并不是列表):

>>> for i in range(5):
...     print(i)
...
0
1
2
3
4
>>> range(1, 5)
range(1, 5)
>>> list(range(1, 5))
[1, 2, 3, 4]
>>> list(range(1, 15, 3))
[1, 4, 7, 10, 13]
>>> list(range(4, 15, 2))
[4, 6, 8, 10, 12, 14]

continue 語句

如同?break?,我們可以在循環中使用另一個語句?continue。它會跳過其后的代碼回到循環開始處執行。這意味著它可以幫助你跳過部分循環。在下面的例子中,我們要求用戶輸入一個整數,如果輸入的是負數,那么我們會再次要求輸入,如果輸入的是整數,我們計算這個數的平方。用戶輸入 0 來跳出這個無限循環。

#!/usr/bin/env python3
while True:n = int(input("Please enter an Integer: "))if n < 0:continue # 這會返回到循環開始處執行elif n == 0:breakprint("Square is ", n ** 2)
print("Goodbye")

運行程序:

此處輸入圖片的描述

循環的 else 語句

我們可以在循環后面使用可選的?else?語句。它將會在循環完畢后執行,除非有?break?語句終止了循環。

>>> for i in range(0, 5):
...     print(i)
... else:
...     print("Bye bye")
...
0
1
2
3
4
Bye bye

在本課程的后續內容中,我們會看到更多有關?break?和?continue?的例子。

棍子游戲

這是一個非常簡單的游戲。這里有 21 根棍子,首先用戶選 1 到 4 根棍子,然后電腦選 1 到 4 根棍子。誰選到最后一根棍子誰就輸。判斷一下用戶有贏的機會嗎?如果沒有的話,如何修改游戲規則可以使用戶有贏的機會呢?

特別說明:用戶和電腦一次選的棍子總數只能是 5。

#!/usr/bin/env python3
sticks = 21print("There are 21 sticks, you can take 1-4 number of sticks at a time.")
print("Whoever will take the last stick will lose")while True:print("Sticks left: " , sticks)if sticks == 1:print("You took the last stick, you lose")breaksticks_taken = int(input("Take sticks(1-4):"))if sticks_taken >= 5 or sticks_taken <= 0:print("Wrong choice")continueprint("Computer took: " , (5 - sticks_taken) , "\n")sticks -= 5

總結

這個實驗中我們了解了兩種循環:while?和?for?循環,其中的?for?循環我們通常與?range()?函數配合使用,要特別注意的是,range()?函數返回的并不是列表而是一種可迭代對象:

此處輸入圖片的描述

python 中?for?循環的?else?子句給我們提供了檢測循環是否順利執行完畢的一種優雅方法。

數據結構

Python 有許多內建的數據結構。如果你困惑于什么是數據結構,那么可以參考一下?Wikipedia。

簡單的來說,數據結構(data structure)是計算機中存儲、組織數據的方式。比如我們之前的課程中使用過的列表就是一種數據結構,在這里我們還會深入學習它。

知識點
  • 列表的方法與列表元素的刪除
  • 將列表用作棧和隊列
  • 列表推導式
  • 元組、集合、字典的創建與操作
  • enumerate()?和?zip()?函數

列表

>>> a = [23, 45, 1, -3434, 43624356, 234]
>>> a.append(45)
>>> a
[23, 45, 1, -3434, 43624356, 234, 45]

首先我們建立了一個列表?a。然后調用列表的方法?a.append(45)?添加元素?45?到列表末尾。你可以看到元素 45 已經添加到列表的末端了。有些時候我們需要將數據插入到列表的任何位置,這時我們可以使用列表的?insert()?方法。

>>> a.insert(0, 1) # 在列表索引 0 位置添加元素 1
>>> a
[1, 23, 45, 1, -3434, 43624356, 234, 45]
>>> a.insert(0, 111) # 在列表索引 0 位置添加元素 111
>>> a
[111, 1, 23, 45, 1, -3434, 43624356, 234, 45]

列表方法?count(s)?會返回列表元素中?s?的數量。我們來檢查一下?45?這個元素在列表中出現了多少次。

>>> a.count(45)
2

如果你想要在列表中移除任意指定值,你需要使用?remove()?方法。

>>> a.remove(234)
>>> a
[111, 1, 23, 45, 1, -3434, 43624356, 45]

現在我們反轉整個列表。

>>> a.reverse()
>>> a
[45, 43624356, -3434, 1, 45, 23, 1, 111]

怎樣將一個列表的所有元素添加到另一個列表的末尾呢,可以使用列表的?extend()?方法。

>>> b = [45, 56, 90]
>>> a.extend(b) # 添加 b 的元素而不是 b 本身
>>> a
[45, 43624356, -3434, 1, 45, 23, 1, 111, 45, 56, 90]

給列表排序,我們使用列表的?sort()?方法,排序的前提是列表的元素是可比較的。

>>> a.sort()
>>> a
[-3434, 1, 1, 23, 45, 45, 45, 56, 90, 111, 43624356]

你也能使用?del?關鍵字刪除指定位置的列表元素。

>>> del a[-1]
>>> a
[-3434, 1, 1, 23, 45, 45, 45, 56, 90, 111]

將列表用作棧和隊列

棧是我們通常所說的一種?LIFO?(Last In First Out 后進先出)數據結構。它的意思是最后進入的數據第一個出來。一個最簡單的例子往一端封閉的管道放入一些彈珠然后取出來,如果你想把彈珠取出來,你必須從你最后放入彈珠的位置挨個拿出來。用代碼實現此原理:

>>> a = [1, 2, 3, 4, 5, 6]
>>> a
[1, 2, 3, 4, 5, 6]
>>> a.pop()
6
>>> a.pop()
5
>>> a.pop()
4
>>> a.pop()
3
>>> a
[1, 2]
>>> a.append(34)
>>> a
[1, 2, 34]

上面的代碼中我們使用了一個新方法?pop()。傳入一個參數 i 即?pop(i)?會將第 i 個元素彈出。

在我們的日常生活中會經常遇到隊列,比如售票窗口、圖書館、超市的結賬出口。隊列?是一種在末尾追加數據以及在開始彈出數據的數據結構。與棧不同,它是?FIFO?(First In First Out 先進先出)的數據結構。

>>> a = [1, 2, 3, 4, 5]
>>> a.append(1)
>>> a
[1, 2, 3, 4, 5, 1]
>>> a.pop(0)
1
>>> a.pop(0)
2
>>> a
[3, 4, 5, 1]

我們使用?a.pop(0)?彈出列表中第一個元素。

列表推導式

列表推導式為從序列中創建列表提供了一個簡單的方法。如果沒有列表推導式,一般都是這樣創建列表的:通過將一些操作應用于序列的每個成員并通過返回的元素創建列表,或者通過滿足特定條件的元素創建子序列。

假設我們創建一個 squares 列表,可以像下面這樣創建。

>>> squares = []
>>> for x in range(10):
...     squares.append(x**2)
...
>>> squares
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

注意這個 for 循環中的被創建(或被重寫)的名為 ?x? 的變量在循環完畢后依然存在。使用如下方法,我們可以計算 squares 的值而不會產生任何的副作用:。

squares = list(map(lambda x: x**2, range(10)))

等價于下面的列表推導式。

squares = [x**2 for x in range(10)]

上面這個方法更加簡明且易讀。

列表推導式由包含一個表達式的中括號組成,表達式后面跟隨一個 ?for 子句,之后可以有零或多個 ?for? 或 ?if? 子句。結果是一個列表,由表達式依據其后面的 for? 和 ?if? 子句上下文計算而來的結果構成。

例如,如下的列表推導式結合兩個列表的元素,如果元素之間不相等的話:

>>> [(x, y) for x in [1,2,3] for y in [3,1,4] if x != y]
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]

等同于:

>>> combs = []
>>> for x in [1,2,3]:
...     for y in [3,1,4]:
...         if x != y:
...             combs.append((x, y))
...
>>> combs
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]

值得注意的是在上面兩個方法中的 for? 和 if 語句的順序。

列表推導式也可以嵌套。

>>> a=[1,2,3]
>>> z = [x + 1 for x in [x ** 2 for x in a]]
>>> z
[2, 5, 10]

元組

元組是由數個逗號分割的值組成。

>>> a = 'Fedora', 'ShiYanLou', 'Kubuntu', 'Pardus'
>>> a
('Fedora', 'ShiYanLou', 'Kubuntu', 'Pardus')
>>> a[1]
'ShiYanLou'
>>> for x in a:
...     print(x, end=' ')
...
Fedora ShiYanLou Kubuntu Pardus

你可以對任何一個元組執行拆封操作并賦值給多個變量,就像下面這樣:

>>> divmod(15,2)
(7, 1)
>>> x, y = divmod(15,2)
>>> x
7
>>> y
1

元組是不可變類型,這意味著你不能在元組內刪除或添加或編輯任何值。如果你嘗試這些操作,將會出錯:

>>> a = (1, 2, 3, 4)
>>> del a[0]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object doesn't support item deletion

要創建只含有一個元素的元組,在值后面跟一個逗號。

>>> a = (123)
>>> a
123
>>> type(a)
<class 'int'>
>>> a = (123, )
>>> b = 321,
>>> a
(123,)
>>> b
(321,)
>>> type(a)
<class 'tuple'>
>>> type(b)
<class 'tuple'>

通過內建函數?type()?你可以知道任意變量的數據類型。還記得我們使用?len()?函數來查詢任意序列類型數據的長度嗎?

>>> type(len)
<class 'builtin_function_or_method'>

集合

集合是一個無序不重復元素的集。基本功能包括關系測試和消除重復元素。集合對象還支持 union(聯合),intersection(交),difference(差)和 symmetric difference(對稱差集)等數學運算。

大括號或 set() 函數可以用來創建集合。注意:想要創建空集合,你必須使用 set() 而不是 {}。后者用于創建空字典,我們在下一節中介紹的一種數據結構。

下面是集合的常見操作:

>>> basket = {'apple', 'orange', 'apple', 'pear', 'orange', 'banana'}
>>> print(basket)                      # 你可以看到重復的元素被去除
{'orange', 'banana', 'pear', 'apple'}
>>> 'orange' in basket
True
>>> 'crabgrass' in basket
False>>> # 演示對兩個單詞中的字母進行集合操作
...
>>> a = set('abracadabra')
>>> b = set('alacazam')
>>> a                                  # a 去重后的字母
{'a', 'r', 'b', 'c', 'd'}
>>> a - b                              # a 有而 b 沒有的字母
{'r', 'd', 'b'}
>>> a | b                              # 存在于 a 或 b 的字母
{'a', 'c', 'r', 'd', 'b', 'm', 'z', 'l'}
>>> a & b                              # a 和 b 都有的字母
{'a', 'c'}
>>> a ^ b                              # 存在于 a 或 b 但不同時存在的字母
{'r', 'd', 'b', 'm', 'z', 'l'}

從集合中添加或彈出元素:

>>> a = {'a','e','h','g'}
>>> a.pop()  # pop 方法隨機刪除一個元素并打印
'h'
>>> a.add('c')
>>> a
{'c', 'e', 'g', 'a'}

字典

字典是無序的鍵值對(key:value)集合,同一個字典內的鍵必須是互不相同的。一對大括號?{}?創建一個空字典。初始化字典時,在大括號內放置一組逗號分隔的鍵:值對,這也是字典輸出的方式。我們使用鍵來檢索存儲在字典中的數據。

>>> data = {'kushal':'Fedora', 'kart_':'Debian', 'Jace':'Mac'}
>>> data
{'kushal': 'Fedora', 'Jace': 'Mac', 'kart_': 'Debian'}
>>> data['kart_']
'Debian'

創建新的鍵值對很簡單:

>>> data['parthan'] = 'Ubuntu'
>>> data
{'kushal': 'Fedora', 'Jace': 'Mac', 'kart_': 'Debian', 'parthan': 'Ubuntu'}

使用?del?關鍵字刪除任意指定的鍵值對:

>>> del data['kushal']
>>> data
{'Jace': 'Mac', 'kart_': 'Debian', 'parthan': 'Ubuntu'

使用?in?關鍵字查詢指定的鍵是否存在于字典中。

>>> 'ShiYanLou' in data
False

必須知道的是,字典中的鍵必須是不可變類型,比如你不能使用列表作為鍵。

dict()?可以從包含鍵值對的元組中創建字典。

>>> dict((('Indian','Delhi'),('Bangladesh','Dhaka')))
{'Indian': 'Delhi', 'Bangladesh': 'Dhaka'}

如果你想要遍歷一個字典,使用字典的?items()?方法。

>>> data
{'Kushal': 'Fedora', 'Jace': 'Mac', 'kart_': 'Debian', 'parthan': 'Ubuntu'}
>>> for x, y in data.items():
...     print("{} uses {}".format(x, y))
...
Kushal uses Fedora
Jace uses Mac
kart_ uses Debian
parthan uses Ubuntu

許多時候我們需要往字典中的元素添加數據,我們首先要判斷這個元素是否存在,不存在則創建一個默認值。如果在循環里執行這個操作,每次迭代都需要判斷一次,降低程序性能。

我們可以使用?dict.setdefault(key, default)?更有效率的完成這個事情。

>>> data = {}
>>> data.setdefault('names', []).append('Ruby')
>>> data
{'names': ['Ruby']}
>>> data.setdefault('names', []).append('Python')
>>> data
{'names': ['Ruby', 'Python']}
>>> data.setdefault('names', []).append('C')
>>> data
{'names': ['Ruby', 'Python', 'C']}

試圖索引一個不存在的鍵將會拋出一個?keyError?錯誤。我們可以使用?dict.get(key, default)?來索引鍵,如果鍵不存在,那么返回指定的 default 值。

>>> data['foo']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'foo'
>>> data.get('foo', 0)
0

如果你想要在遍歷列表(或任何序列類型)的同時獲得元素索引值,你可以使用?enumerate()

>>> for i, j in enumerate(['a', 'b', 'c']):
...     print(i, j)
...
0 a
1 b
2 c

你也許需要同時遍歷兩個序列類型,你可以使用?zip()?函數。

>>> a = ['Pradeepto', 'Kushal']
>>> b = ['OpenSUSE', 'Fedora']
>>> for x, y in zip(a, b):
...     print("{} uses {}".format(x, y))
...
Pradeepto uses OpenSUSE
Kushal uses Fedora

程序示例

本節實驗將會通過兩個實例程序來熟悉 Python3 的基本數據結構:

  1. 判斷學生成績是否達標的程序
  2. 計算兩個矩陣的 Hadamard 乘積

students.py

這是一個判斷學生成績是否達標的程序,要求輸入學生數量,以及各個學生物理、數學、歷史三科的成績,如果總成績小于 120,程序打印 “failed”,否則打印 “passed”。

代碼寫入?/home/shiyanlou/students.py?文件:

#!/usr/bin/env python3
n = int(input("Enter the number of students: "))
data = {} # 用來存儲數據的字典變量
Subjects = ('Physics', 'Maths', 'History') # 所有科目
for i in range(0, n):name = input('Enter the name of the student {}: '.format(i + 1)) # 獲得學生名稱marks = []for x in Subjects:marks.append(int(input('Enter marks of {}: '.format(x)))) # 獲得每一科的分數data[name] = marks
for x, y in data.items():total =  sum(y)print("{}'s total marks {}".format(x, total))if total < 120:print(x, "failed :(")else:print(x, "passed :)")

name 和 marks 是變量,name 用來存儲學生的名稱,marks 是個列表,用來存儲輸入的學生的成績數據。

data 是個字典,字典的鍵值對中,鍵指的是 name 的值,值指的是 marks 的值。因此會使用?data[name] = marks?將學生數據存入到 data 字典。

最后通過 for 循環遍歷字典,x 為學生的 name,y 為學生成績列表 marks,sum()?函數會將傳入的列表進行加和。

運行如下:

此處輸入圖片的描述

matrixmul.py

這個例子里我們計算兩個矩陣的 Hadamard 乘積。要求輸入矩陣的行/列數(在這里假設我們使用的是 n × n 的矩陣)。

代碼寫入?/home/shiyanlou/matrixmul.py?文件:

#!/usr/bin/env python3
n = int(input("Enter the value of n: "))
print("Enter values for the Matrix A")
a = []
for i in range(n):a.append([int(x) for x in input().split()])
print("Enter values for the Matrix B")
b = []
for i in range(n):b.append([int(x) for x in input().split()])
c = []
for i in range(n):c.append([a[i][j] * b[i][j] for j in range(n)])
print("After matrix multiplication")
print("-" * 7 * n)
for x in c:for y in x:print(str(y).rjust(5), end=' ')print()
print("-" * 7 * n)

運行如下:

此處輸入圖片的描述

這里我們使用了幾次列表推導式。[int(x) for x in input().split()]?首先通過?input()?獲得用戶輸入的字符串,再使用?split()?分割字符串得到一系列的數字字符串,然后用?int()?從每個數字字符串創建對應的整數值。我們也使用了?[a[i][j] * b[i][j] for j in range(n)]?來得到矩陣乘積的每一行數據。

總結

本實驗了解了 Python 內置的幾種常用數據結構,在寫程序的過程中,不同的場景應當選取合適的數據結構。

一般來說,目前我們見到的數據結構已經夠用了,不過 Python 中還有一些其它有用的數據結構,可以在這里了解:Data Types — Python 3.12.4 documentation。

字符串

字符串是 Python 中最常用的數據類型。本節實驗將會學習如何對 Python3 的字符串進行處理操作。

知識點
  • 字符串的 3 種表示
  • 字符串的分割、連接、大小寫轉換、搜索等常用操作

字符串表示

可以通過幾種不同的方式表示字符串。如單引號('...')或雙引號("...")。下面的例子能幫助你更好的理解字符串。

>>> s = "I am Chinese"
>>> s
'I am Chinese'
>>> s = 'I am Chinese'
>>> s = "Here is a line \
... split in two lines"
>>> s
'Here is a line split in two lines'
>>> s = "Here is a line \n split in two lines"
>>> s
'Here is a line \n split in two lines'
>>> print(s)
Here is a linesplit in two lines

如果你想要分幾行輸入字符串,并且希望行尾的換行符自動包含到字符串當中,可以使用三對引號:"""..."""?或?'''...'''?。

>>> print("""\
... Usage: thingy [OPTIONS]
...      -h                        Display this usage message
...      -H hostname               Hostname to connect to
... """)
Usage: thingy [OPTIONS]-h                        Display this usage message-H hostname               Hostname to connect to

字符串的方法

每一個字符串對象都有幾個可用的內建方法,我們已經使用過一些了,比如?s.split()

>>> s = "shi yan lou"
>>> s.title()
'Shi Yan Lou'

方法?title()?返回字符串的標題版本,即單詞首字母大寫其余字母小寫。

>>> z = s.upper()
>>> z
'SHI YAN LOU'
>>> z.lower()
'shi yan lou'

方法?upper()?返回字符串全部大寫的版本,反之?lower()?返回字符串的全部小寫版本。

>>> s = "I am A pRoGraMMer"
>> s.swapcase()
'i AM a PrOgRAmmER'

方法?swapcase()?返回字符串大小寫交換后的版本 :)

>>> s = "jdwb 2323bjb"
>>> s.isalnum()
False
>>> s = "jdwb2323bjb"
>>> s.isalnum()
True

方法?isalnum()?檢查所有字符是否只有字母和數字,上面的代碼中第一行的字符串?s?中包含空格字符,所以返回?False

>>> s = "SankarshanSir"
>>> s.isalpha()
True
>>> s = "Sankarshan Sir"
>>> s.isalpha()
False

方法?isalpha()?檢查字符串之中是否只有字母。

>>> s = "1234"
>>> s.isdigit() # 檢查字符串是否所有字符為數字
True
>>> s = "ShiYanLou is coming"
>>> s.islower() # 檢查字符串是否所有字符為小寫
False
>>> s = "Shiyanlou Is Coming"
>>> s.istitle() # To 檢查字符串是否為標題樣式
True
>>> s = "CHINA"
>>> s.isupper() # 檢查字符串是否所有字符為大寫
True

我們可以使用?split()?分割任意字符串,split()?允許有一個參數,用來指定字符串以什么字符分隔(默認為?" "),它返回一個包含所有分割后的字符串的列表。

>>> s = "We all love Python"
>>> s.split()
['We', 'all', 'love', 'Python']
>>> x = "shiyanlou:is:waiting"
>>> x.split(':')
['shiyanlou', 'is', 'waiting']

相反的,方法?join()?使用指定字符連接多個字符串,它需要一個包含字符串元素的列表作為輸入然后連接列表內的字符串元素。

>>> "-".join("GNU/Linux is great".split())
'GNU/Linux-is-great'

在上面的例子中,我們基于空格?" "?分割字符串?"GNU/Linux is great",然后用?"-"?連接它們。

字符串剝離

字符串有幾個進行剝離操作的方法。最簡單的一個是?strip(chars),用來剝離字符串首尾中指定的字符,它允許有一個字符串參數,這個參數為剝離哪些字符提供依據。不指定參數則默認剝離掉首尾的空格和換行符,代碼如下:

>>> s = "  a bc\n "
>>> s.strip()
'a bc'

你可以使用?lstrip(chars)?或?rstrip(chars)?只對字符串左或右剝離。

>>> s = "www.foss.in"
>>> s.lstrip("cwsd.") #刪除在字符串左邊出現的'c','w','s','d','.'字符
'foss.in'
>>> s.rstrip("cnwdi.") #刪除在字符串右邊出現的'c','n','w','d','i','.'字符
'www.foss'

文本搜索

字符串有一些方法能夠幫助你搜索字符串里的文本或子字符串。下面給出示例:

>>> s = "faulty for a reason"
>>> s.find("for")
7
>>> s.find("fora")
-1
>>> s.startswith("fa") # 檢查字符串是否以 fa 開頭
True
>>> s.endswith("reason") # 檢查字符串是否以 reason 結尾
True

find()?能幫助你找到第一個匹配的子字符串,沒有找到則返回 -1。

回文檢查

回文是一種無論從左還是從右讀都一樣的字符序列。比如 “madam”。在這個例子中,我們檢查用戶輸入的字符串是否是回文,并輸出結果。

代碼寫入文件?/home/shiyanlou/palindrome.py

#!/usr/bin/env python3
s = input("Please enter a string: ")
z = s[::-1]  #把輸入的字符串s 進行倒序處理形成新的字符串z
if s == z:print("The string is a palindrome")
else:print("The string is not a palindrome")

運行程序:

此處輸入圖片的描述

單詞計數

在講解單詞計數之前我們先了解一個概念:格式化操作符(%)。

我們先看下面的這個例子:

print("my name is %s.I am %d years old" % ('Shixiaolou',4))

此處輸入圖片的描述

在這個例子中,%s?為第一個格式符,表示一個字符串;%d?為第二個格式符,表示一個整數。格式符為真實值預留位置,并控制顯示的格式。常用的有:

  • %s?字符串(用 str() 函數進行字符串轉換)
  • %r?字符串(用 repr() 函數進行字符串轉換)
  • %d?十進制整數
  • %f?浮點數
  • %%?字符?%

那么接下來我們對用戶輸入的一行文本進行單詞計數。

代碼寫入文件?/home/shiyanlou/countwords.py

#!/usr/bin/env python3
s = input("Enter a line: ")
print("The number of words in the line are %d" % (len(s.split(" "))))

運行程序:

此處輸入圖片的描述

總結

回顧本節實驗的知識點:

  • 字符串的 3 種表示
  • 字符串的分割、連接、大小寫轉換、搜索等常用操作

本實驗學習了字符串的幾種表示方法(3 種引號)以及對字符串的各種常用操作(分割、連接、大小寫轉換、搜索...),應當熟練掌握它們。

單詞計數的實例需要仔細理解,字符串的更多用法在實驗樓的項目實驗中也都會涉及到。

函數

我們經常需要在同一個程序里多次復用代碼。函數可以很好的幫助我們完成這一點。我們在函數里寫我們要重復做的事,然后我們在任何需要的時候調用它。我們已經看到一些內建的函數,比如?len()divmod()

知識點
  • 函數的定義
  • 局部/全局變量的概念
  • 默認參數,關鍵字參數及強制關鍵字參數
  • 文檔字符串的使用
  • 高階函數,map() 函數

定義一個函數

我們使用關鍵字?def?來定義一個函數,語法描述如下所示:

def 函數名(參數):語句1語句2

讓我們編寫一個函數,它將接受兩個整數作為輸入,然后返回總和。

>>> def sum(a, b):
...     return a + b

第二行有個?return?關鍵字,我們把?a + b?的值返回給調用者。

你必須像下面這樣調用這個函數。

>>> res = sum(234234, 34453546464)
>>> res
34453780698L

還記得我們上一個實驗講過的回文檢查程序么,讓我們編寫一個函數來檢查給出的字符串是否為回文,然后返回?True?或者?False

#!/usr/bin/env python3
def palindrome(s):return s == s[::-1]
if __name__ == '__main__':s = input("Enter a string: ")if palindrome(s):print("Yay a palindrome")else:print("Oh no, not a palindrome")

將上述代碼寫入到 testpalindrome.py 文件,執行如下:

python3 testpalindrome.py
Enter a string: test111
Oh no, not a palindromepython3 testpalindrome.py
Enter a string: 1234321
Yay a palindrome

局域或全局變量

我們通過幾個例子來弄明白局域或全局變量,首先我們在函數內部和函數調用的代碼中都使用同一個變量 a,將下方代碼寫入?/home/shiyanlou/local.py

#!/usr/bin/env python3
def change():a = 90print(a)
a = 9
print("Before the function call ", a)
print("inside change function", end=' ')
change()
print("After the function call ", a)

運行程序:

此處輸入圖片的描述

首先我們對?a?賦值 9,然后調用更改函數,這個函數里我們對?a?賦值 90,然后打印?a?的值。調用函數后我們再次打印?a?的值。

當我們在函數里寫?a = 90?時,它實際上創建了一個新的名為?a?的局部變量,這個變量只在函數里可用,并且會在函數完成時銷毀。所以即使這兩個變量的名字都相同,但事實上他們并不是同一個變量。

那么如果我們先定義?a,在函數中是否可以直接使用呢?

例如下面這段代碼:

#!/usr/bin/env python3
a = 9
def change():print(a)
change()

這段代碼是沒有問題的,可以直接打印輸出 9。稍微改動一下:

#!/usr/bin/env python3
a = 9
def change():print(a)a = 100
change()

現在就會報錯了:“UnboundLocalError: local variable 'a' referenced before assignment”,原因是當函數中只要用到了變量 a,并且 a 出現在表達式?=?的前面,就會被當作局部變量。當執行到?print(a)?的時候會報錯,因為 a 作為函數局部變量是在?print(a)?之后才定義的。

現在我們使用?global?關鍵字,對函數中的?a?標志為全局變量,讓函數內部使用全局變量的 a,那么整個程序中出現的?a?都將是這個:

#!/usr/bin/env python3
a = 9
def change():global aprint(a)a = 100
print("Before the function call ", a)
print("inside change function", end=' ')
change()
print("After the function call ", a)

程序中的?end=' '?參數表示,print 打印后的結尾不用換行,而用空格。默認情況下 print 打印后會在結尾換行。

程序執行的結果,不會報錯了,因為函數體內可以訪問全局的變量?a

Before the function call  9
inside change function 9
After the function call  100

在函數內使用?global?會有什么作用呢?嘗試下面的代碼:

#!/usr/bin/env python3
def change():global aa = 90print(a)
a = 9
print("Before the function call ", a)
print("inside change function", end=' ')
change()
print("After the function call ", a)

程序執行的結果:

Before the function call  9
inside change function 90
After the function call  90

這里通過關鍵字?global?來告訴 a 的定義是全局的,因此在函數內部更改了?a?的值,函數外?a?的值也實際上更改了。

運行程序:

此處輸入圖片的描述

默認參數值

函數的參數變量可以有默認值,也就是說如果我們在調用函數時對指定的參數變量沒有給出任何值則會賦其默認值。

>>> def test(a , b=-99):
...     if a > b:
...         return True
...     else:
...         return False

在上面的例子里,我們在函數的參數列表寫出?b = -99。這表示如果調用者未給出?b?的值,那么?b?的值默認為?-99。這是一個關于默認參數的非常簡單的例子。

你可以通過調用函數測試代碼。

>>> test(12, 23)
False
>>> test(12)
True

有兩個非常重要的地方,第一個是具有默認值的參數后面不能再有普通參數,比如?f(a,b=90,c)?就是錯誤的。

第二個是默認值只被賦值一次,因此如果默認值是任何可變對象時會有所不同,比如列表、字典或大多數類的實例。例如,下面的函數在后續調用過程中會累積(前面)傳給它的參數:

>>> def f(a, data=[]):
...     data.append(a)
...     return data
...
>>> print(f(1))
[1]
>>> print(f(2))
[1, 2]
>>> print(f(3))
[1, 2, 3]

要避免這個問題,你可以像下面這樣:

>>> def f(a, data=None):
...     if data is None:
...         data = []
...     data.append(a)
...     return data
...
>>> print(f(1))
[1]
>>> print(f(2))
[2]

關鍵字參數

函數可以通過關鍵字參數的形式來調用,形如?keyword = value。如下:

>>> def func(a, b=5, c=10):
...     print('a is', a, 'and b is', b, 'and c is', c)
...
>>> func(12, 24)
a is 12 and b is 24 and c is 10
>>> func(12, c = 24)
a is 12 and b is 5 and c is 24
>>> func(b = 12, c = 24, a = -1)
a is -1 and b is 12 and c is 24

在上面的例子中你能看見調用函數時使用了變量名,比如?func(12,c = 24),這樣我們將?24?賦給?c?且?b?具有默認值。

強制關鍵字參數

我們也能將函數的參數標記為只允許使用關鍵字參數。用戶調用函數時將只能對每一個參數使用相應的關鍵字參數。

>>> def hello(*, name='User'):
...     print("Hello", name)
...
>>> hello('shiyanlou')
Traceback (most recent call last):File "<stdin>", line 1, in <module>
TypeError: hello() takes 0 positional arguments but 1 was given
>>> hello(name='shiyanlou')
Hello shiyanlou

了解更多,請閱讀PEP-3102。

文檔字符串

在 Python 里我們使用文檔字符串(_docstrings_)來說明如何使用代碼,這在交互模式非常有用,也能用于自動創建文檔。下面我們來看看使用文檔字符串的例子。

#!/usr/bin/env python3
import mathdef longest_side(a, b):"""Function to find the length of the longest side of a right triangle.:arg a: Side a of the triangle:arg b: Side b of the triangle:return: Length of the longest side c as float"""return math.sqrt(a*a + b*b)if __name__ == '__main__':print(longest_side.__doc__)print(longest_side(4,5))

運行程序:

此處輸入圖片的描述

高階函數

高階函數(_Higher-order function_)或仿函數(_functor_)是可以接受函數作為參數的函數:

  • 使用一個或多個函數作為參數
  • 返回另一個函數作為輸出

Python 里的任何函數都可以作為高階函數,下面舉一個簡單的例子:

# 創建一個函數,將參數列表中每個元素都變成全大寫
>>> def high(l):
...     return [i.upper() for i in l]
...
# 創建高階函數,接受一個函數和一個列表作為參數
>>> def test(h, l):
...     return h(l)
...
>>> l = ['python', 'Linux', 'Git']
# 運行高階函數,返回預期的結果
>>> test(high, l)
['PYTHON', 'LINUX', 'GIT']

閱讀官方文檔了解更多。

map 函數

map?是一個在 Python 里非常有用的高階函數。它接受一個函數和一個序列(迭代器)作為輸入,然后對序列(迭代器)的每一個值應用這個函數,返回一個序列(迭代器),其包含應用函數后的結果。

舉例:

>>> lst = [1, 2, 3, 4, 5]
>>> def square(num):
...     "返回所給數字的平方."
...     return num * num
...
>>> print(list(map(square, lst)))
[1, 4, 9, 16, 25]

總結

經過本實驗應當知道如何定義函數,局域變量和全局變量一定要弄清楚,參數默認值、關鍵字參數也需要掌握。

另外,其它高級語言常見的函數重載,Python 是沒有的,這是因為 Python 有默認參數這個功能,函數重載?的功能大都可以使用默認參數達到。

在后面我們還介紹了高階函數的概念并使用了?map()?函數。在 Python 中還有其它的高階函數,如?sorted()、filter()?以及?functools?模塊中的函數,大家可以了解一下。

文件處理

文件是保存在計算機存儲設備上的一些信息或數據。你已經知道了一些不同的文件類型,比如你的音樂文件,視頻文件,文本文件。Python 給了你一些簡單的方式操縱文件。通常我們把文件分為兩類,文本文件和二進制文件。文本文件是簡單的文本,二進制文件包含了只有計算機可讀的二進制數據。

知識點
  • 文件打開模式
  • 文件讀取與寫入
  • with?語句

文件操作

本部分會實踐學習以下的知識:

  1. 文件打開與關閉
  2. 文件讀取與寫入

所有的實例程序都需要你在實驗環境中完整的輸入并執行。

文件打開

我們使用?open()?函數打開文件。它需要兩個參數,第一個參數是文件路徑或文件名,第二個是文件的打開模式。模式通常是下面這樣的:

  • "r",以只讀模式打開,你只能讀取文件但不能編輯/刪除文件的任何內容
  • "w",以寫入模式打開,如果文件存在將會刪除里面的所有內容,然后打開這個文件進行寫入
  • "a",以追加模式打開,寫入到文件中的任何數據將自動添加到末尾

默認的模式為只讀模式,也就是說如果你不提供任何模式,open()?函數將會以只讀模式打開文件。我們將實驗打開一個文件,不過要準備實驗材料:

wget https://labfile.oss-internal.aliyuncs.com/courses/596/sample.txt

此處輸入圖片的描述

然后進入 Python3 打開這個文件。

>>> fobj = open("sample.txt")
>>> fobj
<_io.TextIOWrapper name='sample.txt' mode='r' encoding='UTF-8'>

文件關閉

打開文件后我們應該總是關閉文件。我們使用方法?close()?完成這個操作。

>>> fobj.close()

始終確保你顯式關閉每個打開的文件,一旦它的工作完成你沒有任何理由保持打開文件。因為程序能打開的文件數量是有上限的。如果你超出了這個限制,沒有任何可靠的方法恢復,因此程序可能會崩潰。每個打開的文件關聯的數據結構(文件描述符/句柄/文件鎖...)都要消耗一些主存資源。因此如果許多打開的文件沒用了你可以結束大量的內存浪費,并且文件打開時始終存在數據損壞或丟失的可能性。

文件讀取

使用?read()?方法一次性讀取整個文件。

>>> fobj = open("sample.txt")
>>> fobj.read()
'I love Python\nI love shiyanlou\n'
>>> fobj.close()

如果你再一次調用?read(),它會返回空字符串因為它已經讀取完整個文件。

read(size)?有一個可選的參數?size,用于指定字符串長度。如果沒有指定?size? 或者指定為負數,就會讀取并返回整個文件。當文件大小為當前機器內存兩倍時,就會產生問題。反之,會盡可能按比較大的 ?size? 讀取和返回數據。

readline()?能幫助你每次讀取文件的一行。

>>> fobj = open("sample.txt")
>>> fobj.readline()
'I love Python\n'
>>> fobj.readline()
'I love shiyanlou\n'
>>> fobj.close()

使用?readlines()?方法讀取所有行到一個列表中。

>>> fobj = open('sample.txt')
>>> fobj.readlines()
['I love Python\n', 'I love shiyanlou\n']
>>> fobj.close()

你可以循環遍歷文件對象來讀取文件中的每一行。

>>> fobj = open('sample.txt')
>>> for x in fobj:
...     print(x, end = '')
...
I love Python
I love shiyanlou
>>> fobj.close()

讓我們寫一個程序,這個程序接受用戶輸入的字符串作為將要讀取的文件的文件名,并且在屏幕上打印文件內容。

#!/usr/bin/env python3
name = input("Enter the file name: ")
fobj = open(name)
print(fobj.read())
fobj.close()

運行程序:

cd /home/shiyanlou
chmod +x test.py
./test.py
Enter the file name: sample.txt
I love Python
I love shiyanlou

文件寫入

讓我們通過?write()?方法打開一個文件然后我們隨便寫入一些文本。

>>> fobj = open("ircnicks.txt", 'w')
>>> fobj.write('powerpork\n')
>>> fobj.write('indrag\n')
>>> fobj.write('mishti\n')
>>> fobj.write('sankarshan')
>>> fobj.close()

現在讀取我們剛剛創建的文件。

>>> fobj = open('ircnicks.txt')
>>> s = fobj.read()
>>> fobj.close()
>>> print(s)
powerpork
indrag
mishti
sankarshan

文件操作示例程序

本部分實驗將通過兩個實例程序來實踐之前學習的文件操作方法:

  1. 拷貝文件程序
  2. 文本文件信息統計程序

所有的實例程序都需要你在實驗環境中完整的輸入并執行。

拷貝文件

在這個例子里我們拷貝給定的文本文件到另一個給定的文本文件。

#!/usr/bin/env python3
import sys
if len(sys.argv) < 3:print("Wrong parameter")print("./copyfile.py file1 file2")sys.exit(1)
f1 = open(sys.argv[1])
s = f1.read()
f1.close()
f2 = open(sys.argv[2], 'w')
f2.write(s)
f2.close()

運行程序:

圖片描述

你可以看到我們在這里使用了一個新模塊?syssys.argv?包含所有命令行參數。這個程序的功能完全可以使用 shell 的?cp?命令替代:在?cp?后首先輸入被拷貝的文件的文件名,然后輸入新文件名。

sys.argv?的第一個值是命令自身的名字,下面這個程序打印命令行參數。

#!/usr/bin/env python3
import sys
print("First value", sys.argv[0])
print("All values")
for i, x  in enumerate(sys.argv):print(i, x)

運行程序:

./argvtest.py Hi there
First value ./argvtest.py
All values
0 ./argvtest.py
1 Hi
2 there

這里我們用到了一個新函數?enumerate(iterableobject),在序列中循環時,索引位置和對應值可以使用它同時得到。

文本文件相關信息統計

讓我們試著編寫一個程序,對任意給定文本文件中的制表符、行、空格進行計數。

代碼寫入文件?/home/shiyanlou/parsefile.py

#!/usr/bin/env python3import os
import sysdef parse_file(path):"""分析給定文本文件,返回其空格、制表符、行的相關信息:arg path: 要分析的文本文件的路徑:return: 包含空格數、制表符數、行數的元組"""fd = open(path)i = 0spaces = 0tabs = 0for i,line in enumerate(fd):spaces += line.count(' ')tabs += line.count('\t')# 現在關閉打開的文件fd.close()# 以元組形式返回結果return spaces, tabs, i + 1def main(path):"""函數用于打印文件分析結果:arg path: 要分析的文本文件的路徑:return: 若文件存在則為 True,否則 False"""if os.path.exists(path):spaces, tabs, lines = parse_file(path)print("Spaces {}. tabs {}. lines {}".format(spaces, tabs, lines))return Trueelse:return Falseif __name__ == '__main__':if len(sys.argv) > 1:main(sys.argv[1])else:sys.exit(-1)sys.exit(0)

運行程序:

此處輸入圖片的描述

你可以看到程序有兩個函數,main()?和?parse_file()?,parse_file?函數真正的分析文件并返回結果,然后在?main()?函數里打印結果。通過分割代碼到一些更小的單元(函數)里,能幫助我們組織代碼庫并且也更容易為函數編寫測試用例。

使用 with 語句

在實際情況中,我們應該嘗試使用?with?語句處理文件對象,它會在文件用完后會自動關閉,就算發生異常也沒關系。它是 try-finally 塊的簡寫:

>>> with open('sample.txt') as fobj:
...     for line in fobj:
...         print(line, end = '')
...
I love Python
I love shiyanlou

實現 lscpu 命令

在 Linux 下你可以使用?lscpu?命令來查看當前電腦的 CPU 相關信息,如下圖:

此處輸入圖片的描述

實際上?lscpu?命令是讀取?/proc/cpuinfo?這個文件的信息并美化輸出,現在你可以自己寫一個 Python 程序以只讀模式讀取?/proc/cpuinfo?這個文件,然后打印出來,這樣你就有自己的一個 Python 版本的?lscpu?命令了 :)

記得一行一行的讀取文本文件,不要一次性讀取整個文件,因為有時候你讀取的文件可能比可用內存還大。

總結

回顧本節實驗知識點:

  • 文件打開模式
  • 文件讀取與寫入
  • with?語句

本實驗我們學習了文件的打開與讀寫,在讀寫完畢后一定要記得關閉文件,或者使用 with 語句也是極好的。在 Linux 中你還需要注意你操作的文件的權限。Linux 有一個思想是“一切皆文件”,這在實驗最后的?lscpu?的實現中得到了體現。

挑戰:字符串操作

介紹

我們需要實現一個程序用來提取文件中的字符串中的數字,然后打印輸出。

目標

首先,打開 Xfce 終端,下載所需的測試文件:

cd /tmp
wget https://labfile.oss-internal.aliyuncs.com/courses/790/String.txt

這個文件?/tmp/String.txt?中存儲了一個很長的字符串,需要讀取并進行處理。

然后,我們在?/home/shiyanlou/Code?創建?FindDigits.py?Python 腳本:

cd /home/shiyanlou/Code
touch FindDigits.py

FindDigits.py?中,我們需要完成以下任務:

  1. 使用 open 打開文件?/tmp/String.txt?并讀取其中的字符串
  2. 提取字符串中的所有數字,并組合成一個新的字符串,然后打印輸出

程序執行過程如下:

python3 /home/shiyanlou/Code/FindDigits.py

提示語

  • 可以使用循環來訪問字符串中的單個字符
  • 可以使用?isdigit()?來判斷字符是否為數字
  • 使用?print()?把新的數字組成的字符串輸出
  • 代碼文件必須保存在?/home/shiyanlou/Code/FindDigits.py

知識點

  • 文件讀取
  • for 循環
  • 字符串操作

參考代碼

# 打開并讀取文件里的字符串
with open('/tmp/String.txt') as f:s = f.read()res = ""# 循環字符串里的每個字符,判斷是否為數字for char in s:if char.isdigit():res += charprint(res)

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/35978.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/35978.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/35978.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

數字孿生流域:定義、組成等

數字孿生流域&#xff1a;定義、組成等 1 數字孿生流域&#xff08;Digital Twin Basin/Watershed&#xff09;總則1.1 定義1.2 適用范圍1.3 建設目標1.4 建設原則 2 數字孿生流域框架與組成2.1 數字孿生流域框架2.2 數字孿生流域組成2.2.1 數字孿生平臺2.2.2 信息化基礎設施 3…

類的裝飾器

1 使用類定義裝飾器 class Person(object):def __init__(self):self._age 0propertydef age(self):return self._ageage.setterdef age(self,newValue):print(觸發了嗎)self._age newValuep Person() print(p.age) # 0 p.age 20 print(p.age) # 20 2 類屬性 class Pe…

JavaScript學習筆記(二)

12、數字 常規用法和java的用法相似&#xff0c;就不再做詳細的記錄, JavaScript 數字 以下只記錄特殊用法&#xff1a; 12.1 數字字符串運算 在所有數字運算中&#xff0c;JavaScript 會嘗試將字符串轉換為數字&#xff1a; var x "100"; var y "10"…

探索QCS6490目標檢測AI應用開發(一):Yolov8n模型轉換及量化

目標檢測&#xff08;Object Detection&#xff09;是計算機視覺領域的核心任務之一&#xff0c;它旨在識別圖像中的物體并確定其位置&#xff0c;在本期的文章中&#xff0c;我們用一個端到端的目標檢測AI應用為例子。介紹如何在QCS6490 Ubuntu系統上實現一個目標檢測應用開發…

第 5 章理解 ScrollView 并構建 Carousel UI

通過上一章的學習,我相信你現在應該明白如何使用堆棧構建復雜的 UI。當然,在你掌握 SwiftUI 之前,你還需要大量的練習。因此,在深入研究 ScrollView 以使視圖可滾動之前,讓我們先以一個挑戰開始本章。你的任務是創建一個類似于圖 1 所示的卡片視圖。 …

如何遷移R包

遷移R包涉及將一個或多個R包從一個系統轉移到另一個系統。以下是遷移R包的詳細步驟&#xff1a; 1. 確定要遷移的R包 首先&#xff0c;列出你在當前系統中安裝的所有R包&#xff0c;或僅列出你需要遷移的R包。你可以使用以下代碼列出所有安裝的R包&#xff1a; installed_pa…

swp添加池子addLiquidity失敗

案發現場 首次添加交易對、一直失敗、但是也沒提示具體的原因。到這一步就沒了、由下圖可知、也沒看到log、由此可見第一步就失敗了。 解決方案 一、添加 工廠KywFactory 添加如下 bytes32 public constant INIT_CODE_PAIR_HASH keccak256(abi.encodePacked(type(KywPair…

移植對話框MFC

VC版 MFC程序對話框資源移植 以下均拷貝自上面&#xff0c;僅用來記錄 &#xff08;部分有刪除&#xff09; 法1&#xff1a; Eg&#xff1a;將B工程調試好的對話框移植到A工程中 1.資源移植 1.1 在2017打開B工程,在工作區Resource標簽頁中選中Dialog文件夾下的資源文件,按…

注意!短視頻的致命誤區,云微客教你避開!

為什么你做短視頻就是干不過同行&#xff1f;因為你總想著拍劇情、段子這些娛樂視頻&#xff0c;還想著當網紅做IP人設&#xff0c;但是這些內容跟你的盈利沒有半毛錢關系&#xff0c;況且難度大、見效慢&#xff0c;還不是精準客戶。 以上這些就代表你走進了短視頻的誤區&…

C++初學者指南-2.輸入和輸出---流輸入和輸出

C初學者指南-2.輸入和輸出—流輸入和輸出 文章目錄 C初學者指南-2.輸入和輸出---流輸入和輸出1.定制輸入/輸出1.1 示例&#xff1a;點坐標輸入/輸出1.2 流操作符1.3&#xff08;一部分&#xff09;標準庫流類型 2. 工具2.1 用getline讀取行 2.2 用ignore進行跳轉2.3 格式化操作…

【論文閱讀】-- Temporal Summary Images:通過交互式注釋生成和放置實現敘事可視化的方法

Temporal Summary Images: An Approach to Narrative Visualization via Interactive Annotation Generation and Placement 摘要1 引言2 背景及相關工作2.1 敘事可視化和講故事2.2 顯示面向時間的數據2.3 小倍數和漫畫2.4 注釋可視化 3 設計要求和工作流程3.1 工作流程3.2 TSI…

基線核查--滲透

基線檢查 基線核查概念 it中定義&#xff1a; 基線為初始的標準&#xff0c;以后更改就要經過授權&#xff0c;形成下一基線。 軟件配置管理的基線&#xff1a;1功能基線&#xff0c;分配基線&#xff0c;產品基線 安全配置基線--基線核查 安全基線可以說是木桶理論&…

【python】eval函數

1.eval函數的語法及用法 &#xff08;1&#xff09;語法&#xff1a;eval(expression) 參數說明&#xff1a; expression&#xff1a;必須為字符串表達式&#xff0c;可為算法&#xff0c;也可為input函數等。 說明&#xff1a;表達式必需是字符串&#xff0c;否則會報錯&a…

Vue3-尚硅谷筆記

1. Vue3簡介 2020年9月18日&#xff0c;Vue.js發布版3.0版本&#xff0c;代號&#xff1a;One Piece&#xff08;n 經歷了&#xff1a;4800次提交、40個RFC、600次PR、300貢獻者 官方發版地址&#xff1a;Release v3.0.0 One Piece vuejs/core 截止2023年10月&#xff0c;最…

Dubbo運行原理

目錄 Dubbo通訊協議 Dubbo負載均衡策略 RPC和HTTP有什么區別&#xff1f; 讓你設計一個RPC框架&#xff0c;如何考慮數據序列化問題&#xff1f; Dubbo 是一款高性能、輕量級的開源 RPC&#xff08;遠程過程調用&#xff09;框架&#xff0c;主要用于構建分布式服務和微服務…

springcloud第4季 springcloud-alibaba之openfegin+sentinel整合案例

一 介紹說明 1.1 說明 1.1.1 消費者8081 1.1.2 openfegin接口 1.1.3 提供者9091 9091微服務滿足&#xff1a; 1 openfegin 配置fallback邏輯&#xff0c;作為統一fallback服務降級處理。 2.sentinel訪問觸發了自定義的限流配置&#xff0c;在注解sentinelResource里面配置…

基于SpringBoot的學生綜合測評系統

你好呀&#xff0c;我是計算機學姐碼農小野&#xff01;如果有相關需求&#xff0c;可以私信聯系我。 開發語言&#xff1a;Java 數據庫&#xff1a;MySQL 技術&#xff1a;SpringBoot框架 工具&#xff1a;MyEclipse、Tomcat 系統展示 首頁 系統首頁&#xff0c;提供綜合…

After Effects 2024 mac/win版:創意視效,夢想起航

After Effects 2024是一款引領視效革命的專業軟件&#xff0c;匯聚了創意與技術的精華。作為Adobe推出的全新版本&#xff0c;它以其強大的視頻處理和動畫創作能力&#xff0c;成為從事設計和視頻特技的機構&#xff0c;如電視臺、動畫制作公司、個人后期制作工作室以及多媒體工…

求職產品運營的個人簡歷案例(精選篇)

在求職產品運營的道路上&#xff0c;一份出色的個人簡歷是邁向成功的第一步&#xff0c;但是簡歷怎么寫才最好呢&#xff1f;下面是小編整理的求職產品運營的個人簡歷案例&#xff0c;同時&#xff0c;幻主簡歷網還提供精美簡歷模板下載和簡歷在線制作工具&#xff0c;歡迎大家…

Kivy tutorial 008: More kv language

Kivy tutorial 008: More kv language – Kivy Blog Central themes: Event binding and canvas instructions in kv language 中心主題: 事件綁定 和 kv語言里的畫布結構 This tutorial directly follows on from the previous, so start by retrieving the previous code, …