-
基礎(chǔ)
1.r''表示''內(nèi)部的字符串默認(rèn)不轉(zhuǎn)義 2.'''...'''表示多行內(nèi)容 3. 布爾值:True、False(注意大小寫) 4.與運(yùn)算and、或運(yùn)算:or、非運(yùn)算:not 5. None代表空值 6.聲明一個(gè)變量(前面不用聲明類型--動(dòng)態(tài)語(yǔ)言): a = 1;//a是整數(shù) b = 'hello'//b是str(字符串) 7.除法: /: 9/3 = 3.0(計(jì)算結(jié)果是浮點(diǎn)數(shù)) 地板除//: 10/3 = 3(計(jì)算結(jié)果是整數(shù)) 8.ord()函數(shù)獲取字符的整數(shù)表示,chr()函數(shù)把編碼轉(zhuǎn)換為對(duì)應(yīng)的字符 9.對(duì)bytes類型的數(shù)據(jù)用帶b前綴的單引號(hào)或雙引號(hào)表示:x = b'ABC' 10.要在網(wǎng)絡(luò)上傳輸,或者保存到磁盤上,就需要把str變?yōu)橐宰止?jié)為單位的bytes '中文'.encode('utf-8') 得到bytes類型為b'\xe4\xb8\xad\xe6\x96\x87' 從網(wǎng)絡(luò)或磁盤上讀取了字節(jié)流,那么讀到的數(shù)據(jù)就是bytes。要把bytes變?yōu)閟tr,就需要用decode() b'\xe4\xb8\xad\xe6\x96\x87'.decode('utf-8')得到str類型為'中文' 11.計(jì)算長(zhǎng)度len():計(jì)算的是str的字符數(shù),如果換成bytes應(yīng)該這么寫len(b'ABC')輸出3 len('中文'.encode('utf-8'))輸出6,可見一個(gè)英文字符占一個(gè)字節(jié),一個(gè)中文字符占3個(gè)字節(jié) 12.如果源代碼中有中文,則需要在開頭加上 # -*- coding: utf-8 -*- 告訴Python解釋器按utf-8編碼讀取,注意:聲明了這個(gè)并不代表文件本身是utf-8編碼的 13.格式化字符串%: 'Hello, %s' % 'world' -----'Hello, world' 'Hi, %s, you have $%d.' % ('Michael', 1000000)-----'Hi, Michael, you have $1000000.' 格式化整數(shù)和浮點(diǎn)數(shù)還可以指定是否補(bǔ)0和整數(shù)與小數(shù)的位數(shù): '%2d-%02d' % (3, 1)----' 3-01' '%.2f' % 3.1415926-----'3.14' %015d ----至少15位(不足高位補(bǔ)0) 如果你不太確定應(yīng)該用什么,%s永遠(yuǎn)起作用,它會(huì)把任何數(shù)據(jù)類型轉(zhuǎn)換為字符串: 'Age: %s. Gender: %s' % (25, True)----'Age: 25. Gender: True' 字符串里面的%是一個(gè)普通字符怎么辦?這個(gè)時(shí)候就需要轉(zhuǎn)義,用%%來表示一個(gè)% 14.有序列表list(可變)和tuple(不可變) list: s = ['first','second','three']//索引從0開始s[0] //還可以-1做索引代表最后一個(gè)s[-1]是three、s[-2]、s[-3] s.append('x') s.insert(1,'x') s.pop()//刪除末尾元素 s.pop(1)//刪除index為1的元素 s[1]='haha'//替換 list里面的元素的數(shù)據(jù)類型也可以不同,比如: L = ['Apple', 123, True] [] 是空列表 tuple: ()是空tuple (1)定義的不是tuple而是小括號(hào)1這個(gè)數(shù) 所以,只有1個(gè)元素的tuple定義時(shí)必須加一個(gè)逗號(hào),,來消除歧義:(1,) “可變的”tuple: t = ('a', 'b', ['A', 'B']) t[2][0] = 'X' t[2][1] = 'Y' 15.條件判斷: if x://只要x是非零數(shù)值、非空字符串、非空l(shuí)ist等,就判斷為True,否則為False print('True')//注意要縮進(jìn) 16.int()函數(shù)把str轉(zhuǎn)換成整數(shù) 17.循環(huán)有兩種:a.for...in循環(huán) b.while循環(huán) names = ['Michael', 'Bob', 'Tracy'] for name in names: print(name) sum = 0 n = 99 while n > 0: sum = sum + n n = n - 2 print(sum) 18. 字典dict,在其他語(yǔ)言中也稱為map,使用鍵-值(key-value)存儲(chǔ),具有極快的查找速度 d = {'Michael': 95, 'Bob': 75, 'Tracy': 85} d['Michael']//得到 95 避免key不存在的錯(cuò)誤,有兩種辦法, 一是通過in判斷key是否存在:'Thomas' in d 二是通過dict提供的get方法,如果key不存在,可以返回None,或者自己指定的value: d.get('Thomas') d.get('Thomas', -1) pop(key)//刪除 dict的key必須是不可變對(duì)象 19. set(無序和無重復(fù)元素的集合):set和dict類似,也是一組key的集合,但不存儲(chǔ)value。由于key不能重復(fù),所以,在set中,沒有重復(fù)的key s = set([1, 2, 3])//傳入的參數(shù)[1, 2, 3]是一個(gè)list add(key) remove(key) 20.字符串可以通過+相連(和java一樣) 21.bin()十進(jìn)制轉(zhuǎn)二進(jìn)制,hex()十進(jìn)制轉(zhuǎn)十六進(jìn)制,oct()十進(jìn)制轉(zhuǎn)八進(jìn)制,0b二進(jìn)制 0x十六進(jìn)制 0八進(jìn)制 22.join()方法: fields = [] fields.append('a') fields.append('b') fields.append('c') fields.append('d') print(" ".join(fields))#輸出a b c d print(",".join(fields))#輸出a,b,c,d
-
函數(shù)
1.函數(shù)名是指向一個(gè)函數(shù)對(duì)象的引用,可以把函數(shù)名賦給一個(gè)變量,相當(dāng)于“別名” eg: a = abs #abs是內(nèi)置函數(shù)取絕對(duì)值 a(-1) 2.定義函數(shù): def my_abs(x): #有冒號(hào) if x >= 0: #注意縮進(jìn) return x #注意縮進(jìn) else: return -x 3.默認(rèn)參數(shù): def power(x, n=2): power(5)和power(5,2)的結(jié)果是一樣的 默認(rèn)參數(shù)的坑:L默認(rèn)是一個(gè)空列表,每次調(diào)用這個(gè)方法L的內(nèi)容會(huì)改變,導(dǎo)致L的內(nèi)容是改變后的內(nèi)容 def add_end(L=[]): L.append('END') return L 調(diào)用第一次返回['END'] 調(diào)用第二次返回['END','END'] ... 解決方法: def add_end(L=None): if L is None: L = [] L.append('END') return L 因?yàn)镹one是不可變對(duì)象,所以每次調(diào)用只會(huì)加一個(gè) 調(diào)用第一次返回['END'] 調(diào)用第二次返回['END'] 4.可變參數(shù)(*):在函數(shù)調(diào)用時(shí)自動(dòng)組裝為一個(gè)tuple def calc(*numbers): calc(1,2,3) #調(diào)用 如果已經(jīng)有了一個(gè)list或tuple,只需要在前面加*就會(huì)當(dāng)成可變參數(shù) nums = [1, 2, 3] calc(*nums) 5.關(guān)鍵字參數(shù)(**):可變參數(shù)在函數(shù)調(diào)用時(shí)自動(dòng)組裝為一個(gè)dict,是參數(shù)的拷貝,改變不會(huì)影響參數(shù)本身 def person(name, age, **kw): print('name:', name, 'age:', age, 'other:', kw) eg:person('Adam', 45, gender='M', job='Engineer') 輸出name: Adam age: 45 other: {'gender': 'M', 'job': 'Engineer'} 如果已經(jīng)有了一個(gè)dict,只需要在前面加**就會(huì)當(dāng)成關(guān)鍵字參數(shù) extra = {'city': 'Beijing', 'job': 'Engineer'} person('Jack', 24, **extra) 6.命名關(guān)鍵字參數(shù) 對(duì)于關(guān)鍵字參數(shù),函數(shù)的調(diào)用者可以傳入任意不受限制的關(guān)鍵字參數(shù) 如果要限制關(guān)鍵字參數(shù)的名字,就可以用命名關(guān)鍵字參數(shù) 例如,只接收city和job作為關(guān)鍵字參數(shù),定義如下: def person(name, age, *, city, job): #*后面的參數(shù)被視為命名關(guān)鍵字參數(shù) print(name, age, city, job) 此時(shí)調(diào)用函數(shù)時(shí)必須傳遞四個(gè)參數(shù),并且最后兩個(gè)字典的key必須分別是 city和job,否則會(huì)報(bào)錯(cuò) 如果函數(shù)定義中已經(jīng)有了一個(gè)可變參數(shù),后面跟著的命名關(guān)鍵字參數(shù)就不再需要一個(gè)特殊分隔符*了: def person(name, age, *args, city, job): print(name, age, args, city, job) 命名關(guān)鍵字可以有缺省值: def person(name, age, *, city='Beijing', job): #調(diào)用時(shí)可以不用傳city的字典 7.參數(shù)組合 def f1(a, b, c=0, *args, **kw): print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw) 注意 tuple 和 list可以調(diào)用 eg: args = (1, 2, 3, 4) kw = {'d': 99, 'x': '#'} f1(*args, **kw) 輸出a = 1 b = 2 c = 3 args = (4,) kw = {'d': 99, 'x': '#'} 8.尾遞歸 在函數(shù)返回的時(shí)候,調(diào)用自身本身,并且,return語(yǔ)句不能包含表達(dá)式。這樣,編譯器或者解釋器就可以把尾遞歸做優(yōu)化,使遞歸本身無論調(diào)用多少次,都只占用一個(gè)棧幀,不會(huì)出現(xiàn)棧溢出的情況 普通遞歸: def fact(n): if n==1: return 1 return n * fact(n - 1)#表達(dá)式 尾遞歸: def fact(n): return fact_iter(n, 1) def fact_iter(num, product): if num == 1: return product return fact_iter(num - 1, num * product) #沒有表達(dá)式,僅返回遞歸函數(shù)本身
-
高級(jí)特性
1. 切片(Slice):取一個(gè)list或tuple的部分元素 L[0:3]代表取L的[0,3),如果第一個(gè)索引為0,還可以省略:L[:3] L[1:len(L)]代表L的[1,L的長(zhǎng)度),可以省略為L(zhǎng)[1:] L[-1]取倒數(shù)第一個(gè)元素,L[-2:]代表取后面兩個(gè) L[:10:2] 前10個(gè)元素 每隔兩個(gè)取一個(gè) L[::5] 所有元素,每隔五個(gè)取一個(gè) 對(duì)tuple切片得到的結(jié)果還是tuple 字符串'xxx'也可以看成是一種list,可以進(jìn)行切片(類似java中的substring),eg: 'ABCDEFG'[:3] ->'ABC' 2.迭代(for ... in):只要是可迭代對(duì)象就可以使用這種方式 dict默認(rèn)是對(duì)key迭代,若要對(duì)value 則 for value in dict.values(): 若同時(shí)對(duì)key value迭代則for k, v in d.items() 字符串也是可迭代對(duì)象 eg:for ch in 'ABC': 如何判斷一個(gè)對(duì)象是可迭代對(duì)象呢?方法是通過collections模塊的Iterable類型判斷: from collections import Iterable isinstance('abc', Iterable) # str是否可迭代 輸出true 對(duì)list實(shí)現(xiàn)類似Java那樣的下標(biāo)循環(huán): for i, value in enumerate(['A', 'B', 'C']): print(i, value) #輸出0 A (","逗號(hào)會(huì)輸出空格) 1 B 2 C 同時(shí)遍歷兩個(gè)變量 for x, y in [[1, 1], [2, 4], [3, 9]]: print(x, y) 3.列表生成式(#注意操作在for前面) list(range(1, 11)) 生成 [1,10] [x * x for x in range(1, 11)] 生成[1, 4, 9, 16, 25, 36, 49, 64, 81, 100] 還可以過濾: [x * x for x in range(1, 11) if x % 2 == 0] 生成[4, 16, 36, 64, 100] 兩層循環(huán),可以生成全排列: [m + n for m in 'ABC' for n in 'XYZ']生成 ['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ'] for循環(huán)其實(shí)可以同時(shí)使用兩個(gè)甚至多個(gè)變量: d = {'x': 'A', 'y': 'B', 'z': 'C' } for k, v in d.items(): print(k, '=', v) 輸出:y = B x = A z = C 把一個(gè)list中所有的字符串變成小寫: L = ['Hello', 'World', 'IBM', 'Apple'] [s.lower() for s in L] #注意操作在for前面 4.生成器(generator):不必創(chuàng)建完整的list,從而節(jié)省大量的空間 把一個(gè)列表生成式的[]改成(),就創(chuàng)建了一個(gè)generator 如果一個(gè)函數(shù)定義中包含yield關(guān)鍵字,那么這個(gè)函數(shù)就不再是一個(gè)普通函數(shù),而是一個(gè)generator 每次調(diào)用next()的時(shí)候執(zhí)行,遇到y(tǒng)ield語(yǔ)句返回,再次執(zhí)行時(shí)從上次返回的yield語(yǔ)句處繼續(xù)執(zhí)行,eg定義一個(gè)generator,依次返回?cái)?shù)字1,3,5: def odd(): yield 1 yield(3) yield(5) for i in odd(): print(i) 輸出1 3 5 也可以這樣 o = odd() next(o) next(o) next(o) 同樣輸出1 3 5(到了最后一個(gè)元素,再調(diào)用next(o)會(huì)報(bào)錯(cuò)) 5.迭代器(Iterator) 凡是可作用于for循環(huán)的對(duì)象都是Iterable類型; 凡是可作用于next()函數(shù)的對(duì)象都是Iterator類型,它們表示一個(gè)惰性計(jì)算的序列; 集合數(shù)據(jù)類型如list、dict、str等是Iterable但不是Iterator,不過可以通過iter()函數(shù)獲得一個(gè)Iterator對(duì)象。 Python的for循環(huán)本質(zhì)上就是通過不斷調(diào)用next()函數(shù)實(shí)現(xiàn)的
-
函數(shù)式編程
1.map()函數(shù)接收兩個(gè)參數(shù),一個(gè)是函數(shù),一個(gè)是Iterable,map將傳入的函數(shù)依次作用到序列的每個(gè)元素,并把結(jié)果作為新的Iterator返回 2. reduce()和map接收參數(shù)一樣,把結(jié)果繼續(xù)和序列的下一個(gè)元素做累積計(jì)算eg:reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4) 3.字符串轉(zhuǎn)int(利用 map 和reduce) from functools import reduce def str2int(s): def fn(x, y): return x * 10 + y def char2num(s): return {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}[s] return reduce(fn, map(char2num, s)) 4.filter()篩選和map接收參數(shù)一樣,返回也是Iterator惰性序列 5.sorted()函數(shù)可以對(duì)list進(jìn)行排序,還可以接收一個(gè)參數(shù)key函數(shù)來實(shí)現(xiàn)自定義排序eg:按絕對(duì)值排序: sorted([36, 5, -12, 9, -21], key=abs) # 輸出 [5, 9, -12, -21, 36] 要進(jìn)行反向排序,不必改動(dòng)key函數(shù),可以傳入第三個(gè)參數(shù)reverse=True 6.返回一個(gè)函數(shù)時(shí),牢記該函數(shù)并未執(zhí)行,返回函數(shù)中不要引用任何可能會(huì)變化的變量 def count(): fs = [] for i in range(1, 4): def f(): return i*i fs.append(f) return fs f1, f2, f3 = count() #此時(shí)f1() f2() f3()的結(jié)果都是9,因?yàn)橐昧送粋€(gè)變量i ,解決辦法: 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的當(dāng)前值被傳入f() return fs 7.匿名函數(shù) def f(x): return x * x 等價(jià)于 lambda x: x * x 8.裝飾器:在不改變某個(gè)函數(shù)具體實(shí)現(xiàn)的情況下,增加函數(shù)的功能 def now(): print('2015-3-25') 需要增加打印函數(shù)名的功能: def log(func): @functools.wraps(func)#用于把原始函數(shù)的__name__等屬性復(fù)制到wrapper()函數(shù)中,否則調(diào)用now.__name__會(huì)得到 wrapper def wrapper(*args, **kw): print('call %s():' % func.__name__)#__name__是函數(shù)對(duì)象內(nèi)置 return func(*args, **kw) return wrapper 使用@ @log def now(): print('2015-3-25') @log 等價(jià)于 now = log(now) 輸出:call now(): 2015-3-25 如果decorator本身需要傳入?yún)?shù),那就需要編寫一個(gè)返回decorator的高階函數(shù)eg: def log(text): def decorator(func): def wrapper(*args, **kw): print('%s %s():' % (text, func.__name__)) return func(*args, **kw) return wrapper return decorator 用法: @log('execute') def now(): print('2015-3-25') 9.偏函數(shù)(functools.partial):把一個(gè)函數(shù)的某些參數(shù)給固定住(也就是設(shè)置默認(rèn)值),返回一個(gè)新的函數(shù),調(diào)用這個(gè)新函數(shù)會(huì)更簡(jiǎn)單 int()函數(shù)默認(rèn)按十進(jìn)制轉(zhuǎn)換 int('12345', 8)轉(zhuǎn)化8進(jìn)制到十進(jìn)制 import functools int2 = functools.partial(int, base=2)#偏函數(shù),轉(zhuǎn)換二進(jìn)制到10進(jìn)制 int2('1000000') 相當(dāng)于kw = { 'base': 2 } int('10010', **kw) max2 = functools.partial(max, 10)#實(shí)際上會(huì)把10作為*args的一部分自動(dòng)加到左邊,也就是: max2(5, 6, 7)相當(dāng)于args = (10, 5, 6, 7) max(*args)
-
模塊
1.一個(gè).py文件就是一個(gè)模塊 2.if __name__=='__main__': #運(yùn)行本模塊會(huì)為True,在其他模塊導(dǎo)入這個(gè)模塊時(shí)會(huì)為False 3.作用域: 正常的函數(shù)和變量名是公開的(public)eg:a、b、c 類似_xxx和__xxx這樣的函數(shù)或變量就是非公開的(private)eg:_a、__b
-
面向?qū)ο缶幊?/p>
1.類(class)和實(shí)例: class Student(object):#表示Student類繼承object def __init__(self, name, score):#第一個(gè)參數(shù)必須是self,init前后有兩個(gè)下劃線,代表初始化必須傳name、score兩個(gè)參數(shù) self.name = name#public self.__score = score#private 不能直接訪問__score是因?yàn)镻ython解釋器對(duì)外把__score變量改成了_Student__score,所以,仍然可以通過_Student__score來訪問__score變量(不建議!!) bart.__score = 20 # 設(shè)置__score變量!是給bart新增了一個(gè)變量__score 2.type()獲取對(duì)象的類型 3.類屬性(類似java的靜態(tài)變量) class Student(object): name = 'Student' 4.在類中定義的函數(shù)第一個(gè)參數(shù)永遠(yuǎn)是實(shí)例變量self(self指向創(chuàng)建的實(shí)例本身),并且調(diào)用時(shí)不用傳遞該參數(shù) 5.__init__類似于構(gòu)造方法,用于創(chuàng)建類時(shí)必須傳遞的參數(shù) 6.變量名類似__xxx__的是特殊變量,特殊變量是可以直接訪問的,不是private變量 7.dir()獲得一個(gè)對(duì)象的所有屬性和方法 8.類似__xxx__的屬性和方法在Python中都是有特殊用途的,調(diào)用len()函數(shù)試圖獲取一個(gè)對(duì)象的長(zhǎng)度,實(shí)際上,在len()函數(shù)內(nèi)部,它自動(dòng)去調(diào)用該對(duì)象的__len__() eg: len('ABC') == 'ABC'.__len__() 我們自己寫的類,如果也想用len(myObj)的話,就自己寫一個(gè)__len__()方法 9.給實(shí)例綁定屬性的方法是通過實(shí)例變量,或者通過self變量 10.給類動(dòng)態(tài)綁定方法: def set_age(self, age): # 定義一個(gè)函數(shù)作為實(shí)例方法 self.age = age from types import MethodType s.set_age = MethodType(set_age, s) # 給實(shí)例綁定一個(gè)方法 s.set_age(25) # 調(diào)用實(shí)例方法 s.age # 測(cè)試結(jié)果 輸出25 但是,給一個(gè)實(shí)例綁定的方法,對(duì)另一個(gè)實(shí)例是不起作用的,解決方法給class綁定: def set_score(self, score): self.score = score Student.set_score = set_score
-
面向?qū)ο蟾呒?jí)編程
1.動(dòng)態(tài)綁定允許我們?cè)诔绦蜻\(yùn)行的過程中動(dòng)態(tài)給class加上功能: def set_score(self, score): self.score = score Student.set_score = set_score #動(dòng)態(tài)綁定方法 s = Student() s.set_score(100) s.score 2.__slots__限制實(shí)例可綁定的屬性(僅對(duì)當(dāng)前類實(shí)例起作用,對(duì)繼承的子類不起作用) class Student(object): __slots__ = ('name', 'age') # 用tuple定義允許綁定的屬性名稱 s = Student() # 創(chuàng)建新的實(shí)例 s.name = 'Michael' # 綁定屬性'name' s.age = 25 # 綁定屬性'age' s.score = 99 # 綁定屬性'score'會(huì)報(bào)錯(cuò) 3.多繼承 class Dog(Mammal, Runnable): 4.__str__ 類似java 的toString方法 class Student(object): def __init__(self, name): self.name = name def __str__(self): return 'Student object (name: %s)' % self.name 使用:print(Student('Michael')) 輸出 Student object (name: Michael) 直接顯示變量調(diào)用的不是__str__(),而是__repr__()(可以令__repr__ = __str__) 5.__iter__ 使一個(gè)類可用于for ... in循環(huán) class Fib(object): def __init__(self): self.a, self.b = 0, 1 # 初始化兩個(gè)計(jì)數(shù)器a,b def __iter__(self): return self # 實(shí)例本身就是迭代對(duì)象,故返回自己 def __next__(self): self.a, self.b = self.b, self.a + self.b # 計(jì)算下一個(gè)值 if self.a > 100000: # 退出循環(huán)的條件 raise StopIteration() return self.a # 返回下一個(gè)值 6.__getitem__使一個(gè)類可按照下標(biāo)取出元素 7.__getattr__使可以訪問一個(gè)非類的屬性 class Student(object): def __init__(self): self.name = 'Michael' def __getattr__(self, attr): if attr=='score': return 99 Student().score 實(shí)例:鏈?zhǔn)秸{(diào)用 class Chain(object): def __init__(self, path=''): self._path = path def __getattr__(self, path): return Chain('%s/%s' % (self._path, path)) def __str__(self): return self._path __repr__ = __str__ Chain().status.user.timeline.list #輸出:'/status/user/timeline/list' 8.__call__ 使得對(duì)象方便的調(diào)用方法 class Student(object): def __init__(self, name): self.name = name def __call__(self): print('My name is %s.' % self.name) 調(diào)用:s = Student('neo') s() #輸出My name is neo 所以你完全可以把對(duì)象看成函數(shù),把函數(shù)看成對(duì)象 通過callable()函數(shù),我們就可以判斷一個(gè)對(duì)象是否是“可調(diào)用”對(duì)象. 9.枚舉 from enum import Enum Month = Enum('Month', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec')) 直接使用Month.Jan來引用一個(gè)常量,枚舉它的所有成員: for name, member in Month.__members__.items(): print(name, '=>', member, ',', member.value) 10.type()函數(shù)既可以返回一個(gè)對(duì)象的類型,又可以創(chuàng)建出新的類型 返回類型: from hello import Hello h = Hello() h.hello()#Hello, world. print(type(Hello))#<class 'type'> Hello是一個(gè)class,它的類型就是type print(type(h))#<class 'hello.Hello'> h是一個(gè)實(shí)例,它的類型就是hello.py模塊下的 Hello類 創(chuàng)建類型: def fn(self, name='world'): # 先定義函數(shù) print('Hello, %s.' % name) Hello = type('Hello', (object,), dict(hello=fn)) # 創(chuàng)建Hello class h = Hello() h.hello()#Hello, world. print(type(Hello))#<class 'type'> print(type(h))#<class '__main__.Hello'> # __main__模塊的Hello類 type()函數(shù)參數(shù): 1.class的名稱; 2.繼承的父類集合,注意Python支持多重繼承,如果只有一個(gè)父類,別忘了tuple的單元素寫法; 3.class的方法名稱與函數(shù)綁定,這里我們把函數(shù)fn綁定到方法名hello上。 11.元類metaclass(可以把類看成是metaclass創(chuàng)建出來的“實(shí)例”) # metaclass是類的模板,所以必須從`type`類型派生: class ListMetaclass(type): def __new__(cls, name, bases, attrs): attrs['add'] = lambda self, value: self.append(value) return type.__new__(cls, name, bases, attrs) class MyList(list, metaclass=ListMetaclass):#說明Python創(chuàng)建MyList會(huì)去調(diào)用元類ListMetaclass的__new__方法 pass L = MyList() L.add(1) print(L)#輸出[1] __new__()方法接收到的參數(shù)依次是: 1.當(dāng)前準(zhǔn)備創(chuàng)建的類的對(duì)象; 2.類的名字; 3.類繼承的父類集合; 4.類的方法集合。 12.使用@property:@property裝飾器就是負(fù)責(zé)把一個(gè)方法變成屬性調(diào)用。 class Student(object): @property def birth(self): return self._birth#下劃線開頭的變量名是可以外部直接方法的(但是不建議這么做) @birth.setter #@property內(nèi)部創(chuàng)建的:方法名.setter def birth(self, value): self._birth = value @property def age(self): return 2015 - self._birth birth是可讀寫屬性,而age就是一個(gè)只讀屬性 s = Student() s.birth = 12#等同于s.birth(12) .方法名 s.birth #等同于s.birth() 13.python可以多繼承
-
錯(cuò)誤、調(diào)試、測(cè)試
1. try: print('try...') r = 10 / int('2') print('result:', r) except ValueError as e: print('ValueError:', e) except ZeroDivisionError as e: print('ZeroDivisionError:', e) else: print('no error!') finally: print('finally...') 2. raise類似java的throw logging類似Log 3. pdb命令行方式進(jìn)行調(diào)試
-
IO編程
1.文本文件(默認(rèn)utf-8) try: f = open('/Users/neo/fps.txt', 'r',encoding='gbk')#'r'表示讀 print(f.read()) finally: if f: f.close()#及時(shí)關(guān)閉 等價(jià)于 with open('/Users/neo/fps.txt', 'r') as f: print(f.read())#不用close read()一次性讀取全部?jī)?nèi)部到內(nèi)存有危險(xiǎn),可反復(fù)調(diào)用read(size)方法 2.二進(jìn)制文件 f = open('/Users/michael/test.jpg', 'rb') 3. StringIO:在內(nèi)存中讀寫str from io import StringIO f = StringIO() f.write('hello') f.write(' ') f.write('world!') print(f.getvalue())#輸出hello world! from io import StringIO f = StringIO('Hello!\nHi!\nGoodbye!') while True: s = f.readline() if s == '': break print(s.strip())#輸出Hello! Hi! Goodbye! 4.BytesIO:用法和StringIO類似,是內(nèi)存中讀寫字節(jié) 5.import os os.path.abspath('.')# 查看當(dāng)前目錄的絕對(duì)路徑: os.path.join('/Users/neo', 'testdir')# 在某個(gè)目錄下創(chuàng)建一個(gè)新目錄,首先把新目錄的完整路徑表示出來: os.mkdir('/Users/neo/testdir')# 然后創(chuàng)建一個(gè)目錄: os.rmdir('/Users/neo/testdir')# 刪掉一個(gè)目錄: os.rename('test.txt', 'test.py')# 對(duì)文件重命名: os.remove('test.py')# 刪掉文件: 5.列出所有的.py文件 [x for x in os.listdir('.') if os.path.isfile(x) and os.path.splitext(x)[1]=='.py'] 6. pickling序列化(利用pickle模塊) 對(duì)象到JSON格式的轉(zhuǎn)換(json模塊) import json d = dict(name='Bob', age=20, score=88) print(json.dumps(d))#輸出{"name": "Bob", "age": 20, "score": 88} JSON轉(zhuǎn)為對(duì)象 import json json_str = '{"age": 20, "score": 88, "name": "Bob"}' persion = json.loads(json_str) print(persion['age'])#輸出20 7.json模塊序列化類 import json class Student(object): def __init__(self, name, age, score): self.name = name self.age = age self.score = score def student2dict(std): return { 'name': std.name, 'age': std.age, 'score': std.score} s = Student('Bob', 20, 88) print(json.dumps(s,default=student2dict)) print(json.dumps(s, default=lambda obj: obj.__dict__))#把任意class的實(shí)例變?yōu)閐ict 反序列化: import json class Student(object): def __init__(self, name, age, score): self.name = name self.age = age self.score = score def dict2student(d): return Student(d['name'], d['age'], d['score']) json_str = '{"age": 20, "score": 88, "name": "Bob"}' print(json.loads(json_str, object_hook=dict2student))
-
進(jìn)程和線程
1.Unix/Linux操作系統(tǒng)提供了一個(gè)fork()系統(tǒng)調(diào)用,它非常特殊。普通的函數(shù)調(diào)用,調(diào)用一次,返回一次, 但是fork()調(diào)用一次,返回兩次,因?yàn)椴僮飨到y(tǒng)自動(dòng)把當(dāng)前進(jìn)程(稱為父進(jìn)程)復(fù)制了一份(稱為子進(jìn)程),然后,分別在父進(jìn)程(返回子進(jìn)程id)和子進(jìn)程(返回0)內(nèi)返回 import os print('Process (%s) start...' % os.getpid()) # Only works on Unix/Linux/Mac: pid = os.fork() if pid == 0: print('I am child process (%s) and my parent is %s.' % (os.getpid(), os.getppid())) else: print('I (%s) just created a child process (%s).' % (os.getpid(), pid)) 輸出Process (1812) start... I (1812) just created a child process (1813). I am child process (1813) and my parent is 1812. 2.Windows沒有fork,可使用multiprocessing模塊 from multiprocessing import Process import os # 子進(jìn)程要執(zhí)行的代碼 def run_proc(name): print('Run child process %s (%s)...' % (name, os.getpid())) if __name__=='__main__': print('Parent process %s.' % os.getpid()) p = Process(target=run_proc, args=('test',)) print('Child process will start.') p.start() p.join()#等待子進(jìn)程結(jié)束后再繼續(xù)往下運(yùn)行 print('Child process end.') 3.多線程(使用threading模塊) import time, threading # 新線程執(zhí)行的代碼: def loop(): print('thread %s is running...' % threading.current_thread().name) n = 0 while n < 5: n = n + 1 print('thread %s >>> %s' % (threading.current_thread().name, n)) time.sleep(1) print('thread %s ended.' % threading.current_thread().name) print('thread %s is running...' % threading.current_thread().name) t = threading.Thread(target=loop, name='LoopThread') t.start() t.join()#主線程等待子線程執(zhí)行完畢 print('thread %s ended.' % threading.current_thread().name) 4.鎖:lock = threading.Lock() lock.acquire()#獲取鎖 lock.release()#一定要手動(dòng)釋放鎖 5.Python解釋器由于設(shè)計(jì)時(shí)有GIL全局鎖,任何Python線程執(zhí)行前,必須先獲得GIL鎖,然后,每執(zhí)行100條字節(jié)碼, 解釋器就自動(dòng)釋放GIL鎖,讓別的線程有機(jī)會(huì)執(zhí)行,導(dǎo)致了多線程無法利用多核(可以使用多進(jìn)程) 6. ThreadLocal import threading # 創(chuàng)建全局ThreadLocal對(duì)象: local_school = threading.local() def process_student(): # 獲取當(dāng)前線程關(guān)聯(lián)的student: std = local_school.student print('Hello, %s (in %s)' % (std, threading.current_thread().name)) def process_thread(name): # 綁定ThreadLocal的student: local_school.student = name process_student() t1 = threading.Thread(target= process_thread, args=('Alice',), name='Thread-A') t2 = threading.Thread(target= process_thread, args=('Bob',), name='Thread-B') t1.start() t2.start() t1.join() t2.join() 輸出Hello, Alice (in Thread-A) Hello, Bob (in Thread-B)
-
正則表達(dá)式
1. \d:匹配一個(gè)數(shù)字 \w:匹配一個(gè)字母或數(shù)字 \s:匹配一個(gè)空格(也包括Tab等空白符) 2.匹配變長(zhǎng)的字符: *表示任意個(gè)字符(包括0個(gè)) +表示至少一個(gè)字符 ?表示0個(gè)或1個(gè)字符 {n}表示n個(gè)字符,用{n,m}表示n-m個(gè)字符 3.需要轉(zhuǎn)義的字符: _ :\_ 4.表示范圍:[] [0-9a-zA-Z\_]可以匹配一個(gè)數(shù)字、字母或者下劃線 [0-9a-zA-Z\_]+可以匹配至少由一個(gè)數(shù)字、字母或者下劃線組成的字符串,比如'1','a100','0_Z','Py3000'等等 5.^表示行的開頭,^\d表示必須以數(shù)字開頭。 $表示行的結(jié)束,\d$表示必須以數(shù)字結(jié)束。 6.re模塊 判斷是否匹配: import re if re.match(r'^\d{3}\-\d{3,8}$', '010-12345'): print('yes') else: print('no') 輸出yes ?切分字符串:
-
網(wǎng)絡(luò)編程
1.網(wǎng)絡(luò)通信其實(shí)就是兩個(gè)進(jìn)程通信 2.如果一臺(tái)計(jì)算機(jī)同時(shí)接入到兩個(gè)或更多的網(wǎng)絡(luò),比如路由器,它就會(huì)有兩個(gè)或多個(gè)IP地址,所以,IP地址對(duì)應(yīng)的實(shí)際上是計(jì)算機(jī)的網(wǎng)絡(luò)接口,通常是網(wǎng)卡 3.IP地址實(shí)際上是一個(gè)32位整數(shù)(稱為IPv4),以字符串表示的IP地址如192.168.0.1實(shí)際上是把32位整數(shù)按8位分組后的數(shù)字表示,目的是便于閱讀 4.IPv6地址實(shí)際上是一個(gè)128位整數(shù) 5.IP協(xié)議負(fù)責(zé)把數(shù)據(jù)從一臺(tái)計(jì)算機(jī)通過網(wǎng)絡(luò)發(fā)送到另一臺(tái)計(jì)算機(jī) 6.TCP協(xié)議則是建立在IP協(xié)議之上的。TCP協(xié)議負(fù)責(zé)在兩臺(tái)計(jì)算機(jī)之間建立可靠連接,保證數(shù)據(jù)包按順序到達(dá)。TCP協(xié)議會(huì)通過握手建立連接,然后,對(duì)每個(gè)IP包編號(hào),確保對(duì)方按順序收到,如果包丟掉了,就自動(dòng)重發(fā) 7.HTTP協(xié)議基于TCP協(xié)議 8.端口的作用:同一臺(tái)計(jì)算機(jī)上跑著多個(gè)網(wǎng)絡(luò)程序。一個(gè)IP包來了之后,到底是交給瀏覽器還是QQ,就需要端口號(hào)來區(qū)分 9、端口號(hào)小于1024的是Internet標(biāo)準(zhǔn)服務(wù)的端口,端口號(hào)大于1024的,可以任意使用 10.UDP協(xié)議時(shí),不需要建立連接,只需要知道對(duì)方的IP地址和端口號(hào),就可以直接發(fā)數(shù)據(jù)包,不可靠、速度快
-
電子郵件
1.Email從MUA(Mail User Agent--電子郵件軟件)發(fā)出去,發(fā)到發(fā)件人郵箱所屬的MTA:Mail Transfer Agent——郵件傳輸代理(Email服務(wù)提供商), 從發(fā)件人所屬的MTA發(fā)送到目標(biāo)郵件地址所屬的MTA(這個(gè)過程中間可能還會(huì)經(jīng)過別的MTA), 目標(biāo)地址所屬的MTA會(huì)把郵件發(fā)送到最終目的地MDA:Mail Delivery Agent——郵件投遞代理,Email到達(dá)MDA后,就靜靜地躺在目標(biāo)服務(wù)器,等待MUA從MDA中取郵件 2.發(fā)郵件時(shí),MUA和MTA使用的協(xié)議就是SMTP 3.收郵件時(shí),MUA和MDA使用的協(xié)議有兩種:POP3、IMAP4 4.MUA在發(fā)郵件時(shí),要先配置SMTP服務(wù)器,也就是你要發(fā)到哪個(gè)MTA上 假設(shè)你正在使用163的郵箱,你就不能直接發(fā)到新浪的MTA上,因?yàn)樗环?wù)新浪的用戶, 所以,你得填163提供的SMTP服務(wù)器地址:smtp.163.com,為了證明你是163的用戶,SMTP服務(wù)器還要求你填寫郵箱地址和郵箱口令 類似的,從MDA收郵件時(shí),Outlook之類的郵件客戶端會(huì)要求你填寫POP3或IMAP服務(wù)器地址、郵箱地址和口令 from email.mime.text import MIMEText msg = MIMEText('hello, send by Python...', 'plain', 'utf-8') # 輸入Email地址和口令: from_addr = '755766986@qq.com' password = 'iwfcltqyzjbpbbjj' # 輸入收件人地址: to_addr = '578179809@qq.com' # 輸入SMTP服務(wù)器地址: smtp_server = 'smtp.qq.com' import smtplib server = smtplib.SMTP(smtp_server, 587) # SMTP協(xié)議默認(rèn)端口是25 server.set_debuglevel(1) server.starttls() server.login(from_addr, password) server.sendmail(from_addr, [to_addr], msg.as_string()) server.quit()
-
訪問數(shù)據(jù)庫(kù)
# -*- coding: utf-8 -*- # 導(dǎo)入MySQL驅(qū)動(dòng): import mysql.connector # 注意把password設(shè)為你的root口令: conn = mysql.connector.connect(user='root', password='zq112hf', database='test') cursor = conn.cursor() # 創(chuàng)建user表: cursor.execute('create table IF NOT EXISTS user (id varchar(20) primary key, name varchar(20))') # 插入一行記錄,注意MySQL的占位符是%s: cursor.execute('insert into user (id, name) values (%s, %s)', ['2', 'Michael']) print('cursor.rowcount = %d'%cursor.rowcount) # 提交事務(wù): conn.commit() cursor.close() # 運(yùn)行查詢: cursor = conn.cursor() cursor.execute('select * from user where id = %s', ('2',)) values = cursor.fetchall() print(values) # 關(guān)閉Cursor和Connection: cursor.close() conn.close()
Web開發(fā)
1.Python內(nèi)置了一個(gè)WSGI(Web Server Gateway Interface)服務(wù)器:wsgiref模塊,效率比較低,僅供開發(fā)和測(cè)試使用
# server.py
# 從wsgiref模塊導(dǎo)入:
from wsgiref.simple_server import make_server
# 導(dǎo)入我們自己編寫的application函數(shù):
from hello import application
# 創(chuàng)建一個(gè)服務(wù)器,IP地址為空,端口是8000,處理函數(shù)是application:
httpd = make_server('', 8000, application)
print('Serving HTTP on port 8000...')
# 開始監(jiān)聽HTTP請(qǐng)求:
httpd.serve_forever()
# hello.py
def application(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
return [b'<h1>Hello, web!</h1>']
運(yùn)行server.py來啟動(dòng)WSGI服務(wù)器
2.Web框架-Flask。每個(gè)請(qǐng)求對(duì)于一個(gè)方法
from flask import Flask
from flask import request
app = Flask(__name__)
@app.route('/', methods=['GET', 'POST'])
def home():
return '<h1>Home</h1>'
@app.route('/signin', methods=['GET'])
def signin_form():
return '''<form action="/signin" method="post">
<p><input name="username"></p>
<p><input name="password" type="password"></p>
<p><button type="submit">Sign In</button></p>
</form>'''
@app.route('/signin', methods=['POST'])
def signin():
# 需要從request對(duì)象讀取表單內(nèi)容:
if request.form['username']=='admin' and request.form['password']=='password':
return '<h3>Hello, admin!</h3>'
return '<h3>Bad username or password.</h3>'
if __name__ == '__main__':
app.run()
3. 使用模板
在Jinja2模板中:
{{ name }}:需要替換的變量
{% ... %}:指令
- 異步IO
1.異步IO模型需要一個(gè)消息循環(huán),在消息循環(huán)中,主線程不斷地重復(fù)“讀取消息-處理消息”過程
當(dāng)遇到IO操作時(shí),代碼只負(fù)責(zé)發(fā)出IO請(qǐng)求,不等待IO結(jié)果,然后直接結(jié)束本輪消息處理,進(jìn)入下一輪消息處理過程。
當(dāng)IO操作完成后,將收到一條“IO完成”的消息,處理該消息時(shí)就可以直接獲取IO操作結(jié)果
2.協(xié)程:一個(gè)線程執(zhí)行,效率高(子程序切換不是線程切換、不需要鎖)
協(xié)程通過generator實(shí)現(xiàn)(包含yield關(guān)鍵字的方法就是一個(gè)generator,不知道這樣理解對(duì)不對(duì))
def consumer():#generator
r = ''
while True:
n = yield r
if not n:
return
print('[CONSUMER] Consuming %s...' % n)
r = '200 OK'
def produce(c):#參數(shù)是一個(gè)generator
c.send(None)
n = 0
while n < 5:
n = n + 1
print('[PRODUCER] Producing %s...' % n)
x = c.send(n)
print('[PRODUCER] Consumer return: %s' % x)
c.close()
c = consumer()#把generator賦值給變量c
produce(c)
執(zhí)行過程:
1.首先調(diào)用c.send(None)啟動(dòng)生成器(generator);
2.然后,一旦生產(chǎn)了東西,通過c.send(n)切換到consumer執(zhí)行;
3.consumer通過yield拿到消息,處理,又通過yield把結(jié)果傳回(就是給consumer()的r賦值);
4.produce拿到consumer處理的結(jié)果(上面的x),繼續(xù)生產(chǎn)下一條消息;
5.produce決定不生產(chǎn)了,通過c.close()關(guān)閉consumer,整個(gè)過程結(jié)束
3. asyncio內(nèi)置了對(duì)異步IO的支持(消息循環(huán))
import asyncio
@asyncio.coroutine#標(biāo)記為coroutine
def hello():
print("Hello world!")
# 異步調(diào)用asyncio.sleep(1):
r = yield from asyncio.sleep(1)#執(zhí)行到這里會(huì)直接中斷并去執(zhí)行EventLoop中其他可以執(zhí)行的coroutine
#過了1秒返回一個(gè)None(r = None),CPU再來執(zhí)行后面的代碼
print("Hello again!")
# 獲取EventLoop:
loop = asyncio.get_event_loop()
# 執(zhí)行coroutine
loop.run_until_complete(hello())#把協(xié)程放到消息隊(duì)列里執(zhí)行,如果有多個(gè)使用wait:asyncio.wait([hello(),A(),B()])
loop.close()#記得關(guān)閉循環(huán)
4.Python 3.5開始
@asyncio.coroutine = async
yield from = await
5. aiohttp則是基于asyncio實(shí)現(xiàn)的HTTP框架
import asyncio
from aiohttp import web
async def index(request):
await asyncio.sleep(0.5)
return web.Response(body=b'<h1>Index</h1>')
async def hello(request):
await asyncio.sleep(0.5)
text = '<h1>hello, %s!</h1>' % request.match_info['name']
return web.Response(body=text.encode('utf-8'))
async def init(loop):
app = web.Application(loop=loop)
app.router.add_route('GET', '/', index)
app.router.add_route('GET', '/hello/{name}', hello)
srv = await loop.create_server(app.make_handler(), '127.0.0.1', 8000)
print('Server started at http://127.0.0.1:8000...')
return srv
loop = asyncio.get_event_loop()
loop.run_until_complete(init(loop))
loop.run_forever()
- 其他
1.with關(guān)鍵字的用法:
with expression as variable:
with block
該代碼快的執(zhí)行過程是: 1.先執(zhí)行expression,然后執(zhí)行該表達(dá)式返回的對(duì)象實(shí)例的__enter__函數(shù),然后將該函數(shù)的返回值賦給as后面的變量。(注意,是將__enter__函數(shù)的返回值(返回expression的值)賦給變量)
2.然后執(zhí)行with block代碼塊,不論成功,錯(cuò)誤,異常,在with block執(zhí)行結(jié)束后,會(huì)執(zhí)行第一步中的實(shí)例的__exit__函數(shù)。)
2.