一、python簡介 python語言的特性就是簡單優雅,寫容易明瞭的代碼,而且儘量寫少的代碼。python為我們提供了完善的基礎代碼庫,包括網路、文件、DB、文本等。除了內置庫外,還有大量第三方庫。所以,使用python開發,許多功能不需從零編寫,直接使用現成的即可。 python是解釋性語言,運 ...
一、python簡介
python語言的特性就是簡單優雅,寫容易明瞭的代碼,而且儘量寫少的代碼。python為我們提供了完善的基礎代碼庫,包括網路、文件、DB、文本等。除了內置庫外,還有大量第三方庫。所以,使用python開發,許多功能不需從零編寫,直接使用現成的即可。
python是解釋性語言,運行速度與C語言相比較慢。因為,代碼是在執行時候翻譯為CPU理解的機器碼,這個翻譯過程較為耗時。而C程式會在運行前先編譯為機器碼。
二、python基礎
#
是註釋。通過空格進行縮進,當一行語句以 :
結尾時,縮進的語句視為一段代碼塊。按約定俗成的規範,使用4個空格進行縮進。最後代碼就類似這樣:
# output name a = 100 if a > 10: print("a>10") else: print("a<=10")
1. 數據類型和變數
1.1. 數據類型
整數
:例如:1, -10, 0等。十六進位表示整數方式為:以 0x
為首碼,後面為0-9, a-f
,例如:0x11af
浮點數
:例如:0.12, -0.1。對於很大的浮點數就用科學計數法表示,把10用e表示,例如:1.23 * 10的9次方表示為1.23e9
或 12.3e8
整數和浮點數在計算器存儲方式不同,整數運算永遠是精確的,但是浮點數可能會出現四捨五入的誤差。
1.2. 字元串
字元串
:以 單引號''
或 雙引號""
括起來的文本,例如:'abc'
, "abc"
。
\
是轉義符,例如:'I\'m ok'
中\
轉義字元串內部中的'
,輸出結果為 I'm ok
。此外 \n
表示換行符,\t
表示製表符。
為了簡化,還可以通過 r''
表示''
內部的字元串不轉義。通過'''...'''
來表示很多行,示例:
>>> print('\轉義: ', '\\\t\\') \轉義: \ \ >>> print('不轉義:', r'\\\t\\') 不轉義: \\\t\\ >>> print('多行: ', '''line1 ... line2 ... line3''') 多行: line1 line2 line3
1.3. 布爾值
布爾值只有 True
和 False
兩種,可以通過 and
, or
, not
分別進行與、或、非運算。例如:
>>> True and True True >>> True or Flase True >>> not 5 > 1 False
1.4. 空值
空值使用 None
表示,類似null
的含義。
1.5. 變數
變數可以是任意數據類型,變數名必須是 大小寫、數字、_
組成,不能以數字開頭。變數通過 =
賦值,例如:a = 123
將變數a賦值為整數123。
python是動態語言
,變數的類型是不固定的。而例如Java
則是靜態語言
,變數在定義時必須指定類型,例如:int a = 123;
,賦值時候如果類型不匹配,
則編譯時會報錯。與靜態語言相比,動態語言更靈活。
1.6. 常量
常量就是不能變的變數。一般習慣上將常量大寫。
python中除法有 /
和 //
。/
計算結果是浮點數,//
計算結果則為整數。通過 %
來取兩個整數相除的餘數。例如:
>>> 10 / 3 3.3333333333333335 >>> 10 // 3 3 >>> 10 % 3 1
2. 字元串和編碼
2.1. 字元串
python中的字元串類型為str
,在記憶體中以Unicode表示,一個字元對應若幹位元組。如果在網路上傳輸或保存到磁碟,就需要把str
轉化為位元組bytes
。bytes
類型數據用帶b
首碼的單引號或雙引號表示:x = b'abc'
,註意 abc
是str
類型,而b'abc'
則是bytes
類型。
str
通過encode()
可以將編碼為指定的bytes
,例如:
>>> '中文'.encode('utf-8') b'\xe4\xb8\xad\xe6\x96\x87' >>> 'abc'.encode('ascii') b'abc' >>> '中文'.encode('ascii') Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)
英文的str可以用ASCII
編碼為bytes,中文的str可以用UTF-8
編碼為bytes,而中文的str無法通過ASCII
編碼,因為中文超出ASCII
的編碼範圍,故報錯。
bytes
可以通過decode()
方法解碼為str
,例如:
>>> b'\xe4\xb8\xad\xe6\x96\x87'.decode('utf-8') '中文' >>> b'abc'.decode('ascii') 'abc'
通過len()
可以計算str
的字元數或bytes
的位元組數。例如:
>>> len('中文') 2 >>> len('中文'.encode('utf-8')) 6
操作字元串時,我們經常會將str和bytes互相轉換,為了避免亂碼的問題,一般推薦使用utf-8
編碼方式。
2.2. 格式化
python中的字元串格式化方式和C語言類似,都是通過%
運算符實現。例如:
>>> "Hi, %s, you have %d" % ('peter', 100) 'Hi, peter, you have 100'
有幾個占位符,後面就有幾個變數,順序要對應好。常見的占位符有:
- %s: 字元串
- %d: 整數
- %f: 浮點數,%.2f 表示保留2位小數
另一種格式化字元串的方法是使用字元串的format()
方法,它會用傳入的參數依次替換字元串內的占位符{0}、{1}...
,例如:
>>> "Hi, {0}, you have {1:.2f}".format('peter', 3.1415926) 'Hi, peter, you have 3.14'
3. 基本數據結構
3.1 list
list是內置的數據結構:列表,表示有序的數據集合。例如:books = ['a', 'b', 'c']
,books就是一個list。使用的一些方法如下:
>>> books = ['a', 'b', 'c'] >>> books ['a', 'b', 'c'] >>> len(books) # 計算list元素的個數 3 >>> books[0] # 通過索引訪問list中的元素,索引下標從0開始 'a' >>> books[4] # 超出list的範圍會報IndexError錯誤,最後一個下標是 len-1 Traceback (most recent call last): File "<stdin>", line 1, in <module> IndexError: list index out of range >>> books[-1] # 下標-1代表最後一個元素,-2是倒數第二個元素,以此類推 'c' >>> books[-2] 'b' >>> books.append(True) # 往list隊尾添加元素 >>> books.insert(1, ['abc', 'def']) # 往list指定下標位置(1)添加元素 >>> books # list內的元素可以是不同的類型 ['a', ['abc', 'def'], 'b', 'c', True] >>> books.pop() # 從隊尾刪除元素 True >>> books.pop(1) # 從list指定下標位置(index=1)刪除元素 ['abc', 'def'] >>> books; ['a', 'b', 'c'] >>> books[1] = 'abc' # 可以類似數組,直接替換指定下標位置的元素 >>> list = list(range(5)) # 通過range()函數生成0-4的整數序列,再通過list()函數轉換為list >>> list [0, 1, 2, 3, 4]
3.2 tuple
tuple是另一種有序數組,但和list不同的是tuple一經初始化就不能再修改,不能使用append()
,pop()
等修改方法。可以和list類似使用books[0]
,books[-1]
正常訪問元素。不可變使得代碼更安全。使用方法如下:
>>> books = (1,2,['a','b']) # 通過(... , ...)定義tuple >>> books (1, 2, ['a', 'b']) >>> books[2][1] 'b'
3.3 dict
dict全稱為dictionary,是python的內置字典。使用 key-value 鍵值對存儲,一個key只對應一個value。類似 java 中的 map,使用了哈希表的數據結構,有極快的查找速度。使用方法如下:
>>> dict = {'a':100, 'b':200, 'c':300} >>> dict['c'] # 根據key獲取value 300 >>> dict['Adam'] = 400 # 通過key放入value數據 >>> 'Adam' in dict # 判斷key是否在字典中 True >>> 'adam' in dict False >>> dict.get('Adam') # key如果不存在,則會返回None 400 >>> dict.pop('a') # 刪除一個key-value對 100
註意:dict的key是不可變的
3.4 set
set和dict類似,也是一組key的集合,但不存儲value。在set中,key不能重覆。使用方法如下:
>>> set = set([1,2,3]) # 新建set,以list作為輸入集合 >>> set.add(1) # 往set中添加元素,但set中元素不能重覆 >>> set.remove(1) # 從set中移除元素 >>> s1 = set([1,2,3]) >>> s1 {1, 2, 3} >>> s2 = set([2,3]) >>> s1 & s2 # 求s1和s2兩個set的交集 {2, 3} >>> s1 | s2 # 求s1和s2兩個set的並集 {1, 2, 3}
4. 條件和迴圈
4.1. 條件判斷
條件判讀通過if
, elif
, else
完成,完成形式如下:
if <條件判斷1>: <執行1> elif <條件判斷2>: <執行2> elif <條件判斷3>: <執行3> else: <執行4>
如果一個if
判斷為True,則會忽略下麵的判斷語句
4.2. 迴圈
迴圈方式有兩種,一種是for...in
迴圈,依次將list或tuple中的元素迭代出來,計算1-100的和:
sum = 0 for x in range(101): sum += x print(sum)
另一種方式是while
迴圈,只要條件滿足while後語句,就一直迴圈。計算1-100的和:
sum = 0 x = 1 while x <= 100: sum += x x += 1 print(sum)
可以通過break
提前退出while迴圈,contince
提前結束當前迴圈,進行下次迴圈。這兩個語句通常需要配合if
使用
三、 函數
1. 調用函數
如果想調用一個函數,需要知道這個函數的名稱和參數。如abs()
求絕對值的函數,只要一個參數,可以通過help(abs)
查看該函數的幫助信息。
>>> abs(-1) 1 >>> abs(1,2) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: abs() takes exactly one argument (2 given) >>> abs('abc') Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: bad operand type for abs(): 'str'
如果傳參的個數或類型不正確,會報TypeError
錯誤,並提示錯誤信息。
函數名就是指向函數對象的引用,可以將函數名賦值給一個變數,相當於給函數起了個"別名":
>>> a = abs # 將變數a指向函數abs() >>> a(-1) # 通過a調用abs()函數 1
2. 定義函數
定義函數使用def
,函數的返回值使用return
,例如:
def my_abs(x): if not isinstance(x, (int, float)): # 檢查 x 的數據類型 raise TypeError("type error") # 拋出TypeError異常 if x >= 0: x; else: return -x; print(my_abs(-1))
如果沒有return
值,則會返回None
。
pass
作為占位符,表示什麼都不會做。如果沒想好怎麼寫函數中的代碼,可以先用pass讓代碼運行起來。而缺少了pass,代碼會報錯。
if x >= 0: pass;
函數可以返回多個返回值,但其實是返回的單一值:tuple
。但寫起來方便,可以使用多個變數來接受一個tuple。
def test(x): return 1,2 x, y = test('a') print(test('a')) 輸出: (1, 2)
3. 函數的參數
函數除了必選參數外,還提供了預設參數,可變參數和關鍵字參數,使得定義的函數能處理複雜的參數,簡化開發者的調用。
1)預設參數:先定義power函數,計算x的n次方:
def enroll(name, gender, age=6, city='Beijing'): # 第3、4個參數設置預設值 print('name:', name) print('gender:', gender) print('age:', age) print('city:', city) return print(enroll('a', 'F')) # 等同於調用enroll('a','F',6,'Beijing') print(enroll('a', 'F', city='BJ')) # 當參數不按定義的順序傳遞時,需要把參數名寫上,此時age還使用預設值
設置預設參數有幾點需要註意:
- 必選參數在前,預設參數在後。否則無法判斷參數的值該是哪個
- 變化大的參數放前面,變化小的參數放後面。變化小的可以設置為預設參數,好處就是降低了調用函數的難度。
- 預設參數必須指向不可變對象
2)可變參數,傳入函數的參數個數是可變的,可以是0, 1...個。可變參數是在參數前面加上了*
,例如:
def cacl(*number): # number接收的是一個tuple for x in number: print(x) cacl() cacl(1,2,3) # 函數可以傳任意值 nums = [1,2,3] cacl(*nums) # nums前加一個*,將list或tuple的值作為可變參數傳遞
3)關鍵字參數:允許傳遞0或任意個含參數名的參數,這些關鍵字參數在函數內部組裝成一個dict。關鍵字參數可以擴展函數的功能。例如:
def person(name, age, **kw): print('name', name, 'age', age, 'others', kw) # 可傳入任意個關鍵字參數 person('peter', 10, gender='M', job='Engineer') # 可先組裝dict,然後通過**dict將所有key-value用關鍵字參數傳入函數的**kw,kw獲得dict的一份拷貝,對kw的改動不會影響外面的dict dict = {'gender':'M', 'job':'Engineer'} person('peter', 10, **dict)
4)命名關鍵字參數:
函數調用者可以傳入任意不受限制的關鍵字參數,在函數內部可以通過kw檢查到底傳遞了哪些。例如:
def person(name, age, **kw): if 'city' in kw: # 檢查是否有city和job參數 print(kw['city']) if 'job' in kw: print(kw['job']) print(name, age, kw)
如果要限制關鍵字參數的名字,可以使用命名關鍵字參數,和關鍵字參數**kw
不同,命名關鍵字參數需要一個特殊的分隔符*
,*
後面的參數被視為命名關鍵字參數。例如:
def person(name, age, *, city, job): # 只接收city和job作為關鍵字參數 print(name, age, city, job) # 命名關鍵字參數必須傳入參數名,如果沒有傳入參數名,則調用會報錯 person('name', 18, city='city', job='job')
4. 遞歸函數
函數內部可以調用其他函數,如果一個函數在內部調用本身,則這個函數是遞歸函數。例如:計算n的階乘用遞歸方式寫出來就是
def func(n): if n == 1: return 1 return n * func(n-1)
四、高級特性
利用python的一些高級特性,可以用1行代碼實現很多功能,從而幫助我們提升了開發效率。
1. 切片
python提供了切片(Slice)操作符,用於取list或tuple的部分元素。
>>> L = ['a','b','c','d','e'] >>> L[0:3] # 取前3個元素,從索引0到索引3(但不包括索引3)的元素 ['a', 'b', 'c'] >>> L[:3] # 如果第一個索引是0,可以省略 ['a', 'b', 'c'] >>> L[-2:-1] # 倒數切片,倒數第2個元素,倒數第一個元素索引是-1 ['d'] >>> L[-2:] # 倒數前2個元素 ['d', 'e'] >>> L[0:5:2] # 取前5個元素,每2個取一次 ['a', 'c', 'e'] >>> L[::2] # 取所有元素,每2個取一次 ['a', 'c', 'e']
tuple是不可變的一種list,也支持切片操作,操作結果仍是tuple
>>> (1,2,3,4,5)[:3]
(1, 2, 3)
字元串"abcde"也可看做是一個list,每個元素就是一個字元,也可以使用切片操作,其結果仍舊是字元串
>>> 'abcde'[:5:2] 'ace'
2. 迭代
如果給定一個list或tuple,可以使用for迴圈來遍歷,這種遍歷稱為迭代(Iteration)。python中的迭代是通過for...in
來完成,不僅可迭代list/tuple。還可迭代其他對象。
# 迭代list >>> l = list(range(10)) >>> for item in l: ... print(item) # 迭代dict,由於dict的存儲不是像list那樣順序存儲,所有迭代結果可能不是按順序的 >>> d = {'a':1, 'b':2} >>> for key in d: # 預設是迭代的key ... print(key) ... b a >>> for value in d.values(): # 迭代value ... print(value) ... 2 1 >>> for k,v in d.items(): # 迭代key和value ... print(k, v) ... b 2 a 1 # 迭代字元串 >>> for ch in 'abc': ... print(ch) ... a b c
當使用for
時,只要作用與一個迭代對象,就可以正常運行,我們不需要關註迭代對象是list還是其他數據類型。可以通過collections
模塊的Iterable
類型判斷一個對象是否是可迭代對象:
>>> from collections import Iterable >>> isinstance('abc', Iterable) # str類型可迭代 True >>> isinstance(123, Iterable) # 整數不可迭代 False >>> dict={'a':1} >>> isinstance(dict, Iterable) # dict類型可迭代 True
python內置的enumerate
函數可以將list變成索引-元素對。這樣可以在for
中迭代索引和對象本身:
>>> l = ['a','b','c','d'] >>> for i,value in enumerate(l): ... print(i, value) ... 0 a 1 b 2 c 3 d
3. 列表生成式
python內置了簡單而強大的生成list的方式,通過使用列表生成式可以寫出非常簡潔的代碼。
# 生成 2-10 的list >>> L=list(range(2,11)) >>> L [2, 3, 4, 5, 6, 7, 8, 9, 10]
此外,還可以在for...in...
後面加上if
進行判斷。例如:生成3-10中偶數的平方的list:
>>> L=[x * x for x in range(3,11) if x % 2 ==0] >>> L [16, 36, 64, 100]
等價於
>>> L=[] >>> for x in range(3,11): ... if x % 2 == 0: ... L.append(x * x) ... >>> L [16, 36, 64, 100]
列表生成式也可以使用兩個變數來生成list:
>>> dict={'a':'1', 'b':'2'} >>> [k+'='+v for k,v in dict.items()] ['b=2', 'a=1']
4. 生成器
通過列表生成器,可以直接創建一個列表。但是,假如創建一個包含100萬個元素的列表,需要占用大量的記憶體空間,而我們只需要前幾個元素,那麼大多數元素占用的記憶體空間就浪費了。
對於這種情況,python提供了生成器(generator)
,能一邊迴圈一邊計算,從而不需要創建完整的list,節省了記憶體空間。
第一種創建generator
生成器的方式:將[]
改為()
>>> L = [x * x for x in range(1,10)] # 創建list >>> L # 列印list的每一個元素 [1, 4, 9, 16, 25, 36, 49, 64, 81] >>> g = (x * x for x in range(1,10)) # 創建generator >>> g <generator object <genexpr> at 0x1024e0bf8> >>> next(g) # 用next()函數獲取generator下一個返回值 1 >>> next(g) 4
next()會計算g的下一個元素,當沒有元素時,會拋出StopIteration
異常。generator是可迭代對象,可以使用for
迴圈來代替next()
>>> g = (x * x for x in range(1,5)) >>> for n in g: ... print(n) ... 1 4 9 16
第二種創建generator
生成器的方式:函數定義中使用yield
,將函數變成generator
下麵是生成菲波那切數列的函數,除第一個和第二個數之外,後面每個數等於前兩個數的和:
def fib(max): n, a, b = 0, 0, 1 while n < max: print(b) a, b = b, a + b n = n + 1 return 'done' fib(6) # 輸出菲波那切數列前6個數
這種邏輯非常類似generator,可以從第一個元素開始,推算後面任意的元素。將print(b)
改為yield b
,該函數就就變成了generator。generator和普通函數執行流程不一樣:
- 普通函數是順序執行,遇到
return
或最後一行函數語句就會返回; - 而變為
generator
的函數,每次調用next()
的時候執行,遇到yield
中斷並返回值,再次調用next()
時從上次yield
語句處繼續執行。
>>> def fib(max): ... n, a, b = 0, 0, 1 ... while n < max: ... yield b ... a, b = b, a + b ... n = n + 1 ... return 'done' ... >>> g = fib(6) # 生成generator對象 >>> g <generator object fib at 0x1024e0bf8> >>> next(g) # 調用next()函數不斷獲取後一個返回值 1 >>> next(g) 1 >>> next(g) 2 >>> next(g) 3 >>> next(g) 5 >>> next(g) 8 >>> next(g) # 此時 n = max, 沒有yield可以執行了,所有調用就報錯了 Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration: done >>> for n in fib(6): # 也可以使用for迴圈進行generator的迭代 ... print(n)
5. 迭代器
直接作用於for
迴圈的數據類型有以下幾種:
- 集合數據類型:
list
,tuple
,dict
,set
,str
等 generator
:包括生成器和帶yield
的生成器函數
這些可作用for迴圈的對象統稱為可迭代對象:Iterable
。可通過isinstance()
判斷一個對象是否是Iterable:
>>> isinstance([],Iterable) True >>> isinstance((x for x in range(10)),Iterable) True >>> isinstance(123,Iterable) False
生成器不僅可作用於for迴圈,還可被next()
不斷調用返回下一個值,直至拋出StopIteration
,這類對象成為迭代器:Iterator
,也可使用isinstance
進行判斷:
>>> from collections import Iterator >>> isinstance([],Iterator) False >>> isinstance((x for x in range(10)), Iterator) True
迭代器Iterator表示的是一個數據流,可將數據流看做是一個有序隊列,但不能提前知道隊列的長度,只能通過next()函數實時按需計算下一個元素的值。
五、函數式編程
1. 高階函數
函數名是指向函數的變數,對於函數abs()
,可將abs
函數名看做變數,它指向可以計算絕對值的函數。另外,函數本身可以賦值給其他變數:
>>> abs(-10) # 調用求絕對值的函數 10 >>> abs # abs是函數本身 <built-in function abs> >>> f=abs # 將函數本身賦值給變數 >>> f <built-in function abs> >>> f(-10) # 通過變數來調用函數。直接調用abs()和調用變數f()相同 10
既然變數可以指向函數,函數的參數能接受變數,那麼一個函數就可以接收另一個函數作為參數,這種函數就稱為高階函數
。函數式編程就是指這種高度抽象的編程範式。例如:
def add(x, y, f): print(f(x) + f(y)) add(-5, 6, abs) # f=abs 作為參數傳入, 最後計算abs(-5) + abs(6) 輸出:11