python - Python 3 學習筆記1
一、 python基礎
1. 字符串
### 斜杠轉義 和 r 不轉義 # \可以轉義很多字符,\n表示換行,\t表示制表符,\\表示\ # \ \ print('\\\t\\') # \\\t\\ print(r'\\\t\\') # hello,\n # world print(r'''hello,\n world''') ### 字符串的修改 a.replace('A', 'a') ### 計算分數增長百分比 s1 = 72 s2 = 85 r = (s2 - s1) / s1 * 100 print('%.1f%%' % r) >>> 18.1% ### 字符串連接 'Jim' + 'Green' = 'JimGreen' '%s, %s' % ('Jim', 'Green') = 'Jim, Green' var_list = ['tom', 'david', 'john'] a = '###' a.join(var_list) = 'tom###david###john'
2. 變量(字符串、列表)
#### 字符串變量 a = 'ABC' b = a b = 'XYZ' print (a) # >>> ABC # 在內存中創(chuàng)建了一個'ABC'的字符串; # 在內存中創(chuàng)建了一個名為a的變量,并把它指向'ABC'。 #### 列表變量 a = [1, 2, 3] b = a # 和java數組一樣 b[0] = 9 print (a) # >>> [9, 2, 3] # 將b指向了與a的同一個列表。b與a共同指向一個列表“實例”
3. list增刪改
#### 列表的增加刪除 ## 增加 append insert classmates = ['Michael', 'Bob', 'Tracy'] classmates.append('Adam') classmates.insert(1, 'Jack') ## 刪除 pop # 刪除list末尾的元素,用pop()方法 # 刪除指定位置的元素,用pop(i)方法 classmates.pop() classmates.pop(1)
## 刪除指定元素
classmates.remove('Bob')
# 清空列表
classmates.clear() ## 修改 #某個元素替換成別的元素,可以直接賦值給對應的索引位置 classmates[1] = 'Sarah' #### 下標循環(huán) enumerate # >>> 0 A # >>> 1 B # >>> 2 C for i, value in enumerate(['A', 'B', 'C']): print(i, value) ## 超出列表長度 list = [1, 2, 3] print (list[4:]) >>> []
4. tuple
#### 元祖 # 定義一個空的tuple t = () # 定義一個只有1個元素的tuple t = (1) # 定義的不是tuple,是1這個數 t = (1,) # 元祖的修改 # 變的不是tuple的元素,而是list的元素。 # tuple一開始指向的list并沒有改成別的list # 指向'a',就不能改成指向'b', # 指向一個list,就不能改成指向其他對象,但指向的這個list本身是可變的 t = ('a', 'b', ['A', 'B']) t[2][0] = 'X' t[2][1] = 'Y' print (t) # >>> ('a', 'b', ['X', 'Y'])
5. 字典dict增刪改查
dic_t = {'Michael': 95, 'Bob': 75, 'Tracy': 85}
#### 增加
dic_t ['blithe'] = 100
print (dic_t ['blithe'])
# >>> 100
dic_t ['blithe'] = 90
print (dic_t ['blithe'])
# >>> 90 會直接修改之前key值的value
d = {}
d.update( [('key1', 'value1'), ('key2', 'value2')] )
#### 條件判斷 查找 in 和 get()
# 判斷key值是否在字典中
>>> 'Thomas' in dic_t
>>> False
# 通過dict提供的get()方法,
# 如果key不存在,可以返回None,或者自己指定的value
dic_t .get('Thomas') # >>>None
dic_t .get('Thomas', -1) # >>> -1
#### 刪除 pop(), del, clear()
# pop 刪除字典給定鍵 key 所對應的值,
# 返回值為被刪除的值
dic_t .pop('Bob')
# del 能刪單一的元素也能清空字典,
# 清空只需一項操作
del dic_t ['Bob']
del dic_t
# clear 刪除字典內所有元素
dic_t .clear() # dic_t = {}
# popitem 隨機刪除字典中的一對鍵值 并 隨機返回還存在的值
dic_t .popitem()
#### 字典不存在的key值
dict = { 'a': 1, 'b': 2 }
print (dict['c'])
>>> KeyError: 'c'
#### 生成空字典的方法
d = {}
d = dict()
d.update([('svk', 'Bratislava'), ('deu', 'Berlin'), ('dnk', 'Copenhagen')])
#### 字典遍歷 d = {'a': 1, 'b':2, 'c': 3} for key in d: print (key) for value in d.values(): print (value) for k, v in d.items(): print (k, v) #### zip字典生成 def create_dict(lista, listb): # print (create_dict(['a', 'b', 'c'], [2, 3, 4])) # >>>{'a': 2, 'b': 3, 'c': 4} if not isinstance(lista, list): return ("lista is not list") elif not isinstance(listb, list): return ("listb is not list") else: new_dict = {} if len(lista) == len(listb): new_dict = dict( zip( lista, listb) ) return new_dict #### formkey字典生成 # >>>{0: 'x', 1: 'x', 2: 'x'} dic = dict.fromkeys(range(3), 'x') #### 二元組列表創(chuàng)建 # >>>{'bar': 3, 'egg': 2, 'spam': 1} list = [('spam', 1), ('egg', 2), ('bar', 3)] dic = dict(list)
6. 集合(set)
#### set的增刪 # set和dict類似,也是一組key的集合,但不存儲value。 # 由于key不能重復,所以,在set中,沒有重復的key ### 創(chuàng)建 # 創(chuàng)建一個set,需要提供一個list作為輸入集合 # 重復元素在set中自動被過濾 s = set([1, 1, 2, 2, 3, 3]) # >>> {1, 2, 3} ### 增加 add # 可以重復添加,但不會有效果 s.add(4) s.add(4) # >>> {1, 2, 3, 4} ### 刪除 remove s.remove(4) # >>> {1, 2, 3} ### 兩個set可以做數學意義上的交集、并集 s1 = set([1, 2, 3]) s2 = set([2, 3, 4]) print (s1 & s2) # >>>{2, 3} print (s1 | s2) # >>> {1, 2, 3, 4}
二、 函數
1. 函數參數
參數定義的順序必須是:必選參數、默認參數、可變參數、命名關鍵字參數和關鍵字參數
#### 默認參數
def enroll(name, gender, age=6, city='Beijing'):
print('name:', name)
print('gender:', gender)
print('age:', age)
print('city:', city)
print (enroll('Sarah', 'F'))
## 與默認參數不符的才需要提供額外的信息
print (enroll('Adam', 'M', city='Tianjin'))
## 默認參數必須指向不變對象
def add_end(L=[]):
# add_end()
# add_end()
# add_end()
# >>>['END', 'END', 'END']
L.append('END')
return L
#修改后 借用None這個不變對象
def add_end(L=None):
if L is None:
L = []
L.append('END')
return L
#### 可變參數
# 允許傳入0個或任意個參數,
# 這些可變參數在函數調用時自動組裝為一個tuple
def calc(*numbers):
sum = 0
for n in numbers:
sum = sum + n * n
return sum
#### 關鍵字參數 & 命名關鍵字參數
# 允許你傳入0個或任意個含參數名的參數,
# 這些關鍵字參數在函數內部自動組裝為一個dict
# 存在可變參數和不存在可變參數
"""
>>> f1(1, 2)
a = 1 b = 2 c = 0 args = () kw = {}
>>> f1(1, 2, c=3)
a = 1 b = 2 c = 3 args = () kw = {}
>>> f1(1, 2, 3, 'a', 'b')
a = 1 b = 2 c = 3 args = ('a', 'b') kw = {}
>>> f1(1, 2, 3, 'a', 'b', x=99)
a = 1 b = 2 c = 3 args = ('a', 'b') kw = {'x': 99}
>>> f2(1, 2, d=99, ext=None)
a = 1 b = 2 c = 0 d = 99 kw = {'ext': None}
"""
def f1(a, b, c=0, *args, **kw):
print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)
def f2(a, b, c=0, *, d, e, **kw):
# 要限制關鍵字參數的名字
# 只接受 d、e為命名關鍵字參數
print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)
def person(name, age, *args, city='city', job, **kw):
# 如果函數定義中已經有了一個可變參數,
# 后面跟著的命名關鍵字參數就不再需要一個特殊分隔符*
# person('a', 11, 33, job='job', ot= 'ot', ot2= 'ot2'))
# >>>a 11 (33,) city job {'ot': 'ot', 'ot2': 'ot2'}
print(name, age, args, city, job, kw)
2. 函數返回值
import math def move(x, y, step, angle=0): nx = x + step * math.cos(angle) ny = y - step * math.sin(angle) return nx, ny # 函數可以同時返回多個值,但其實就是一個tuple。 x, y = move(100, 100, 60, math.pi / 6) r = move(100, 100, 60, math.pi / 6) print(x, y) # >>> 151.96152422706632 70.0 print(r) # >>> (151.96152422706632, 70.0)
三、 高級特性
1. 切片(Slice)
數列、元祖、字符串均可切片
## 先創(chuàng)建一個0-99的數列 L = list(range(100)) ## 取前10個數 # >>> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] L[:10] ## 取后10個數 # >>> [90, 91, 92, 93, 94, 95, 96, 97, 98, 99] L[-10:] # >>> [90, 91, 92, 93, 94, 95, 96, 97, 98] L[-10:-1] ## 前10個數,每兩個取一個 # >>> [0, 2, 4, 6, 8] L[:10:2] ## 所有數,每5個取一個 # >>> [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95] L[::5] ## 只寫[:]就可以原樣復制一個list # >>> [0, 1, 2, 3, ..., 99] L[:]
2. 迭代
使用for循環(huán)時,只要作用于一個可迭代對象,for循環(huán)就可以正常運行
判斷一個對象是可迭代對象,方法是通過collections模塊的Iterable類型判斷
>>> from collections import Iterable >>> isinstance('abc', Iterable) # str是否可迭代 True >>> isinstance([1,2,3], Iterable) # list是否可迭代 True >>> isinstance(123, Iterable) # 整數是否可迭代 False
判斷對象類型:
#### 判斷對象類型 # 基本類型都可以用type()判斷 """ >>> import types >>> def fn(): ... pass ... >>> type(fn)==types.FunctionType True >>> type(abs)==types.BuiltinFunctionType True >>> type(lambda x: x)==types.LambdaType True >>> type((x for x in range(10)))==types.GeneratorType True """ # 判斷一個對象是否可迭代對象 """ from collections import Iterable print (isinstance('abc', Iterable)) print (isinstance([1,2,3], Iterable)) """ # 要獲得一個對象的所有屬性和方法,可以使用dir()函數 """ >>> dir('ABC') ['__add__', '__class__',..., '__subclasshook__', 'capitalize', 'casefold',..., 'zfill'] """
3. 列表生成式
可以用來創(chuàng)建list的生成式
# 生成list [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] list(range(1, 11)) # 生成[4, 16, 36, 64, 100] L = [x * x for x in range(1, 11) if x % 2 == 0] # 兩層循環(huán),可以生成全排列 # >>> ['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ'] L = [m + n for m in 'ABC' for n in 'XYZ'] ### 列出當前目錄下的所有文件和目錄名 # >>> ['.emacs.d', '.ssh', '.Trash'......'Workspace', 'XCode'] import os [d for d in os.listdir('.')] ### 使用兩個變量來生成list # >>> ['y=B', 'x=A', 'z=C'] d = {'x': 'A', 'y': 'B', 'z': 'C' } L = [k + '=' + v for k, v in d.items()] ### if...else 和列表生成式 # 在一個列表生成式中,for前面的if ... else是表達式, # 而for后面的if是過濾條件,不能帶else,否則報錯 # >>> [-1, 2, -3, 4, -5, 6, -7, 8, -9, 10] L = [x if x % 2 == 0 else -x for x in range(1, 11)]
4. 生成器
在循環(huán)的過程中不斷推算出后續(xù)的元素,就不必創(chuàng)建完整的list,從而節(jié)省大量的空間。這種一邊循環(huán)一邊計算的機制,稱為生成器:generator。
#### 創(chuàng)建 # 把一個列表生成式的[]改成(),就創(chuàng)建了一個generator L = [x * x for x in range(10)] # >>> [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] g = (x * x for x in range(10)) # >>> <generator object <genexpr> at 0x1022ef630> # generator保存的是算法, # 每次調用next(g),就計算出g的下一個元素的值, # 直到計算到最后一個元素,沒有更多的元素,拋出錯誤。 ''' >>> next(g) 0 >>> next(g) 1 …… >>> next(g) 81 >>> next(g) Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration ''' # 正確的方法是使用for循環(huán),因為generator也是可迭代對象 g = (x * x for x in range(10)) for n in g: print(n) #### 定義generator的另一種方法 yield ## 斐波拉契數列 def fib(max): # >>> 1, 1, 2, 3, 5, 8, 13, 21, 34, ... n, a, b = 0, 0, 1 while n < max: yield b a, b = b, a + b n = n + 1 return 'done'
楊輝三角形:
# 楊輝三角形 生成器 generator def triangles(): L = [1] while True: yield L L.append(0) L = [ L[i]+ L[i-1] for i in range(len(L))] def triangles_yh(): # 期待輸出: # [1] # [1, 1] # [1, 2, 1] # [1, 3, 3, 1] # [1, 4, 6, 4, 1] # [1, 5, 10, 10, 5, 1] # [1, 6, 15, 20, 15, 6, 1] # [1, 7, 21, 35, 35, 21, 7, 1] # [1, 8, 28, 56, 70, 56, 28, 8, 1] # [1, 9, 36, 84, 126, 126, 84, 36, 9, 1] n = 0 results = [] for t in triangles(): results.append(t) n = n + 1 if n == 10: break for t in results: print(t) real_res = [ [1], [1, 1], [1, 2, 1], [1, 3, 3, 1], [1, 4, 6, 4, 1], [1, 5, 10, 10, 5, 1], [1, 6, 15, 20, 15, 6, 1], [1, 7, 21, 35, 35, 21, 7, 1], [1, 8, 28, 56, 70, 56, 28, 8, 1], [1, 9, 36, 84, 126, 126, 84, 36, 9, 1] ] if results == real_res: print('測試通過!') else: print('測試失敗!')
5. 迭代器
可以直接作用于for循環(huán)的數據類型有以下幾種:
一類是集合數據類型,如list、tuple、dict、set、str等;
一類是generator,包括生成器和帶yield的generator function。
這些可以直接作用于for循環(huán)的對象統(tǒng)稱為可迭代對象:Iterable。
可以被next()函數調用并不斷返回下一個值的對象稱為迭代器:Iterator。
可以使用isinstance()判斷一個對象是否是Iterator對象
>>> from collections.abc import Iterator >>> isinstance((x for x in range(10)), Iterator) True >>> isinstance([], Iterator) False >>> isinstance({}, Iterator) False >>> isinstance('abc', Iterator) False
生成器都是Iterator對象,但list、dict、str雖然是Iterable,卻不是Iterator。
把list、dict、str等Iterable變成Iterator可以使用iter()函數:
>>> isinstance(iter([]), Iterator) True >>> isinstance(iter('abc'), Iterator) True
四、 函數式編程
1. 高階函數: map / reduce
#### map()函數接收兩個參數,一個是函數,一個是Iterable, # map將傳入的函數依次作用到序列的每個元素, # 并把結果作為新的Iterator返回。 def f(x): return x * x r = map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9]) list(r) # >>> [1, 4, 9, 16, 25, 36, 49, 64, 81] # 把這個list所有數字轉為字符串 list(map(str, [1, 2, 3, 4, 5, 6, 7, 8, 9])) # >>> ['1', '2', '3', '4', '5', '6', '7', '8', '9']
#### reduce()函數 # reduce把一個函數作用在一個序列[x1, x2, x3, ...]上, # 這個函數必須接收兩個參數, # reduce把結果繼續(xù)和序列的下一個元素做累積計算,其效果就是: # reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4) # 把序列[1, 3, 5, 7, 9]變換成整數13579 from functools import reduce def fn(x, y): return x * 10 + y reduce(fn, [1, 3, 5, 7, 9]) # 把str轉換為int的函數 def char2num(s): digits = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9} return digits[s] reduce(fn, map(char2num, '13579'))
2. 高階函數:filter
#### filter() # filter()也接收一個函數和一個序列。 #和map()不同的是,filter()把傳入的函數依次作用于每個元素,然后根據返回值是True還是False決定保留還是丟棄該元素。 ## 把一個序列中的空字符串刪掉 def not_empty(s): return s and s.strip() list(filter(not_empty, ['A', '', 'B', None, 'C', ' ']))
3. 高階函數:sorted
#### sorted() # sorted()函數可以對list進行排序 sorted([36, 5, -12, 9, -21]) # >>> [-21, -12, 5, 9, 36] sorted([36, 5, -12, 9, -21], key=abs) # >>> [5, 9, -12, -21, 36] # 反向排序,不必改動key函數,可以傳入第三個參數reverse=True sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower, reverse=True)
4. 返回函數(閉包)
高階函數除了可以接受函數作為參數外,還可以把函數作為結果值返回。
返回一個函數時,牢記該函數并未執(zhí)行,返回函數中不要引用任何可能會變化的變量。
def lazy_sum(*args): def sum(): ax = 0 for n in args: ax = ax + n return ax return sum # 當我們調用lazy_sum()時,返回的并不是求和結果,而是求和函數 # 調用lazy_sum()時,每次調用都會返回一個新的函數,即使傳入相同的參數 f1 = lazy_sum(1, 3, 5, 7, 9) # >>> <function lazy_sum.<locals>.sum at 0x101c6ed90> f2 = lazy_sum(1, 3, 5, 7, 9) f1<> f2 f1() == f2() # >>> 25 ''' 在函數lazy_sum中又定義了函數sum,并且,內部函數sum可以引用外部函數lazy_sum的參數和局部變量, 當lazy_sum返回函數sum時,相關參數和變量都保存在返回的函數中,這稱為“閉包(Closure)” ''' ## 閉包數據異常 =============== def count(): fs = [] for i in range(1, 4): def f(): return i*i fs.append(f) return fs # 返回閉包時牢記一點:返回函數不要引用任何循環(huán)變量,或者后續(xù)會發(fā)生變化的變量。 f1, f2, f3 = count() # >>> f1() = f2() = f3() = 9 =============== def count(): def f(j): def g(): return j*j return g fs = [] for i in range(1, 4): fs.append(f(i)) # f(i)立刻被執(zhí)行,因此i的當前值被傳入f() return fs f1, f2, f3 = count() # >>> f1() f2() f3() = 1, 4, 9
5. 匿名函數
lambda x:[ 表達式 ]
關鍵字lambda表示匿名函數,冒號前面的x表示函數參數。
匿名函數有個限制,就是只能有一個表達式,不用寫return,返回值就是該表達式的結果。
用匿名函數有個好處,因為函數沒有名字,不必擔心函數名沖突。此外,匿名函數也是一個函數對象,也可以把匿名函數賦值給一個變量,再利用變量來調用該函數:f = lambda x: x * x
也可以把匿名函數作為返回值返回:
def build(x, y): return lambda: x * x + y * y
6. 裝飾器
def now(): print('2015-3-25')
假設我們要增強now()函數的功能,比如,在函數調用前后自動打印日志,但又不希望修改now()函數的定義,這種在代碼運行期間動態(tài)增加功能的方式,稱之為“裝飾器”(Decorator)。
本質上,decorator就是一個返回函數的高階函數。所以,我們要定義一個能打印日志的decorator,可以定義如下:
def log(func): def wrapper(*args, **kw): print('call %s():' % func.__name__) return func(*args, **kw) return wrapper
wrapper()函數的參數定義是(*args, **kw),因此,wrapper()函數可以接受任意參數的調用。
7. 偏函數
functools.partial的作用就是,把一個函數的某些參數給固定?。ㄒ簿褪窃O置默認值),返回一個新的函數。
當函數的參數個數太多,需要簡化時,使用functools.partial可以創(chuàng)建一個新的函數,這個新函數可以固定住原函數的部分參數,從而在調用時更簡單。
import functools int2 = functools.partial(int, base=2) print (int2('1000000')) # 64 print (int2('1000000', base=10)) # 1000000
五、模塊
1. 包和模塊
一個abc.py的文件就是一個名字叫abc的模塊,一個xyz.py的文件就是一個名字叫xyz的模塊。
現在,假設我們的abc和xyz這兩個模塊名字與其他模塊沖突了,于是我們可以通過包來組織模塊,避免沖突。方法是選擇一個頂層包名,比如mycompany,按照如下目錄存放:
mycompany
├─ __init__.py
├─ abc.py
└─ xyz.py
引入了包以后,只要頂層的包名不與別人沖突,那所有模塊都不會與別人沖突?,F在,abc.py模塊的名字就變成了mycompany.abc,類似的,xyz.py的模塊名變成了mycompany.xyz。
請注意,每一個包目錄下面都會有一個__init__.py的文件,這個文件是必須存在的,否則,Python就把這個目錄當成普通目錄,而不是一個包。__init__.py可以是空文件,也可以有Python代碼,因為__init__.py本身就是一個模塊,而它的模塊名就是mycompany。
2. 使用模塊
#!/usr/bin/env python3 # -*- coding: utf-8 -*- ' a test module ' __author__ = 'Michael Liao' import sys def test(): args = sys.argv if len(args)==1: print('Hello, world!') elif len(args)==2: print('Hello, %s!' % args[1]) else: print('Too many arguments!') if __name__=='__main__': test()
第1行和第2行是標準注釋,第1行注釋可以讓這個hello.py文件直接在Unix/Linux/Mac上運行,第2行注釋表示.py文件本身使用標準UTF-8編碼;
第4行是一個字符串,表示模塊的文檔注釋,任何模塊代碼的第一個字符串都被視為模塊的文檔注釋;
第6行使用__author__變量把作者寫進去,這樣當你公開源代碼后別人就可以瞻仰你的大名;
3. 作用域
正常的函數和變量名是公開的(public),可以被直接引用,比如:abc,x123,PI等;
類似__xxx__這樣的變量是特殊變量,可以被直接引用,但是有特殊用途,比如上面的__author__,__name__就是特殊變量,hello模塊定義的文檔注釋也可以用特殊變量__doc__訪問,我們自己的變量一般不要用這種變量名;
類似_xxx和__xxx這樣的函數或變量就是非公開的(private),不應該被直接引用,比如_abc,__abc等;

浙公網安備 33010602011771號