1. 程式人生 > 其它 >python 只取數值_Python入門教程 | 第 1 章 Python 基礎

python 只取數值_Python入門教程 | 第 1 章 Python 基礎

技術標籤:python 只取數值溫度轉換的python程式

第一章 Python 基礎

Python 非常適合初學者用來進入計算機程式設計領域。Python 屬於非常高階的語言,掌握了這門高階語言,就對計算機程式設計的核心思想——抽象有了初步理解。如果希望繼續深入學習計算機程式設計,可以學習 Java、C、JavaScript、Lisp 等不同型別的語言,只有多掌握不同領域的語言,有比較才更有收穫。

710b2cce-b912-eb11-8da9-e4434bdf6706.png
image-20200611064112524

1.1 環境準備

1.1.1 Python 安裝

(1)官網下載 Python

進入官網(https://www.python.org[1]

),點選 Downloads,選擇要下載的版本:

730b2cce-b912-eb11-8da9-e4434bdf6706.png
image-20200517223148826

(2)安裝 Python

安裝時注意下圖勾選部分一定要勾選:

7c0b2cce-b912-eb11-8da9-e4434bdf6706.png
image-20200517223527044

1.1.2 安裝程式碼編輯器 PyCharm

(1)官網下載 PyCharm

進入官網(https://www.jetbrains.com/pycharm[2]),點選 Downloads,選擇要下載的版本:

800b2cce-b912-eb11-8da9-e4434bdf6706.png
image-20200517223348661

(2)安裝 PyCharm

設定安裝路徑之後,一直點 next 即可。

870b2cce-b912-eb11-8da9-e4434bdf6706.png
image-20200517224622654

(3)優化 PyCharm 使用

  • PyCharm 優化使用[3]

1.1.3 安裝 Jupyter notebook

資料分析,對我來說最好用的還是 Jupyter notebook

  • 「Jupyter notebook」 :基於 web 的互動式計算環境,可以編輯易於人們閱讀的文件,用於展示資料分析的過程。

✨ 使用文件可參考我的筆記:Jupyter - notebook 使用指南[4]

觀察一段 10 行 Python 程式碼,感受一下 Python 的風格:

#溫度轉換
#TempConvert.py
TempStr=input("請輸入帶有符號的溫度值:")
ifTempStr[-1]in['F','f']:
C=(eval(TempStr[0:-1])-32)/1.8
print("轉換後的溫度是{:.2f}C".format(C))
elifTempStr[-1]in['C','c']:
F=1.8*eval(TempStr[0:-1])+32
print("轉換後的溫度是{:.2f}F".format(F))
else:
print("輸入格式錯誤!")

☎️ eval()去掉引數最外側引號並執行餘下語句的函式,稱為“評估函式”。

8a0b2cce-b912-eb11-8da9-e4434bdf6706.png
評估函式

程式的基本編寫方法:IPO

  • I:Input 輸入,程式的輸入
  • P:Process 處理,程式的主要邏輯
  • O:Output 輸出,程式的輸出

「程式設計解決問題的步驟」

  • (1)分析問題:分析問題的計算部分,想清楚
  • (2)劃分邊界:劃分問題的功能邊界,規劃 IPO
  • (3)設計演算法:設計問題的求解演算法,關注演算法
  • (4)編寫程式:編寫問題的計算程式,程式設計序
  • (5)除錯測試:除錯程式使正確執行,執行除錯
  • (6)升級維護:適應問題的升級維護,更新完善

1.2 第一個 Python 程式

1.2.1 HelloWorld

建立第一個專案 HelloWorld --> 建立檔案 app.py --> 寫入程式碼:

print("HelloWorld")

效果圖:

8e0b2cce-b912-eb11-8da9-e4434bdf6706.png
image-20200517225658342

1.2.2 輸入和輸出

① 輸出

print() 在括號中加上字串,就可以向螢幕上輸出指定的文字。比如輸出 hello, world,用程式碼實現如下:

print('hello,world')

print() 函式也可以接受多個字串,用逗號 “,” 隔開,就可以連成一串輸出:

print('Thequickbrownfox','jumpsover','thelazydog')

print() 會依次列印每個字串,遇到逗號 “,” 會輸出一個空格,因此,輸出的字串是這樣拼起來的:

?> The quick brown fox jumps over the lazy dog

print()也可以列印整數,或者計算結果:

print(300)
print('100+200=',100+200)#輸出100+200=300

!> 注意,對於 100 + 200,Python 直譯器自動計算出結果 300,但是,'100 + 200 ='是字串而非數學公式,Python 把它視為字串

② 輸入

Python 提供了一個 input(),可以讓使用者輸入字串,並存放到一個變數裡。比如輸入使用者的名字:

print('Inputyourname:')
name=input()
print('Hello!',name)
950b2cce-b912-eb11-8da9-e4434bdf6706.png
image-20200610194537419

我們也可以直接在 input 中顯示一個字串

name=input('Inputyourname:')
print('Hello!',name)
990b2cce-b912-eb11-8da9-e4434bdf6706.png
image-20200610194823007

1.2.3 小結

任何計算機程式都是為了執行一個特定的任務,有了輸入,使用者才能告訴計算機程式所需的資訊,有了輸出,程式執行後才能告訴使用者任務的結果。

輸入是 Input,輸出是 Output,因此,我們把輸入輸出統稱為 Input / Output,或者簡寫為 IO。

input()print() 是在命令列下面最基本的輸入和輸出,但是,使用者也可以通過其他更高階的圖形介面完成輸入和輸出,比如,在網頁上的一個文字框輸入自己的名字,點選 “確定” 後在網頁上看到輸出資訊。

1.2.4 例項 1:溫度轉換

「設計演算法」:根據華氏和攝氏溫度定義,利用轉換公式如下:

其中,C 表示攝氏溫度,F 表示華氏溫度。

在前面,我給過溫度轉換的程式碼,如下:

#TempConvert.py
TempStr=input("請輸入帶有符號的溫度值:")
ifTempStr[-1]in['F','f']:
C=(eval(TempStr[0:-1])-32)/1.8
print("轉換後的溫度是{:.2f}C".format(C))
elifTempStr[-1]in['C','c']:
F=1.8*eval(TempStr[0:-1])+32
print("轉換後的溫度是{:.2f}F".format(F))
else:
print("輸入格式錯誤!")

? 現在看不懂沒關係,有個印象就可以了,學習完下面 Python 基礎,再回來瞧瞧就會更清晰啦!

1.3 Python 基礎

Python 是一種計算機程式語言。計算機程式語言和我們日常使用的自然語言有所不同,最大的區別就是,自然語言在不同的語境下有不同的理解,而計算機要根據程式語言執行任務,就必須保證程式語言寫出的程式決不能有歧義,所以,任何一種程式語言都有自己的一套語法,編譯器或者直譯器就是負責把符合語法的程式程式碼轉換成 CPU 能夠執行的機器碼,然後執行。Python 也不例外。

Python 的語法比較簡單,採用縮排方式,寫出來的程式碼就像下面的樣子:

#printabsolutevalueofaninteger:
a=100
ifa>=0:
print(a)
else:
print(-a)

# 開頭的語句是註釋,註釋是給人看的,可以是任意內容,直譯器會忽略掉註釋。其他每一行都是一個語句,當語句以冒號:結尾時,縮排的語句視為程式碼塊。

縮排有利有弊。好處是強迫你寫出格式化的程式碼,但沒有規定縮排是幾個空格還是Tab。按照約定俗成的慣例,「應該始終堅持使用 4 個空格的縮排。」

縮排的另一個好處是強迫你寫出縮排較少的程式碼,你會傾向於把一段很長的程式碼拆分成若干函式,從而得到縮排較少的程式碼。

縮排的壞處就是“複製-貼上”功能失效了,這是最坑爹的地方。當你重構程式碼時,貼上過去的程式碼必須重新檢查縮排是否正確。此外,IDE 很難像格式化 Java 程式碼那樣格式化 Python 程式碼。

最後,請務必注意,Python 程式是大小寫敏感的,如果寫錯了大小寫,程式會報錯。

1.3.1 資料型別

「資料型別」:供計算機程式理解的資料形式

計算機顧名思義就是可以做數學計算的機器,因此,計算機程式理所當然地可以處理各種數值。但是,計算機能處理的遠不止數值,還可以處理文字、圖形、音訊、視訊、網頁等各種各樣的資料,不同的資料,需要定義不同的資料型別。在 Python 中,能夠直接處理的資料型別有以下幾種:

  • 整數
  • 浮點數
  • 字串
  • 布林值 True / False
  • 空值 None
  • 列表 list / tuple
  • 字典 dict / set
  • 自定義資料型別

① 整數

Python 可以處理任意大小的整數,當然包括負整數,在程式中的表示方法和數學上的寫法一模一樣。

例如:1100-80800,等等。

計算機由於使用二進位制,所以,有時候用十六進位制表示整數比較方便,十六進位制用 0x 字首和 0 - 9, a - f 表示。

例如:0xff000xa5b4c3d2,等等。

② 浮點數

浮點數也就是小數,之所以稱為浮點數,是因為按照科學記數法表示時,一個浮點數的小數點位置是可變的,比如,1.23x10^9 和 12.3x10^8 是完全相等的。浮點數可以用數學寫法,如 1.23,3.14,-9.01,等等。但是對於很大或很小的浮點數,就必須用科學計數法表示,把 10 用 e 替代, 1.23x10^9 就是 1.23e9,或者 12.3e8,0.000012 可以寫成 1.2e-5,等等。

整數和浮點數在計算機內部儲存的方式是不同的,整數運算永遠是精確的(除法難道也是精確的?是的!),而浮點數運算則可能會有四捨五入的誤差。

注意:

在 Python 中,有兩種除法,一種除法是 /

print(10/3)
#輸出3.3333333333333335

/ 除法計算結果是浮點數,即使是兩個整數恰好整除,結果也是浮點數:

print(9/3)
#輸出3.0

還有一種除法是 //,稱為地板除,兩個整數的除法仍然是整數:

print(10//3)
#輸出3

你沒有看錯,整數的地板除 // 永遠是整數,即使除不盡。要做精確的除法,使用 / 就可以。

因為 // 除法只取結果的整數部分,所以 Python 還提供一個餘數運算,可以得到兩個整數相除的餘數:

print(10%3)
#輸出1

無論整數做 // 除法還是取餘數,結果永遠是整數,所以,整數運算結果永遠是精確的。

③ 字串

「字串」:由 0 個或多個字元組成的有序字元序列。

  • 字串是以單引號 ' 或雙引號 " 括起來的任意文字,比如 'abc'"xyz" 等等。請注意,''"" 本身只是一種表示方式,不是字串的一部分,因此,字串 'abc' 只有 abc 這3個字元。如果 ' 本身也是一個字元,那就可以用 "" 括起來,比如 "I'm OK" 包含的字元是 I'm, 空格,OK這 6 個字元。
  • 字串是字元的有序序列,可以對其中的字元進行索引。

如果字串內部既包含 ' 又包含 " 怎麼辦?可以用轉義字元 \ 來標識,比如:

'I\'m\"OK\"!'

表示的字串內容是:

I'm "OK"!

轉義字元 \ 可以轉義很多字元,比如 \n 表示換行,\t 表示製表符,字元 \ 本身也要轉義,所以 \\ 表示的字元就是 \

如果字串裡面有很多字元都需要轉義,就需要加很多 \,為了簡化,Python 還允許用 r '...' 表示,'...' 內部的字串預設不轉義,可以自己試試:

? 示例程式碼:

print('\\\t\\')
#輸出:\\
print(r'\\\t\\')
#輸出:\\\t\\

如果字串內部有很多換行,用 \n 寫在一行裡不好閱讀,為了簡化,Python 允許用 '''...''' 的格式表示多行內容,可以自己試試:

print('''line1
line2
line3''')

效果:

9b0b2cce-b912-eb11-8da9-e4434bdf6706.png
image-20200610222139397

字串的使用:

「使用 [] 獲取字串中一個或多個字元」

  • 索引:返回字串中單個字元 [M]
  • 切片:返回字串中一段字元子串 [M:N]

④ 布林值

布林值和布林代數的表示完全一致,一個布林值只有 TrueFalse 兩種值,要麼是 True,要麼是 False,在 Python 中,可以直接用 TrueFalse 表示布林值(請注意大小寫),也可以通過布林運算計算出來:

print(3>2)
print(3>5)
print(True)
print(False)

布林值可以用 andornot 運算。

and 運算是與運算,只有所有都為 Trueand運算結果才是 True

print(TrueandTrue)#True
print(TrueandFalse)#False
print(FalseandFalse)#False
print(5>3and3>1)#True

or運算是或運算,只要其中有一個為 Trueor運算結果就是 True

print(TrueorFalse)#True
print(53or1>3)#False

not 運算是非運算,它是一個單目運算子,把 True 變成 FalseFalse 變成 True

print(notTrue)#False
print(not1>3)#True

布林值經常用在條件判斷中,比如:

age=int(input())
ifage>=18:
print('adult')
else:
print('teenager')

⑤ 空值

空值是 Python 裡一個特殊的值,用 None 表示。None 不能理解為 0,因為 0 是有意義的,而 None 是一個特殊的空值。

此外,Python 還提供了列表、字典等多種資料型別,還允許建立自定義資料型別,我們後面會繼續講到。

⑥ 列表

Ⅰ 可變的有序列表 list [ ]

Python 內建的一種資料型別是列表:list,list 是一種有序的集合,可以隨時新增刪除其中的元素。

  • 「建立」

比如,列出班裡所有同學的名字,就可以用一個 list 表示:

classmates=['Michael','Bob','Tracy']
print(classmates)#輸出['Michael','Bob','Tracy']

變數 classmates 就是一個 list。用 len()函式可以獲得 list 元素的個數:

print(len(classmates))#輸出3

? list 裡面的元素的資料型別可以不同,比如:

L=['Apple',123,True]

list 元素也可以是 另一個 list,比如:

s=['Python','Java',['C','C++'],'C#']
print(s)#['Python','Java',['C','C++'],'C#']
print(len(s))#4

要注意 s 只有 4 個元素,其中 s[2] 又是一個 list,如果拆開寫就更容易理解了:

p=['C','C++']
s=['Python','Java',p,'C#']
print(s)#['Python','Java',['C','C++'],'C#']
print(len(s))#4

要拿到'C++'可以寫 p[1] 或者 s[2][1],因此 s 可以看成是一個二維陣列,類似的還有三維、四維……陣列,不過很少用到。

如果一個 list 中一個元素也沒有,就是一個空的 list,它的長度為0:

L=[]
print(len(L))#0
  • 「訪問」

用索引來訪問 list 中每一個位置的元素,記得索引是從 0 開始的:

classmates=['Michael','Bob','Tracy']
print(classmates[0])#輸出Michael

當索引超出了範圍時,Python 會報一個 IndexError 錯誤,所以,要確保索引不要越界,記得最後一個元素的索引是 len(classmates) - 1

? 如果要取最後一個元素,除了計算索引位置外,還可以用 -1 做索引,直接獲取最後一個元素:

classmates=['Michael','Bob','Tracy']
print(classmates[-1])#輸出Tracy

以此類推,可以獲取倒數第 2 個、倒數第 3 個:

classmates=['Michael','Bob','Tracy']
print(classmates[-1])#Tracy
print(classmates[-2])#Bob
print(classmates[-3])#Michael
  • 「插入」

list 是一個可變的有序表,所以,可以利用 append 往 list 中追加元素到末尾:

classmates.append('WuGenQiang')

也可以利用 insert 把元素插入到指定的位置,比如索引號為1的位置:

classmates.insert(1,'MengLinLin')

效果:

a00b2cce-b912-eb11-8da9-e4434bdf6706.png
image-20200611164619720
  • 「刪除」

要刪除 list 末尾的元素,用 pop() 方法:

classmates.pop()

要刪除指定位置的元素,用 pop(i) 方法,其中 i 是索引位置:

classmates.pop(1)

效果:

a40b2cce-b912-eb11-8da9-e4434bdf6706.png
image-20200611165043478
  • 「替換」

要把某個元素替換成別的元素,可以直接賦值給對應的索引位置:

classmates[1]='Oliver'
Ⅱ 不可變有序列表 - 元組 tuple ( )

另一種有序列表叫元組:tuple。tuple 和 list 非常類似,但是 tuple 一旦初始化就不能修改,比如同樣是列出同學的名字:

classmates=('Michael','Bob','Tracy')

現在,classmates 這個 tuple 不能變了,它也沒有 append(),insert() 這樣的方法。其他獲取元素的方法和 list 是一樣的,你可以正常地使用 classmates[0]classmates[-1],但不能賦值成另外的元素。

!> 不可變的 tuple 有什麼意義?因為 tuple 不可變,所以程式碼更安全。如果可能,能用 tuple 代替 list 就儘量用 tuple。

? 「tuple 的陷阱」:當你定義一個 tuple 時,在定義的時候,tuple 的元素就必須被確定下來,比如:

t=(1,2)
print(t)#(1,2)

如果要定義一個空的 tuple,可以寫成 ()

t=()
print(t)#()

但是,要定義一個只有 1 個元素的 tuple,如果你這麼定義:

t=(1)
print(t)#1

定義的不是 tuple,是 1 這個數!這是因為括號 () 既可以表示 tuple,又可以表示數學公式中的小括號,這就產生了歧義,因此,「Python 規定,這種情況下,按小括號進行計算」,計算結果自然是 1

所以,「只有 1 個元素的 tuple 定義時必須加一個逗號,,來消除歧義」

t=(1,)
print(t)#(1,)

?> Python 在顯示只有 1 個元素的 tuple 時,也會加一個逗 ,,以免你誤解成數學計算意義上的括號。

最後來看一個 「“可變的” tuple」

t=('a','b',['A','B'])
t[2][0]='X'
t[2][1]='Y'
print(t)#('a','b',['X','Y'])

這個 tuple 定義的時候有 3 個元素,分別是'a''b'和一個 list。不是說 tuple 一旦定義後就不可變了嗎?怎麼後來又變了?

別急,我們先看看定義的時候 tuple 包含的 3 個元素:

a50b2cce-b912-eb11-8da9-e4434bdf6706.png
image-20200611170358099

當我們把 list 的元素 'A''B' 修改為 'X''Y' 後,tuple 變為:

a90b2cce-b912-eb11-8da9-e4434bdf6706.png
image-20200611170515905

表面上看,tuple 的元素確實變了,但其實變的不是 tuple 的元素,而是 list 的元素。tuple 一開始指向的 list 並沒有改成別的 list,所以,⭐ 「tuple 所謂的 “不變” 是說,tuple 的每個元素,指向永遠不變。即指向 'a',就不能改成指向 'b',指向一個 list,就不能改成指向其他物件,但指向的這個 list 本身是可變的!」

理解了 “指向不變” 後,要建立一個內容也不變的 tuple 怎麼做?那就必須保證 tuple 的每一個元素本身也不能變。

⑦ 字典

Ⅰ dict(key - value) { }

Python 內建了字典:dict 的支援,dict 全稱 dictionary,在其他語言中也稱為 map,使用鍵 - 值(key - value)儲存,具有極快的查詢速度。

  • 「建立」

示例程式碼:學生姓名和成績

d={'Michael':95,'Bob':75,'Tracy':85}
print(d)#{'Michael':95,'Bob':75,'Tracy':85}
print(d['Michael'])#95

print(d[0])#KeyError:0

為什麼 dict 查詢速度這麼快?因為 dict 的實現原理和查字典是一樣的。假設字典包含了 1 萬個漢字,我們要查某一個字,一個辦法是把字典從第一頁往後翻,直到找到我們想要的字為止,這種方法就是在 list 中查詢元素的方法,list 越大,查詢越慢。

第二種方法是先在字典的索引表裡(比如部首表)查這個字對應的頁碼,然後直接翻到該頁,找到這個字。無論找哪個字,這種查詢速度都非常快,不會隨著字典大小的增加而變慢。

dict 就是第二種實現方式,給定一個名字,比如'Michael',dict 在內部就可以直接計算出 Michael 對應的存放成績的 “頁碼”,也就是 95 這個數字存放的記憶體地址,直接取出來,所以速度非常快。

把資料放入 dict 的方法,除了初始化時指定外,還可以通過 key 放入:

d['Adam']=67
print(d['Adam'])#67
print(d)#{'Michael':95,'Bob':75,'Tracy':85,'Adam':67}
  • 「判斷 value 是否存在」

由於一個 key 只能對應一個 value,所以,多次對一個 key 放入 value,後面的值會把前面的值沖掉:

d['Adam']=67
print(d['Adam'])#67
d['Adam']=97
print(d['Adam'])#97

如果 key 不存在,dict 就會報錯:KeyError

ae0b2cce-b912-eb11-8da9-e4434bdf6706.png
image-20200611172243031

要避免 key 不存在的錯誤,有兩種辦法,一是通過in判斷 key 是否存在:

print('Thomas'ind)#False

二是通過 dict 提供的 get() 方法,如果 key 不存在,可以返回 None,或者自己指定的 value:

print(d.get('Thomas'))#None
print(d.get('Thomas',-1))#-1
  • 「刪除」

要刪除一個 key,用 pop(key) 方法,對應的 value 也會從 dict 中刪除:

d.pop('Bob')

!> 請務必注意,dict 內部存放的順序和 key 放入的順序是沒有關係的。

⭐ 和 list 比較,dict 有以下幾個特點:

  • 查詢和插入的速度極快,不會隨著 key 的增加而變慢;
  • 需要佔用大量的記憶體,記憶體浪費多。

而 list 相反:

  • 查詢和插入的時間隨著元素的增加而增加;
  • 佔用空間小,浪費記憶體很少。

所以,dict 是用空間來換取時間的一種方法。

dict 可以用在需要高速查詢的很多地方,在 Python 程式碼中幾乎無處不在,正確使用 dict 非常重要,需要牢記的第一條就是 dict 的 key 必須是「不可變物件」

這是因為 dict 根據 key 來計算 value 的儲存位置,如果每次計算相同的 key 得出的結果不同,那 dict 內部就完全混亂了。這個通過 key 計算位置的演算法稱為雜湊演算法(Hash)。

要保證 hash 的正確性,作為 key 的物件就不能變。在 Python 中,字串、整數等都是不可變的,因此,可以放心地作為 key。而 list 是可變的,就不能作為 key:

b50b2cce-b912-eb11-8da9-e4434bdf6706.png
image-20200611173457932
Ⅱ set(key,且 key 不可重複) ([ ])

set 和 dict 類似,也是一組 key 的集合,但不儲存 value。由於 key 不能重複,所以,在 set 中,沒有重複的 key。

set 和 dict 的唯一區別僅在於沒有儲存對應的 value,但是,set 的原理和 dict 一樣,所以,同樣「不可以放入可變物件」,因為無法判斷兩個可變物件是否相等,也就無法保證 set 內部 “不會有重複元素”。

  • 「建立」

要建立一個 set,需要提供一個 list 作為輸入集合:

s=set([1,2,3])
print(s)#{1,2,3}

注意,傳入的引數 [1, 2, 3] 是一個 list,而顯示的 {1, 2, 3} 只是告訴你這個 set 內部有 1,2,3 這 3 個元素,顯示的順序也不表示 set 是有序的。

「重複元素在 set 中自動被過濾:」

s=set([1,1,2,2,3,3])
print(s)#{1,2,3}
  • 「新增」

通過 add(key) 方法可以新增元素到 set 中,可以重複新增,但不會有效果:

s.add(4)
print(s)#{1,2,3,4}
s.add(4)
print(s)#{1,2,3,4}
  • 「刪除」

通過 remove(key) 方法可以刪除元素:

s.remove(4)
print(s)#{1,2,3}
  • 「並集、交集操作」

set 可以看成數學意義上的無序和無重複元素的集合,因此,兩個 set 可以做數學意義上的交集、並集等操作:

s1=set([1,2,3])
s2=set([2,3,4])
print(s1&s2)#{2,3}
print((s1|s2))#{1,2,3,4}

1.3.2 再議不可變物件

上面我們講了,str 是不變物件,而 list 是可變物件。

對於可變物件,比如 list,對 list 進行操作,list 內部的內容是會變化的,比如:

a=['c','b','a']
a.sort()
print(a)#['a','b','c']

而對於不可變物件,比如 str,對 str 進行操作呢:

a='abc'
print(a.replace('a','A'))#'Abc'
print(a)#'abc'

雖然字串有個 replace() 方法,也確實變出了 'Abc',但變數 a 最後仍是 'abc',應該怎麼理解呢?

我們先把程式碼改成下面這樣:

a='abc'
b=a.replace('a','A')
print(b)#'Abc'
print(a)#'abc'

要始終牢記的是,a 是變數,而 'abc' 才是字串物件!有些時候,我們經常說,物件 a 的內容是 'abc',但其實是指,a 本身是一個變數,它指向的物件的內容才是 'abc'

b80b2cce-b912-eb11-8da9-e4434bdf6706.png
image-20200611175123150

當我們呼叫 a.replace('a', 'A') 時,實際上呼叫方法 replace 是作用在字串物件 'abc' 上的,而這個方法雖然名字叫 replace,但卻沒有改變字串 'abc' 的內容。相反,replace 方法建立了一個新字串 'Abc' 並返回,如果我們用變數 b 指向該新字串,就容易理解了,變數 a 仍指向原有的字串 'abc',但變數 b 卻指向新字串 'Abc' 了:

bb0b2cce-b912-eb11-8da9-e4434bdf6706.png
image-20200611175231653

所以,對於不變物件來說,呼叫物件自身的任意方法,也不會改變該物件自身的內容。相反,這些方法會建立新的物件並返回,這樣,就保證了不可變物件本身永遠是不可變的。

!> 小結

  • 使用 key - value 儲存結構的 dict 在 Python 中非常有用,選擇不可變物件作為 key 很重要,最常用的 key 是字串。
  • tuple 雖然是不變物件,但試試把(1, 2, 3)(1, [2, 3])放入 dict 或 set 中,就會有新發現。

1.3.3 變數與常量

① 變數

**變數是用來儲存和表示資料的佔位符號。**變數採用識別符號(名字)來表示,關聯識別符號的過程叫命名。比如例項 1:溫度轉換中的 TempStr 就是變數名字。

「命名規則」:大小寫字母、數字、下劃線_和漢字等字元及組合,且不能用數字開頭

如:TempStr,Python_Great,這是門Python好課

? 注意點:大小寫敏感、首字元不能是數字、不與保留字相同。

⛳️ 拓展:保留字

保留字:被程式語言內部定義並保留使用的識別符號。

  • Python 語言有 33 個保留字(也叫關鍵字),比如:if、elif、else、in
  • 保留字是程式語言的基本單詞,大小寫敏感,比如:if 是保留字,If 是變數

「保留字」看下錶:

bd0b2cce-b912-eb11-8da9-e4434bdf6706.png
保留字

在 Python 中,等號 = 是賦值符號,可以把任意資料型別賦值給變數,同一個變數可以反覆賦值,而且可以是不同型別的變數,例如:

a=123#a是整數
print(a)
a='ABC'#a變為字串
print(a)
a=True#a是一個布林值True
print(a)

? 這種變數本身型別不固定的語言稱之為 「動態語言 (Python、......)」,與之對應的是 「靜態語言(Java、C++、......)」。靜態語言在定義變數時必須指定變數型別,如果賦值的時候型別不匹配,就會報錯。

例如 Java 是靜態語言,賦值語句如下(// 表示註釋):

inta=123;//a是整數型別變數
a="ABC";//錯誤:不能把字串賦給整型變數

和靜態語言相比,動態語言更靈活,就是這個原因。

請不要把賦值語句的等號等同於數學的等號。比如下面的程式碼:

x=10
x=x+2

如果從數學上理解 x = x + 2 那無論如何是不成立的,在程式中,賦值語句先計算右側的表示式 x + 2,得到結果 12,再賦給變數 x。由於 x 之前的值是 10,重新賦值後,x 的值變成 12

最後,理解變數在計算機記憶體中的表示也非常重要。當我們寫:

a='ABC'

時,Python 直譯器幹了兩件事情:

  • 在記憶體中建立了一個 'ABC' 的字串;
  • 在記憶體中建立了一個名為 a 的變數,並把它指向 'ABC'

? 也可以把一個變數 a 賦值給另一個變數 b,這個操作實際上是把變數 b 指向變數 a 所指向的資料,例如下面的程式碼:

a='ABC'
b=a
a='XYZ'
print(b)#輸出ABC

最後一行打印出變數 b 的內容到底是'ABC'呢還是'XYZ'?如果從數學意義上理解,就會錯誤地得出 ba 相同,也應該是'XYZ',但實際上 b 的值是 'ABC',讓我們一行一行地執行程式碼,就可以看到到底發生了什麼事:

  • 執行a = 'ABC',直譯器建立了字串'ABC'和變數a,並把a指向'ABC'

    c20b2cce-b912-eb11-8da9-e4434bdf6706.png
    img
  • 執行b = a,直譯器建立了變數b,並把b指向a指向的字串'ABC'

    c80b2cce-b912-eb11-8da9-e4434bdf6706.png
    img
  • 執行a = 'XYZ',直譯器建立了字串'XYZ',並把a的指向改為'XYZ',但b並沒有更改:

    cd0b2cce-b912-eb11-8da9-e4434bdf6706.png
    img
  • 所以,最後列印變數b的結果自然是'ABC'了。

② 常量

所謂常量就是不能變的變數,比如常用的數學常數 π 就是一個常量:

PI=3.14159265359

在 Python 中,通常用全部大寫的變數名錶示常量。

但事實上 PI 仍然是一個變數,Python 根本沒有任何機制保證 PI 不會被改變,所以,用全部大寫的變數名錶示常量只是一個習慣上的用法,如果你一定要改變變數 PI 的值,也沒人能攔住你。

1.3.4 字串和編碼

① 字串編碼問題

我們已經講過了,字串也是一種資料型別,但是,字串比較特殊的是還有一個編碼問題。

因為計算機只能處理數字,如果要處理文字,就必須先把文字轉換為數字才能處理。最早的計算機在設計時採用 8 個位元(bit)作為一個位元組(byte),所以,一個位元組能表示的最大的整數就是 255(二進位制 11111111 = 十進位制 255),如果要表示更大的整數,就必須用更多的位元組。比如兩個位元組可以表示的最大整數是65535,4 個位元組可以表示的最大整數是4294967295

由於計算機是美國人發明的,因此,最早只有 127 個字元被編碼到計算機裡,也就是大小寫英文字母、數字和一些符號,這個編碼表被稱為ASCII編碼,比如大寫字母A的編碼是65,小寫字母z的編碼是122

但是要處理中文顯然一個位元組是不夠的,至少需要兩個位元組,而且還不能和 ASCII 編碼衝突,所以,中國製定了GB2312編碼,用來把中文編進去。

你可以想得到的是,全世界有上百種語言,日本把日文編到Shift_JIS裡,韓國把韓文編到Euc-kr裡,各國有各國的標準,就會不可避免地出現衝突,結果就是,在多語言混合的文字中,顯示出來會有亂碼。

d60b2cce-b912-eb11-8da9-e4434bdf6706.png
image-20200623172824974

因此,Unicode 應運而生。「Unicode 把所有語言都統一到一套編碼裡,這樣就不會再有亂碼問題了。」

Unicode 標準也在不斷髮展,但最常用的是用兩個位元組表示一個字元(如果要用到非常偏僻的字元,就需要 4 個位元組)。現代作業系統和大多數程式語言都直接支援 Unicode。

? 現在,捋一捋 ASCII 編碼和 Unicode 編碼的區別:「ASCII 編碼是 1 個位元組,而 Unicode 編碼通常是 2 個位元組。」

  • 字母A用 ASCII 編碼是十進位制的65,二進位制的01000001
  • 字元0用 ASCII 編碼是十進位制的48,二進位制的00110000,注意字元'0'和整數0是不同的;
  • 漢字已經超出了 ASCII 編碼的範圍,用 Unicode 編碼是十進位制的20013,二進位制的01001110 00101101

你可以猜測,如果把 ASCII 編碼的A用 Unicode 編碼,只需要在前面補 0 就可以,因此,A的 Unicode 編碼是00000000 01000001

新的問題又出現了:如果統一成 Unicode 編碼,亂碼問題從此消失了。但是,如果你寫的文字基本上全部是英文的話,用 Unicode 編碼比 ASCII 編碼需要多一倍儲存空間,在儲存和傳輸上就十分不划算。

所以,本著節約的精神,又出現了把 Unicode 編碼轉化為 “可變長編碼” 的UTF-8編碼。UTF-8 編碼把一個 Unicode 字元根據不同的數字大小編碼成 1-6 個位元組,常用的英文字母被編碼成 1 個位元組,漢字通常是 3 個位元組,只有很生僻的字元才會被編碼成 4-6 個位元組。如果你要傳輸的文字包含大量英文字元,用 UTF-8 編碼就能節省空間:

e10b2cce-b912-eb11-8da9-e4434bdf6706.png
image-20200623173834408

從上面的表格還可以發現,UTF-8 編碼有一個額外的好處,就是 ASCII 編碼實際上可以被看成是 UTF-8 編碼的一部分,所以,大量只支援 ASCII 編碼的歷史遺留軟體可以在 UTF-8 編碼下繼續工作。

搞清楚了 ASCII、Unicode 和 UTF-8 的關係,我們就可以總結一下現在計算機系統通用的字元編碼工作方式:

? 「在計算機記憶體中,統一使用 Unicode 編碼,當需要儲存到硬碟或者需要傳輸的時候,就轉換為 UTF-8 編碼。」

用記事本編輯的時候,從檔案讀取的 UTF-8 字元被轉換為 Unicode 字元到記憶體裡,編輯完成後,儲存的時候再把 Unicode 轉換為 UTF-8 儲存到檔案:

e50b2cce-b912-eb11-8da9-e4434bdf6706.png
image-20200623174150679

瀏覽網頁的時候,伺服器會把動態生成的 Unicode 內容轉換為 UTF-8 再傳輸到瀏覽器:

ea0b2cce-b912-eb11-8da9-e4434bdf6706.png
image-20200623174254190

所以你看到很多網頁的原始碼上會有類似 的資訊,表示該網頁正是用的 UTF-8 編碼。

② 字串詳解

搞清楚了令人頭疼的字元編碼問題後,我們再來研究 Python 的字串。

在最新的 Python 3 版本中,字串是以 Unicode 編碼的,也就是說,「Python 的字串支援多語言」,例如:

print('包含中文的str')
#輸出:包含中文的str

對於單個字元的編碼,Python 提供了ord()函式獲取字元的整數表示,chr()函式把編碼轉換為對應的字元:

ord('A')#65
ord('中')#20013
chr(66)#'B'
chr(25991)#'文'

如果知道字元的整數編碼,還可以用十六進位制這麼寫str

print('\u4e2d\u6587')#中文

兩種寫法完全是等價的。

由於 Python 的字串型別是str,在記憶體中以 Unicode 表示,一個字元對應若干個位元組。如果要在網路上傳輸,或者儲存到磁碟上,就需要把str變為以位元組為單位的bytes

Python 對bytes型別的資料用帶b字首的單引號或雙引號表示:

x=b'ABC'

要注意區分'ABC'b'ABC',前者是str,後者雖然內容顯示得和前者一樣,但bytes的每個字元都只佔用一個位元組。

以 Unicode 表示的str通過encode()方法可以編碼為指定的bytes,例如:

print('ABC'.encode('ascii'))#b'ABC'
print('中文'.encode('utf-8'))#b'\xe4\xb8\xad\xe6\x96\x87'

純英文的str可以用ASCII編碼為bytes,內容是一樣的,含有中文的str可以用UTF-8編碼為bytes「含有中文的str無法用ASCII編碼」,因為中文編碼的範圍超過了ASCII編碼的範圍,Python 會報錯。

反過來,如果我們從網路或磁碟上讀取了位元組流,那麼讀到的資料就是bytes。要把bytes變為str,就需要用decode()方法:

print(b'ABC'.decode('ascii'))
print(b'\xe4\xb8\xad\xe6\x96\x87'.decode('utf-8'))

如果bytes中包含無法解碼的位元組,decode()方法會報錯:

f00b2cce-b912-eb11-8da9-e4434bdf6706.png
image-20200623175618702

如果bytes中只有一小部分無效的位元組,可以傳入errors='ignore'忽略錯誤的位元組:

f50b2cce-b912-eb11-8da9-e4434bdf6706.png
image-20200623175706636

要計算str包含多少個字元,可以用len()函式:

print(len('ABC'))#3
print(len('中文'))#2

len()函式計算的是str的字元數,如果換成byteslen()函式就計算位元組數:

print(len(b'ABC'))#3
print(len(b'\xe4\xb8\xad\xe6\x96\x87'))#6
print(len('中文'.encode('utf-8')))#6

可見,1 箇中文字元經過 UTF-8 編碼後通常會佔用 3 個位元組,而 1 個英文字元只佔用 1 個位元組。

? 在操作字串時,我們經常遇到strbytes的互相轉換。為了避免亂碼問題,應當始終堅持使用 UTF-8 編碼對strbytes進行轉換。

由於 Python 原始碼也是一個文字檔案,所以,當你的原始碼中包含中文的時候,「在儲存原始碼時,就需要務必指定儲存為 UTF-8 編碼」。當 Python 直譯器讀取原始碼時,為了讓它按 UTF-8 編碼讀取,我們通常在檔案開頭寫上這兩行:

#!/usr/bin/envpython3
#-*-coding:utf-8-*-

第一行註釋是為了告訴 Linux/OS X 系統,這是一個 Python 可執行程式,Windows 系統會忽略這個註釋;

第二行註釋是為了告訴 Python 直譯器,按照 UTF-8 編碼讀取原始碼,否則,你在原始碼中寫的中文輸出可能會有亂碼。

③ 格式化

最後一個常見的問題是如何輸出格式化的字串。我們經常會輸出類似'親愛的 xxx 你好!你 xx 月的話費是 xx,餘額是 xx'之類的字串,而 xxx 的內容都是根據變數變化的,所以,需要一種簡便的格式化字串的方式。

f70b2cce-b912-eb11-8da9-e4434bdf6706.png
image-20200623180524717

在 Python 中,採用的格式化方式和 C 語言是一致的,用%實現,舉例如下:

print('Hello,%s'%'world')#Hello,world
print('Hello,%s,youhave%dmoney'%('WuGenQiang',100))
#Hello,WuGenQiang,youhave100money

你可能猜到了,%運算子就是用來格式化字串的。在字串內部,%s表示用字串替換,%d表示用整數替換,有幾個%?佔位符,後面就跟幾個變數或者值,順序要對應好。如果只有一個%?,括號可以省略。

常見的佔位符有:

fd0b2cce-b912-eb11-8da9-e4434bdf6706.png
image-20200623181028546

其中,格式化整數和浮點數還可以指定是否補 0 和整數與小數的位數:

print('%2d-%02d'%(3,1))#3-01
print('%.2f'%3.1415926)#3.14

如果你不太確定應該用什麼,%s永遠起作用,它會把任何資料型別轉換為字串:

print('Age:%sGender:%s'%(25,True))
#輸出:Age: 25 Gender: True

有些時候,字串裡面的%是一個普通字元怎麼辦?這個時候就需要轉義,用%%來表示一個%

print(‘growthrate:%d%%'%7)
#輸出:'growthrate:7%'

④ format()

另一種格式化字串的方法是使用字串的format()方法,它會用傳入的引數依次替換字串內的佔位符{0}{1}……,不過這種方式寫起來比 % 要麻煩得多:

print('Hello,{0},成績提升了{1:.1f}%'.format('小明',17.125))
#輸出:Hello, 小明, 成績提升了 17.1%

✏️ 練習題:

【題目】小明的成績從去年的 72 分提升到了今年的 85 分,請計算小明成績提升的百分點,並用字串格式化顯示出'xx.x%',只保留小數點後 1 位:

score1=72
score2=85
r=(score2-score1)*100/score1
print('%.1f%%'%r)

1.3.5 條件判斷

計算機之所以能做很多自動化的任務,因為它可以自己做條件判斷

比如,輸入使用者年齡,根據年齡列印不同的內容,在 Python 程式中,用if語句實現:

age=20
ifage>=18:
print('yourageis',age)
print('adult')

根據 Python 的縮排規則,如果if語句判斷是True,就把縮排的兩行 print 語句執行了,否則,什麼也不做。

也可以給if新增一個else語句,意思是,如果if判斷是False,不要執行if的內容,去把else執行了:

age=3
ifage>=18:
print('yourageis',age)
print('adult')
else:
print('yourageis',age)
print('teenager')

!> 注意不要少寫了冒號:

當然上面的判斷是很粗略的,完全可以用elif做更細緻的判斷:

age=3
ifage>=18:
print('adult')
elifage>=6:
print('teenager')
else:
print('kid')

elifelse if的縮寫,完全可以有多個elif,所以if語句的完整形式就是:

if1>:
1>
elif2>:
2>
elif3>:
3>
else:
4>

if語句執行有個特點,它是從上往下判斷,如果在某個判斷上是True,把該判斷對應的語句執行後,就忽略掉剩下的elifelse,所以,下面的程式列印的是teenager

age=20
ifage>=6:
print('teenager')
elifage>=18:
print('adult')
else:
print('kid')

if判斷條件還可以簡寫,比如寫:

ifx:
print('True')

只要x是非零數值、非空字串、非空 list 等,就判斷為True,否則為False

再議 input

最後看一個有問題的條件判斷。很多同學會用input()讀取使用者的輸入,這樣可以自己輸入,程式執行得更有意思:

birth=input('birth:')
ifbirth2000:
print('00前')
else:
print('00後')

輸入1982,結果報錯:

Traceback(mostrecentcalllast):
File"",line1,in
TypeError:unorderabletypes:str()>int()

這是因為input()返回的資料型別是strstr不能直接和整數比較,必須先把str轉換成整數。Python 提供了int()函式來完成這件事情:

s=input('birth:')
birth=int(s)
ifbirth2000:
print('00前')
else:
print('00後')

再次執行,就可以得到正確地結果。但是,如果輸入abc呢?又會得到一個錯誤資訊:

Traceback(mostrecentcalllast):
File"",line1,in
ValueError:invalidliteralforint()withbase10:'abc'

原來int()函式發現一個字串並不是合法的數字時就會報錯,程式就退出了。

如何檢查並捕獲程式執行期的錯誤呢?後面的錯誤和除錯會講到。

✏️ 練習題:

小明身高 1.75,體重 80.5kg。請根據 BMI 公式(體重除以身高的平方)幫小明計算他的 BMI 指數,並根據 BMI 指數:

  • 低於 18.5 :過輕
  • 18.5-25 :正常
  • 25-28 :過重
  • 28-32 :肥胖
  • 高於 32 :嚴重肥胖

if-elif判斷並列印結果:

height=1.75
weight=80.5
bmi=weight/(height*height)
ifbmi>=32:
print('嚴重肥胖')
elifbmi32andbmi>=28:
print('肥胖')
elifbmi28andbmi>=25:
print('過重')
elifbmi25andbmi>=18.5:
print('正常')
else:
print('過輕')
pass

1.3.6 迴圈

要計算 1+2+3,我們可以直接寫表示式:

print(1+2+3)#6

要計算 1+2+3+...+10,勉強也能寫出來。

但是,要計算 1+2+3+...+10000,直接寫表示式就不可能了。

為了讓計算機能計算成千上萬次的重複運算,我們就需要迴圈語句。

① for ... in

Python 的迴圈有兩種,一種是 for...in 迴圈,依次把 list 或 tuple 中的每個元素迭代出來,看例子:

names=['Michael','Bob','Tracy']
fornameinnames:
print(name)

執行這段程式碼,會依次列印names的每一個元素:

Michael
Bob
Tracy

所以for x in ...迴圈就是把每個元素代入變數x,然後執行縮排塊的語句。

再比如我們想計算 1-10 的整數之和,可以用一個sum變數做累加:

sum=0
forxin[1,2,3,4,5,6,7,8,9,10]:
sum=sum+x
print(sum)

如果要計算 1-100 的整數之和,從 1 寫到 100 有點困難,幸好 Python 提供一個range()函式,可以生成一個整數序列,再通過list()函式可以轉換為 list。比如range(5)生成的序列是從 0 開始小於 5 的整數:

a=list(range(5))
print(a)#[0,1,2,3,4]

range(101)就可以生成 0-100 的整數序列,計算如下:

sum=0
forxinrange(101):
sum=sum+x
print(sum)#5050

② while 迴圈

第二種迴圈是 while 迴圈,只要條件滿足,就不斷迴圈,條件不滿足時退出迴圈。

比如我們要計算 100 以內所有奇數之和,可以用 while 迴圈實現:

sum=0
n=99
whilen>0:
sum=sum+n
n=n-2
print(sum)

在迴圈內部變數n不斷自減,直到變為-1時,不再滿足 while 條件,迴圈退出。

✏️ 練習題:

請利用迴圈依次對 list 中的每個名字打印出Hello, xxx!

L=['Bart','Lisa','Adam']
foriteminL:
print('Hello,'+item)

③ break

在迴圈中,break語句可以提前退出迴圈。例如,本來要迴圈列印 1~100 的數字:

n=1
whilen<=100:
print(n)
n=n+1
print('END')

上面的程式碼可以打印出 1~100。

如果要提前結束迴圈,可以用break語句:

n=1
whilen<=100:
ifn>10:#當n=11時,條件滿足,執行break語句
break#break語句會結束當前迴圈
print(n)
n=n+1
print('END')

執行上面的程式碼可以看到,打印出 1~10 後,緊接著列印END,程式結束。

可見break的作用是提前結束迴圈。

④ continue

在迴圈過程中,也可以通過continue語句,跳過當前的這次迴圈,直接開始下一次迴圈。

n=0
whilen10:
n=n+1
print(n)

上面的程式可以打印出 1~10。但是,如果我們想只打印奇數,可以用continue語句跳過某些迴圈:

n=0
whilen10:
n=n+1
ifn%2==0:#如果n是偶數,執行continue語句
continue#continue語句會直接繼續下一輪迴圈,後續的print()語句不會執行
print(n)

執行上面的程式碼可以看到,列印的不再是 1~10,而是 1,3,5,7,9。

可見continue的作用是提前結束本輪迴圈,並直接開始下一輪迴圈。

✏️ 總結:

迴圈是讓計算機做重複任務的有效的方法。

break語句可以在迴圈過程中直接退出迴圈,而continue語句可以提前結束本輪迴圈,並直接開始下一輪迴圈。這兩個語句通常都必須配合if語句使用。

要特別注意,不要濫用breakcontinue語句。breakcontinue會造成程式碼執行邏輯分叉過多,容易出錯。大多數迴圈並不需要用到breakcontinue語句,上面的兩個例子,都可以通過改寫迴圈條件或者修改迴圈邏輯,去掉breakcontinue語句。

有些時候,如果程式碼寫得有問題,會讓程式陷入“死迴圈”,也就是永遠迴圈下去。這時可以用Ctrl+C退出程式,或者強制結束 Python 程序。

1.4 參考資料

  • 廖雪峰 - Python 3.x - Python 基礎[5]
  • 跟老齊學 Python 從入門到精通,需要電子書請關注微信公眾號“碼客趣分享”回覆 Python資料即可獲取。
  • Python 語言程式設計 - 北京理工大學[6]

Reference

[1]

https://www.python.org: https://www.python.org/

[2]

https://www.jetbrains.com/pycharm: https://www.jetbrains.com/pycharm/

[3]

PyCharm 優化使用: Python/PyCharm優化使用.md

[4]

Jupyter - notebook 使用指南: Python/Jupyter-notebook使用指南

[5]

廖雪峰 - Python 3.x - Python 基礎: https://www.liaoxuefeng.com/wiki/1016959663602400/1017063413904832

[6]

Python 語言程式設計 - 北京理工大學: https://www.icourse163.org/learn/BIT-268001?tid=1460270441#/learn/content