Python基礎筆記

#############################################################################################
# Subject: Python 3
# Author: Blue_Chou
# Update: 2018.12
# 在cmd中執行py文件(路徑可加雙引號),如:python E:\PythonSrc\mypy_package\demo.py
#############################################################################################

一、輸入函數:input('輸入提示信息'),獲取用戶輸入,保存成一個字符串!
輸出(打印)函數:print(*args, sep=' ', end='\n', file=None),"sep"分隔符號,"end"打印後的結束方式,活用print的參數,能夠實現靈活的打印控制。

二、Python數據類型都是"類(class)"類型。
Python中的變量不須要聲明類型(根據Python的動態語言特性而來)。
每一個變量在使用前都必須賦值!變量賦值之後纔會被建立。
在Python中,變量自己沒有數據類型的概念,一般所說的"變量類型"是變量所引用的對象的類型,或者說是變量的值的類型。

dir():顯示對象全部的屬性和方法。最棒的輔助函數之一!
dir(__builtins__):輸出全部Python內置系統的變量和函數,首字母大寫的是異常類名。
dir(__name__):輸出Python對象的屬性和方法。
vars():輸出某對象全部屬性,vars()跟__dict__是等同的。
chr():將十進制數轉化爲對應的ASCII字符。
ord():將ASCII字符轉化爲對應的十進制數。
divmod():返回商和餘數的元組。
reversed():反轉序列。
repr():調用對象所屬類的__repr__方法,與print功能相似。

3、數據類型:
(1)整型:int,長度32位(即long)
賦值方式:① x=99 ② x=int(99),若是是浮點數,則取整。
轉換函數:int(),bin(),oct(),hex()等。
進製表示法:二進制0b,八進制0o,十六進制0x。進行二進制計算時加前綴"0b",其餘相似。

(2)布爾型:bool

(3)浮點型:float(雙精度)、complex(複數)、Decimal(定點數)
Decimal入參是整數或字符串,由於float精度不夠。 

(4)字符串型:str (Unicode字符構成)
使用三引號(''' '''),能夠格式化縮進和換行。
" * "能複製字符串、列表、元組等,如s='#'*9,即9個#
使用"\"鏈接,能夠換行書寫代碼。如:
s='abcd'\
'efgh'

字符串對象方法:
s.strip(c):去除空格或指定的字符c;lstrip/rstrip;
s.zfill(w):右對齊,寬度小於w用0前補;
s.ljust(w,c):左對齊,寬度w,填充符c;rjust()右對齊。
s.join(q):用"s"將序列"q"中的元素串起來; 
s.partition(sep):以sep爲分隔符,把字符串分割,返回一個元組(包含分割符);
s.split(sep=None, maxsplit=-1):把字符串以sep爲分隔符分割,maxsplit爲分割次數,返回一個列表(不包含分割符);
s.find(t):返回t的最左位置,未找到,返回-1;
s.index(t):返回t的最左位置,未找到,返回ValueError異常;
s.capitalize():第一個字母變大寫;
s.title():每一個單詞首字母大寫;
s.center(width, fillchar=None):字符串內容居中,在給定的字符串長度width中內容居中,兩邊用提供的字符fillchar填充,fillchar默認爲空;
s.count(sub, start=None, end=None):在指定位置start與end之間,計算sub字符的數量;
s.endswith(suffix, start=None, end=None):判斷字符串在start與end位置之間是否是以某個子序列suffix結尾,相似方法還可有startwith();
s.replace(old, new, count=None):把字符串中某個子序列old替換成一個新序列new,count是替換數,返回一個新字符串;
s.isdigit():判斷是否全是數字;
s.isalpha():判斷是否全是字母;
s.isalnum():判斷是否包含字母或數字;
s.isspace():判斷是不是空字符串;

新式格式化方法(傳統格式化方法見本文第11標號):
s.format():格式化,用{}配合使用。如'...{0}...{1}...{2}'.format('A','B','C') 或'...{name}...{0}...'.format(20,name='She');
format參數說明:位置參數必須在關鍵字參數以前,能夠傳字典參數。 
用冒號":"進行格式化輔助:
'{0:20}'.format(s) # 寬度20,默認左對齊
'{0:<20}'.format(s) # 寬度20,左對齊
'{0:>20}'.format(s) # 寬度20,右對齊
'{0:^20}'.format(s) # 寬度20,居中
'{0:*>20}'.format(s) # 寬度20,右對齊,用*填充
'{0:.4}'.format(s) # 剪切字符,最大寬度4
'{0:+20}'.format(num) # 對於數值num,寬度20,帶符號輸出
'{0:#x}'.format(num) # 返回十六進制形式,#b二進制,#o八進制
'{0:,}'.format(num) # 三個數字逗號分組,如銀行數
'{0:.2f}'.format(num) # 帶2位小數的浮點數
'{0:e}'.format(num) # 科學計數
4)字節型(二進制):
bytes(固定的)、bytearray(可變的,可插入可刪除某個字符)。
如,bin=b'python''python'.encode()
binarr=bytearray(bin), binarr.pop(1), binarr.insert(1,ord('a'))

(5)其餘類型:列表、元組、字典、集合。

四、運算符"/"結果是浮點數,"//"結果是整數,"**"表冪運算,"!="表不等於。
is: 基於內存的身份比較。如,x=('python'),y=('python'),x is y 返回True。"is""=="結果相似。
比較操做符: 基於對象值比較。如,x=('python'),y=('python'),x == y 返回True。Python支持鏈式比較,1 <= a <= 3。
id(): 獲取內存地址。
in: 理解爲屬於,判斷成員關係,val in lists。
andor: 與、或。短運算邏輯,返回布爾值,或決定結果的操做數。Python中沒有"&&""||""!"符號。
not: 非。老是返回布爾值。
del obj: 只是刪除引用對象(當無任何引用對象時,數據才被回收),沒有刪除內存地址。
[]: 切片操做符或項目操做符。

6、ASCII編碼:只有127個字符,字母佔1個字節;(沒法編碼漢字、日文等)
Unicode編碼:萬國碼,字母佔2個字節,漢字佔3個字節;(字母佔用了多餘的空間)
utf-8編碼:字母佔1個字節,漢字佔3個字節。(推薦)

七、方法encode('編碼格式'):如,'中文'.encode('utf-8')。

八、方法decode('解碼格式'):如,b'\xe6\xb1\xaa'.decode('utf-8')。Python對bytes類型的數據用帶"b"前綴的單引號或雙引號表示。

九、r'\字符':原生字符串,使轉義無效。

十、#!/usr/bin/env python3
告訴Linux/OS X系統,這是一個Python可執行程序,Windows系統會忽略這個註釋;
# -*- coding: utf-8 -*-
告訴Python解釋器,按照UTF-8編碼讀取源代碼,不然,你在源代碼中寫的中文輸出可能會有亂碼。

Python文件名不能和關鍵字、模塊名相同,不然極可能會報找不到屬性的錯誤。

11、print傳統格式化(變量前加格式):
%d 格式化整數
%f 格式化浮點數
%s 格式化字符串
%o 格式化八進制
%x 格式化十六進制

格式化輔助:"."精度,"-"左對齊,"+"整數帶加號,"0"數字前面填充0,等。

如,print('成績增加率:%.2f' %(num)) #保留兩位小數

十二、列表(list),定義用"[]":有序、重複,列表是可變對象。若是要取最後一個元素,除了計算索引位置外,還能夠用-1作索引,直接獲取最後一個元素,以此類推,能夠獲取倒數第2個、倒數第3個。
若L=[...]
print(L) #整個列表
print(*L) #用"*"拆出列表全部元素

組合類型函數,list(),tuple(),dict(),set(),frozenset()只能傳入一個參數。

list適合當作"堆棧",queue.Queue做爲"單向隊列",collections.deque做爲"雙向隊列"13、列表對象方法:
1)append(self, p_object):在原有列表最後位置上追加新元素到列表,不生成新的列表。
2)clear(self):清空列表裏面的元素,不生成新列表。
3)copy(self):複製一份列表,至關於一次淺拷貝。
5)extend(self, iterable):把iterable中的每一個元素擴展成列表的元素,iterable能夠是字符串、列表、集合、元組、字典。
6)index(self, value, start=None, stop=None):查找列表中value元素索引位置,start與stop參數是查找起始與結束位置,默認爲None。
7)insert(self, index, p_object):在列表index索引位置插入元素p_object,當index大於列表包含的元素個數時,在最後位置插入元素。
8)pop(self, index=None):從列表中取出index位置的值,index默認爲None,此時彈除並返回列表中最後一個值。
9)remove(self, value):移除列表中第一個出現的value元素,value元素不存在列表中時,則拋出ValueError。
10)reverse(self):反轉列表元素的位置。
11)sort(self, key=None, reverse=False):給列表中的元素排序,reverse實現降序排序,默認爲False(升序排列)。【sorted是生成個副本進行排序】。
12)切片[start:stop:step]:從列表中取出一部分元素生成一個新列表,start與stop默認爲None,step表示步長值,默認是一個接着一個切取,
若是爲2,則表示進行隔一取一操做。步長值爲正時表示從左向右取,若是爲負,則表示從右向左取。步長值不能爲0。
13)索引[index]:獲取索引位置index的值。

1四、元組(tuple),定義用"()":有序、重複,tuple和list很是相似,可是tuple是不可變對象,一旦初始化就不能修改,只讀,更安全。
元組只保證它的一級子元素不可變,對於嵌套的元素內部,不保證不可變!
若是可能,能用tuple代替list就儘可能用tuple。
最好以","結尾,當tuple只有一個元素時,必須以","結尾。 

元組對象方法:
1)count(self, value):統計元組中包含value元素的數量,返回一個int值。
2)index(self, value, start=None, stop=None):索引,查找元組中value元素第一個出現的位置,start與stop參數是查找起始與結束位置,默認爲None。

1五、for <元素> in <範圍>:,循環就是把每一個元素代入變量x,而後執行縮進塊的語句。
for _ in range(n):,使用下劃線"_",循環n次執行循環體。此時"_"做爲臨時性的名稱使用,忽略循環計數中的實際值。

1六、range(x1,x2,步長)函數,能夠生成一個整數序列,長度爲(x2-x1),左閉右開規則。range(n)範圍是"0 ~ n-1"17、不要濫用break和continue語句。break和continue會形成代碼執行邏輯分叉過多,容易出錯。
大多數循環並不須要用到break和continue語句。
(1)break只能用於循環體內。其效果是直接結束並退出當前循環,剩下的未循環的工做所有被忽略和取消。
(2)與break不一樣,continue語句用於跳過當前循環的剩餘部分代碼,直接開始下一輪循環。

1八、字典(dict),定義用{'k':'v'}:無序、不重複,字典是可變對象,在其餘語言中也稱爲map,使用可哈希算法的鍵-值("key":"value")存儲,具備極快的查找速度。字典無序。
經過in判斷key是否存在,若是key不存在,返回false,如:'Thomas' in d;

字典對象方法:
1)clear(self):清除字典中的全部元素。
2)copy(self):複製一份元組,至關於一次淺拷貝。 
3)fromkeys(self, iter, value=None):分別以iter中的元素爲鍵,以value爲值,建立一個字典。
4)get(self, k, d=None):獲取字典中鍵爲k的值,若是字典中不包含k,則給出d值,d默認爲None。
5)items(self):遍歷字典的一個方法,把字典中每對key和value組成一個元組,並把這些元組放在一個相似列表的dict_items中返回。
6)keys(self):遍歷字典鍵keys的一個方法,返回一個相似列表的dict_keys,與items方法用法相同。
7) values(self):遍歷字典值value的一個方法,返回一個相似列表的dict_values,與items方法用法相同。
8)pop(self, k, d=None):彈除並返回字典中鍵爲k的值。
9)popitem(self):從字典中隨機取出一組鍵值,返回一個新的元組。
10)setdefault(self, k, default=None):從字典中獲取鍵爲k的值,當存在k時,功能和get基本一致,當字典中不存在k時,在原字典上添加鍵爲k、值爲default的項,並返回default值。
11)update(self, E=None, **F):給字典新增元素,沒有返回值。用法:dict.update(dict2)。

1九、zip(iter1,...):組合函數,將對象逐一配對。依次取出每一個iter元素組合成tuple,可轉成list輸出。如,list(zip([1,2],['a','b'])) -->[(1,'a'),(2,'b')]。

20、dict內部存放的順序和key放入的順序是沒有關係的。
和list比較,dict有如下幾個特色:
1)查找和插入的速度極快,不會隨着key的增長而變慢;
2)須要佔用大量的內存,內存浪費多。

而list相反:
1)查找和插入的時間隨着元素的增長而增長;
2)佔用空間小,浪費內存不多。

21、集合(set),定義用set({})或{}賦值,定義空集合必須是set(),由於{}表示空字典。無序、不重複,集合是可變對象。
交集:set1 & set2,並集:set1 | set2,交集以外:set1 ^ set2 
固定集合(frozenset),不可變的集合。 
集合沒有讀取操做!由於集合既不支持下標索引,也不支持字典那樣的鍵取值。

集合對象方法:
1)add(self, *args, **kwargs):在集合裏添加一個元素,不生成新的集合。
2)clear(self, *args, **kwargs):清空集合裏面的元素,不生成新的集合。
3)copy(self, *args, **kwargs):淺拷貝集合,返回一個新集合。
4)difference(self, *args, **kwargs):傳入一個或多個參數集合對比,返回一個與參數集合不同元素的集合。
5)discard(self, *args, **kwargs):刪除集合中的某個元素,若是這個元素沒有在集合中,不作操做。
6)isdisjoint(self, *args, **kwargs):對比兩個集合,若空交集則返回True,沒有則返回False。
7)issubset(self, *args, **kwargs):判斷集合的包含關係,是不是參數集合的子集。
8)pop(self, *args, **kwargs):從集合中隨機(因集合無序)彈除並返回一個元素,若是集合爲空,則報TypeError錯誤。
9)remove(self, *args, **kwargs):移除集合中的一個元素,這個元素必須在集合中,若是不在,則報TypeError錯誤。
10)union(self, *args, **kwargs):兩個集合拼接返回一個新集合。
11)update(self, *args, **kwargs):更新集合,添加集合中沒有的新元素,不返回新集合。 

2二、"不可變對象":str、tuple;
"可變對象":list、dict、set;
對於不變對象來講,調用對象自身的任意方法,也不會改變該對象自身的內容;
好比,字符串雖然像列表同樣,經過方括號加下標的方式獲取它的子串,固然也包括切片操做,但這一切都不會修改字符串自己。

23、若是想定義一個什麼事也不作的空函數,能夠用pass語句,如:
def nop():
pass
實際上pass能夠用來做爲佔位符,好比如今還沒想好怎麼寫函數的代碼,就能夠先放一個pass,讓代碼能運行起來以至不報錯。

24、判斷數據類型用內置函數:isinstance(x,(int,float))。
查看數據類型用內置函數:type(obj)。

2五、raise TypeError('bad operand type'):拋出異常信息。

2六、包:必須包含一個"__init__.py"文件。
import importname[.modulename as newname] ,使用"as"能避免同名同API的包衝突。
from importname import * ,導入非私有的一切對象,使用"*"會調用該包的"__init__.py"模塊中"__all__"語句(模塊名、類名、方法名列表)。
相對導入:from ..dir import modulename。
將包或模塊放入"C:\Python\Lib\site-packages"中,對全部程序均可用。

2七、return(或return None),跳出函數。
函數能夠同時返回多個值,但其實就是一個tuple。

做用域:局部、全局(global)、外層(nonlocal)。如:

total = 0 # 全局變量
def outerfun():
x = 0 # 局部變量
global total # 聲明使用外部全局變量

def innerfun():
nonlocal x # 聲明內部函數使用外層的變量
return
return

2八、位置參數:傳參時,能夠直接寫值(這種方式必須按照順序傳參),也能夠是"參數名=值"(這種方式能夠不按順序傳參)。

默認參數:可看做是單一的字典參數,必須放位置參數以後!
定義默認參數要牢記一點:默認參數儘可能指向不變的對象!

備註:1.任何參數入參時均可以用"參數名=值"的方式指定入參。
2.使用" * "可總體傳入全部位置和默認參數,如def func(arg1,arg2,arg3) data=(1,2,3) func(*data)。

2九、可變參數(相似於重載):"*nums" 表示把nums這個"list""tuple"的多個元素做爲可變參數傳進去,定義函數時每每需配用for..in..,如:
不使用可變參數則可用元組或列表:
def calc(arg),用法:calc((arg1,arg2,arg3,));
使用可變參數則可直接輸入多個參數:
def calc(*arg),用法:calc(arg1,arg2,arg3)。
注意:可變參數以後的參數進行入參時,必須寫"參數名=值"的形式表達。可變參數,必須放在全部的位置參數和默認參數後面!

30、關鍵字參數(字典參數):"**kwargs"表示把kw這個dict的全部key-value用關鍵字形式傳入到函數的參數中,如:
def func(**kwargs):
print('keys:{0},vals:{1}'.format(kwargs.keys(),kwargs.values()))

用法(調用時必須帶上**): 
extra = {'city': 'Beijing', 'job': 'Engineer',...}
func(**extra) #等價於,func(**{'city': 'Beijing', 'job': 'Engineer',...})
或者一個一個地傳入鍵值:
func(city='Beijing', job='Engineer',...)。

注意:同可變參數相似,關鍵字參數,必須放在全部的位置參數和默認參數後面!
"萬能參數":當"*args""**kwargs"組合起來使用(有前後順序),理論上能接受任何形式和任意數量的參數。

3一、命名的關鍵字參數:限制關鍵字參數的名字,調用時帶上參數名。須要一個特殊分隔符"*""*"後面的參數被視爲命名關鍵字參數。
例如,只接收city和job做爲關鍵字的參數,如:
def person(name, age, *, city, job) ==> 調用時,必須帶上"city""job"參數名!如:person('nina', 21, city='shenzhen', job='管理')。
函數調用時不要帶上*3二、1)大多數編程語言沒有針對尾遞歸作優化,Python解釋器也沒有作優化,因此任何遞歸函數都存在棧溢出的問題。
遞歸核心思想:每一次遞歸,總體問題都要比原來減少,而且遞歸到必定層次時,能直接給出結果!

2)流程控制
一、if condition:
...
elif condition:
...
else: # else可選
...

if語句的簡單形式:exp if condition else val

二、while condition:
...
else: # else可選,循環結束後執行else語句
...

三、for el in iter: # 遍歷
...
else: # else可選,遍歷結束後執行else語句
...

四、備註:在Python中沒有"switch – case"語句。

3三、切片"[]":mylist['開始索引':'結束索引':'±步長'],"+"正向切片,"-"逆向切片。
注意:不包含結束索引的位置,若是要包含"結束索引"的值,請將"結束索引"加1。
tuple也能夠用切片操做,只是操做的結果還是tuple;
字符串也能夠當作是一種list,也能夠用切片操做,只是操做結果還是字符串。
字符串翻轉:str(mystr)[::-1]

3四、默認狀況下,"dict"迭代的是key。若是要迭代value,能夠用for value in d.values(),若是要同時迭代key和value,能夠用for k, v in d.items()。

35、判斷一個對象是可迭代:
from collections import Iterable
print(isinstance('12345',Iterable))

3六、函數enumerate():能夠把一個list的每一個元素變成"序號,元素"對(tuple)。

37、列表推導式。
['生成規則' for i in range(1, 11) if i % 2 == 0],使用[]轉成列表,生成的結果元素放前面(表達式),後面跟for循環。能夠for嵌套、if條件。
將循環結果進行了表達式運算並保存結果到列表中,直接打印出print(mylist)。

字典推導式。
{'鍵生成規則':'值生成規則' for k,v in iterable if condition},使用{}轉成字典,必須含有鍵值。

集合推導式。
{'生成規則' for i in range(1, 11) if i % 2 == 0},使用{}轉成集合。

3八、生成器(generator):只產生數據,不接收數據。建立一個生成器後,基本上不會調用next(),而是經過" for "循環來迭代它,而且不需關心StopIteration的錯誤。
第一種(相似於迭代),只要把一個列表生成式的[]改爲()。沒必要一次性建立整個list,而是迭代生成,從而節省大量的空間。如: 
gen=(i*i for i in range(1, 11) if i % 2 == 0)

第二種(相似於中斷(循環)),利用關鍵字"yield"則變成了生成器,yield只用於函數中,遇到yield語句中斷返回,再次執行時從上次返回的yield語句處繼續執行。例:
next(),返回下一個yield參數值;
send(msg),將msg做爲當前的yield表達式的返回值,並返回下一個yield參數值。

#斐波拉契數列#
def fib(max):
n=0
a,b=(0,1) # 利用tuple分別賦值
while n<max:
# print(b)
yield b # 產生數據
a,b=(b,a+b)
n+=1

for v in fib(6): # 通常使用for循環輸出
print(v)

#楊輝三角#
def yanghui(lines):
L=[1]
n=0
while n<=lines:
yield L
L = [1] + [L[x-1] + L[x] for x in range(1,len(L))] + [1]
n+=1
for v in yanghui(10):
print(*v) # "*"只輸出列表元素

39、可迭代(Iterable):實現了__iter__()方法,凡是可做用於for循環的對象都是Iterable類型,可迭代的類型有:list、tuple、dict、set、str等。 
迭代器(Iterator):實現__iter__()方法和next()方法,凡是可做用於"next()"函數的對象都是Iterator類型,它們表示一個惰性計算的序列,
能夠經過iter()函數得到一個迭代器(Iterator)對象。

__iter__():該方法返回一個迭代對象,return self ;
next():該方法拿到循環的下一個值。

區別:迭代器是一個對象(類),而生成器是一個函數。

40、高階函數:把函數做爲參數傳入,也就是"函數式編程"。
函數式編程的三個關聯概念:映射、過濾、下降處理。共同特色以函數和Iterable爲入參。其餘函數式:find, all, any
any():只要對象非空,或對象中某一個元素是"真元素"(非空、非0、True值),即返回True;
all():對象中全部元素是"真元素"時,返回True,可是對象爲空時(all([])、all({})、all('')),也返回True。

41、映射函數map(函數f,Iter):即映射,函數f依次做用到Iter的每一個元素,並把結果做爲新的Iterator返回。結果是個迭代器(Iterator)。

42、過濾函數filter(函數f,Iter):過濾,函數f依次做用到Iter的每一個元素上,若函數f返回True則留下該Iter的元素,若返回False則濾除掉該Iter的元素。

43、統計函數reduce(函數f,Iter):函數f(arg1,arg2),該函數f返回的結果又做爲arg1,這樣的函數f做用在Iter元素上進行累積計算。如,
from functools import reduce
reduce(lambda x,y: x*y, [1,2,3,4,5]) # return 120,或利用操做符模塊 reduce(operator.add, [1,2,3,4,5])

4四、函數sorted(Iter,<key=函數名>,<reverse=False>):排序。能夠經過函數完成自定義排序,該函數做用在Iter元素上。如:
d={'d':9,'b':2,'a':10,'c':3}
sorted(d.items(), key=lambda e:e[0], reverse=False) # e[0]自動迭代,按鍵排序

"冒泡排序":兩兩比較相鄰的元素,若是第一個比第二個大,就交換它們,以此類推。
ls = [87,90,45,23,100,98,12,67,99]
length = len(ls)
for i in range(length-1):
for j in range(length-1-i):
if ls[j] > ls[j+1]:
ls[j], ls[j+1] = ls[j+1], ls[j] # 直接在源列表中交換數據!

print(ls)

"選擇排序":首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,而後,再從剩餘未排序元素中繼續尋找最小(大)元素,而後放到已排序序列的末尾,以此類推。
ls = [87,90,45,23,100,98,12,67,99]
length = len(ls)
for i in range(length):
min_index = i
for j in range(i, length): # 從未排序的裏面找最小索引
if ls[j] < ls[min_index]:
min_index = j # 找到最小數的索引

ls[min_index], ls[i] = ls[i], ls[min_index]
print(ls)

"二分法":查找有序列表:
def bin_search(arr,findind):
mid = int(len(arr)/2)
if findind < 0:
print('不支持反查')
return 
if len(arr) == 0:
print('未找到,列表爲空。')
return

elif len(arr) == 1 and findind == 0:
print('找到了:',arr[0])
elif findind >= len(arr):
print('未找到,索引值溢出。')
return 
elif findind < len(arr):
if findind < mid:
bin_search(arr[:mid],findind) # 使用了遞歸。遞歸核心思想:每一次遞歸,總體問題都要比原來減少,而且遞歸到必定層次時,能直接給出結果!
elif findind > mid:
bin_search(arr[mid+1:],findind)
else:
print('找到了:',arr[mid])
return

45、一個函數能夠返回一個計算結果,也能夠返回一個函數。
返回一個函數時,牢記該函數並未執行,返回函數中不要引用任何可能會變化的變量。

46、當咱們在傳入函數時,有些時候,不須要顯式地定義函數,直接傳入匿名函數(λ)更方便。
lambda '參數': '返回值'。如,lam = lambda x: x**2,則可顯式調用lam(3)=9。
sorted.L(key=lambda ele: abs(ele)),隱式調用,會自動將列表L每一個元素傳入ele。

4七、偏函數:當函數的參數個數太多,須要簡化時,使用"functools.partial"能夠建立一個新的函數,這個新函數能夠固定住原函數的部分參數,從而在調用時更簡單。如:
int2 = functools.partial(int, base=2) # 修改默認參數值。int函數原先是十進制內容的字符,如今爲二進制內容的字符

48、模塊:一個.py文件就稱之爲一個模塊。最大的好處是大大提升了代碼的可維護性。
導入模塊:" from 包名 import 模塊名 "4九、if __name__=='__main__':
test()
這句話表示,僅當直接執行本模塊時,執行if代碼塊。當其餘模塊調用此模塊時,則忽略該代碼塊。

50、面向對象編程:Object Oriented Programming,簡稱OOP,是一種程序設計方法。OOP把對象做爲程序的基本單元,一個對象包含了數據和操做數據的方法。
具備封裝、繼承、多態三大特色。Python就是一種面向對象的語言,支持面向對象編程,在其內部,一切都被視做對象。
類是抽象的模板,實例是根據類建立出來的一個個具體的"對象",每一個對象都擁有相同的方法,但各自的數據可能不一樣。
class Student(object):
attrcls = value # 方法以外的屬性,稱做類屬性。類屬性是全部實例公有的屬性,每個實例均可以訪問、修改。
def __init__(self, attrobj): # 重寫object中__init__()方法初始化,可用super().__init__()調用父類的__init__()初始化。
self.attrobj = attrobj # 實例屬性寫在這裏!實例自己擁有的屬性。

class後面緊接着是類名,即Student,類名一般是大寫開頭的單詞,緊接着是繼承類(默認爲object,在builtins.py模塊中第720行~820行),表示該類是從哪一個類繼承下來的。

"self"通常用在實例方法中,表示只有實例對象能訪問,而類對象不能訪問。做用:調用自身(實例)的屬性或方法。
實例對象:能夠訪問實例屬性/方法和類屬性/方法;
類對象:只能訪問類屬性/方法。 
實例對象:stu=Student([args]),自動進行了兩個步驟,首先調用__new__()方法建立實例對象,而後調用__init__()初始化。

Python要麼是"public"要麼就是"private",通常要避免下劃線的使用:
1.以單下劃線開頭(_foo):建議性的私有成員,建議不要在外部訪問;
2.以雙下劃線開頭的(__foo):強制的私有成員,只能在類本身內部中使用;(可是仍是能夠強制經過"obj._類名__屬性名"成功訪問,因此Python的私有成員是""的)。
3.以雙下劃線開頭和結尾的(__foo__):魔法方法,即特殊方法專用的標識,一般狀況下是自動觸發調用的,如__init__()構造函數在初始化時自動調用。
特殊方法特殊使用,這類特殊方法能夠重定義,但不是同名調用,而是使用操做符或調用去掉雙"__"的方法。
一些魔法方法(或屬性):
__doc__:說明性文檔和信息。
__class__:表示當前操做的對象屬於哪一個類。
__dict__:列出類或對象中的全部成員。
__slots__:限制實例的變量(對繼承它的子類不起做用)。
__new__():建立實例時自動調用。
__init__():初始化時自動調用。
__del__():析構方法,當對象在內存中被釋放時,自動觸發此方法。
__getitem__()、__setitem__()、__delitem__():按索引方式(方括號)取值、賦值、刪除數據。
__iter__():迭代器方法。 
__str__()與__repr__():返回用戶看到的字符串,而__repr__()返回程序開發者看到的字符串,也就是說,__repr__()是爲調試服務的,一般二者代碼同樣便可。

5一、(1)封裝:將數據與具體操做的實現代碼放在某個對象內部,使這些代碼的實現細節不被外界發現,外界只能經過接口使用該對象,而不能經過任何形式修改對象內部實現。
(2)繼承:子類在調用某個方法或屬性時,首先在本身內部查找,若是沒有找到,則開始根據繼承機制在父類裏查找。
根據父類定義中的順序,以深度優先的方式逐一查找父類!(當一條路走到黑也沒找到的時候,才換另外一條路)。
可是,多條路的公共基類最後查找。
(3)多態:一個類實例能夠是該類的類型,也能夠是父類的類型,但不能夠是其子類的類型。

52、對於靜態語言(例如Java)來講,若是須要傳入Animal類型,則傳入的對象必須是Animal類型或者它的子類,不然,將沒法調用其中的方法。
對於Python這樣的動態語言("鴨子語言":若是某個對象調用某個方法,就沒必要管該對象屬於哪一個類,只要存在須要調用的方法便可)來講,
則不必定須要傳入Animal類型,咱們只須要保證傳入的對象有其方法就能夠了。

53、方法type(數據參數):返回數據類型。

54、函數與方法區別:
方法(類的)調用方式: 對象.方法名()
函數調用方式: 函數名(對象)
方法的第一個參數是自調參數(self),函數沒有自調參數。

5五、函數getattr(對象/類,屬性):獲取對象/類的屬性;
函數setattr(對象/類,屬性):設置對象/類的屬性;
函數hasattr(對象/類,屬性):判斷對象/類的屬性是否存在。

56、動態添加(綁定)屬性:
"對象名.新屬性名" = "" , 此方式添加的屬性只對該實例對象有效;
"類名.新屬性名" = "" , 此方式添加的屬性對全部實例對象有效;
"動態"缺點:沒法作屬性檢查,而自定義的"getter()""setter()"能夠作參數的檢查,如判斷等。

57、動態添加(綁定)方法:
"對象名.新方法名" = "已定義函數名" , 此方式添加的方法只對該實例對象有效;
"類名.新方法名" = "已定義函數名" , 此方式添加的方法對全部實例對象有效;

5八、變量__slots__=('屬性1','屬性2',...):限制類屬性,對象只能訪問和修改屬性,不能添加和移除屬性。但對繼承的子類是不起做用的。
若是沒有__slots__,類屬性存在於__dict__私有字典中。

hasattr(object, name):
判斷一個對象裏面是否有name屬性或者name方法,返回BOOL值,有name特性返回True, 不然返回False。

getattr(object, name[,default]):
獲取對象object的屬性或者方法,若是存在打印出來,若是不存在,打印出默認值,默認值可選。

setattr(object, name, values):
給對象的屬性賦值,若屬性不存在,先建立再賦值。

59、@property屬性裝飾器:把類的方法假裝成屬性調用的方式,也就是原本是Foo.func()的調用方法,變成Foo.func的方式。
通常用於私有屬性,把取值、賦值(getter()、setter())方法變成屬性,則能夠經過"obj.__attr"取值,經過"obj.__attr=val"賦值(最好使用私有屬性)。
@property 屬性裝飾器普遍應用在類的定義中,能夠控制屬性訪問,保證對參數進行必要的檢查,如判斷等,這樣,程序運行時就減小了出錯的可能性。
例:
class Money:
def __init__(self, dollars, cents):
self.__total_cents = dollars * 100 + cents

#獲取屬性,直接使用@property,取值-->obj.cents,至關於obj.getter()
@property
def cents(self):
return self.__total_cents % 100;

#設置屬性,使用@方法名.setter,賦值-->obj.cents=val,至關於obj.setter()
@cents.setter
def cents(self, new_cents):
self.__total_cents = 100 * self.dollars + new_cents

#刪除屬性
@cents.deleter
def cents(self):
return

#實例
m=Money(1,1)
m.cents #取值
m.cents=2 #賦值

@classmethod 類方法裝飾器,這樣,類對象就能夠調用該方法(classname.classmethod)。

1)@staticmethod :類方法裝飾器,其跟實例方法的區別是沒有"self"參數,而且能夠在類不進行實例化的狀況下調用;
2)@classmethod :靜態方法裝飾器,與實例方法的區別在於所接收的第一個參數不是"self"(類實例的指針),而是"cls"(當前類的具體類型);
3)@property :屬性裝飾器,表示能夠經過經過類實例直接訪問的信息。

60、Mixin:在設計類的繼承關係時,一般,主線都是單一繼承下來的,若是須要"組合"額外的功能,經過多重繼承就能夠實現,這種設計一般稱之爲Mixin(混合)。
Mixin類通常以Mixin爲後綴,使用Mixin類實現多重繼承須要注意:
1)首先,它必須表示某一種輔助功能,而不是某個事物;
2)其次,它必須功能單一,若是有多個功能,那就寫多個Mixin類;
3)再者,它不依賴於子類的實現;
4)最後,子類即使沒有繼承這個Mixin類,也照樣能夠工做,就是缺乏了某個功能(好比飛機照樣能夠載客,就是不能飛了^_^)。

6一、1)動態建立類:經過type()函數建立的類和直接寫class是徹底同樣的,由於Python解釋器遇到class定義時,僅僅是掃描一下class定義的語法,而後調用type()函數建立出class。
myclass=type('MyClass',(baseclass,),{'func':exfun})
說明:'MyClass':類名; 
(baseclass,):繼承類,用tuple; 
{'func':exfun}:類方法,dict型,其中exfun是外部定義好的方法。

2)元類(metaclass):元類建立類(修改當前類),而類建立實例。(不多狀況使用。抽象基類、ORM中有應用)
定義:class Name_metaclass(type): # 必須傳入type
def __new__(cls, name, bases, attrs): # cls當前準備建立的類;name類名,即"Name_metaclass";
pass # bases父類集合;attrs類的方法集合。
return type.__new__(cls, name, bases, attrs)

62、捕獲異常
try:
pass
except Exception as e: # 捕獲異常,儘可能指定精確的異常類(類名首字母大寫)
pass # 處理異常
raise # 主動拋出一個異常,讓上層調用者處理。程序不會往下執行。若是沒有拋出,程序會繼續往下執行。
else# 可選,沒有異常時執行
pass
finally: # 可選,老是被執行
pass
當認爲某些代碼可能會出錯時,就能夠用try來運行這段代碼,若是執行出錯,則後續代碼不會繼續執行,而是直接跳轉至錯誤處理代碼,
即except語句塊,執行完except後,若是有finally語句塊(非必需),則執行finally語句塊,至此,執行完畢。
全部的錯誤類型都繼承自BaseException,因此在使用except時須要注意的是,它不但捕獲該類型的錯誤,還把其子類也"一網打盡"。

錯誤和異常:
錯誤,機器出現的錯誤不須要處理。
異常,程序運行而能自動識別的異常,通常要捕獲處理(當即處理或上拋給調用者)。系統異常與邏輯異常。

63、若是要打印錯誤追蹤,導入logging,如:
import logging
...
except Exception as e:
logging.exception(e) #不須要print(),直接輸出錯誤日誌追蹤。

64、拋出異常
a、raise Exception('str')
b、raise # raise語句若是不帶參數,就會把當前錯誤原樣拋出給調用者。

65、調試。
(1)使用斷言"assert"語句。面向開發者設計,用於程序的調試。
凡是用print()來輔助查看的地方,均可以用斷言(assert)來替代。
語法:assert '表達式', '輸出假結果提示' 
其中,若"表達式"爲假,程序終止,並給出"輸出提示";爲真,程序繼續執行,無輸出提示。

(2)使用"logging"日誌模塊,服務端寫入日誌,還能夠經過http get/post,socket,email寫入日誌。
例:
logging.basicConfig(level=logging.DEBUG, 
format='%(asctime)s \t %(filename)s \t [line:%(lineno)d] \t %(levelname)s \t %(message)s', 
datefmt='%a, %d %b %Y %H:%M:%S', 
filename='/test.log', 
filemode='w') 
logging.debug('debug message') 
logging.info('info message') 
logging.warning('warning message') 
logging.error('error message') 
logging.critical('critical message') 

參數說明:
level:設置日誌最低級別,默認是WARNING,打印出此級別及以上的信息;
format:指定日誌顯示格式;
datefmt:指定日期時間格式;
filename:日誌存儲指定的文件,默認是控制檯輸出;
filemode:文件打開方式;

其中format參數值說明:
%(name)±10s:Logger的名字(+10s寬度爲10的字符串,右對齊; -左對齊)
%(levelno)s:數字形式的日誌級別
%(levelname)s:文本形式的日誌級別
%(message)s:用戶輸出的消息
%(pathname)s:調用日誌輸出函數的模塊的完整路徑名,可能沒有
%(filename)s:調用日誌輸出函數的模塊的文件名
%(module)s:調用日誌輸出函數的模塊名
%(funcName)s:調用日誌輸出函數的函數名
%(lineno)d:調用日誌輸出函數的語句所在的代碼行
%(created)f:當前時間,用UNIX標準的表示時間的浮點數表示
%(relativeCreated)d:輸出日誌信息時的,自Logger建立以 來的毫秒數
%(asctime)s:字符串形式的當前時間,默認格式是 "2003-07-08 16:49:45,896",逗號後面的是毫秒
%(thread)d:線程ID。可能沒有
%(threadName)s:線程名。可能沒有
%(process)d:進程ID。可能沒有 

(3)單元測試(標準庫 unittest) 測試驅動開發(TDD)
單元測試是用來對一個模塊、一個函數或者一個類來進行正確性檢驗的測試工做。

編寫一個測試類,從unittest.TestCase繼承,測試方法必須以"test"開頭,不然不被認爲是測試方法,測試的時候不會被執行。
對每一類測試都須要編寫一個"test_xxx()"方法,因爲unittest.TestCase提供了不少內置的條件判斷,咱們只須要調用這些方法就能夠斷言輸出是不是咱們所指望的。
能夠在單元測試中編寫兩個特殊的"setUp()"(初始化、鏈接庫等)和"tearDown()"(清除對象、關閉鏈接等)方法,這兩個方法會分別在每調用一個測試方法的先後分別被執行。

最經常使用的斷言assertEqual(first,second,msg),與指望值對比是否相等。另外一種重要的斷言assertRaises(exception),期待拋出指定類型的異常。
最後運行單元測試:if __name__ == '__main__':
unittest.main()

第三方庫 pytest:
安裝:pip install pytest (管理員cmd,"pip""easy_install"是Python的安裝工具)
測試樣例能夠寫在類中,也能夠直接寫模塊中。
與unittest相似,提供setup和teardown函數。可是斷言只用原始的assert便可。
運行單元測試:在CMD中執行單元測試文件,命令 "pytest -q testname.py" (-q會清除版本信息,testname爲文件名)
生成log結果文件:"pytest testname.py --resultlog=filename.txt"
例:TestAdd.py
def setup():
print('start...')
def teardown():
print('end...')
def test_add():
assert MyAdd.add((1, 2, 0)) == 6, '計算有誤!'
cmd執行:pytest -q TestAdd.py

(4)性能測試cProfile,用C語言實現。
# 測試內容爲test函數,測試結果輸出到filename,按cumtime列排序。若是沒指定filename,則輸出到控制檯。
# filename保存的是二進制文件
cProfile.run("test()", filename="result", sort="cumtime")

測試結果是二進制文件,Python提供了一個"pstats"模塊,用來分析cProfile輸出的文件內容:
p = pstats.Stats("result")
p.strip_dirs().sort_stats('').print_stats() # strip_dirs(): 去掉無關的路徑信息
# sort_stats(): 排序,支持的方式和上述的一致
# print_stats(): 打印分析結果,能夠指定打印前幾行;參數爲小數,表示前百分之幾的函數信息

66、閉包:若是外部函數裏有內部函數,內部函數對上一層的外部函數做用域(但不是在全局做用域)的變量進行引用,那麼內部函數就被認爲是閉包(closure)。
"裝飾器就是一種閉包!"
調用外部函數傳遞的參數就是自由變量。
簡單說,閉包就是根據不一樣的配置信息獲得不一樣的結果。 
用途1:當閉包執行完後,仍然可以保持住當前的運行環境。(相似靜態變量)
用途2:閉包能夠根據外部做用域的局部變量來獲得不一樣的結果。(這有點相似配置功能(註冊),咱們能夠修改外部的變量,閉包根據這個變量展示出不一樣的功能。)
如:
def exfunc(x):
def clofunc(y):
return x + y
return clofunc
調用:f=exfunc(6) # x=6,返回了內部函數clofunc賦給f,即此時調用內部函數,"由外而內"。
print(f(8)) # y=8,結果14

67、裝飾器(decorator):使用@調用裝飾器。在不更改原函數的狀況下,該函數被調用前,擴展該函數功能。
故裝飾器以函數入參,並返回內部函數。例:
1)函數裝飾器
def deco(func): # 函數裝飾器,故以函數爲參數
# @functools.wraps(func) # 能夠加上此語句,確保wrapper()函數的名稱、docstring與原函數相同
def _wrap(*args2, **kw2): # 內部函數,"*args2,**kw2",表示可接收任何參數
print('調用了%s()' % func.__name__)
return func(*args2, **kw2) # 返回入參函數
return _wrap # 返回內部函數,閉包。

使用:
@deco #等價語句:now = deco(now) 。一般裝飾器沒參數,若是裝飾器帶參,則在裝飾器定義時再外套一層函數名並返回內嵌函數。
def now():
print('2017-5-4')

2)類方法裝飾器
使用:
@method_decorator(decorator_name) # 參數decorator_name指裝飾器的調用
def func():
...

68、IO:涉及到數據交換的地方,一般是磁盤、網絡等,就須要IO接口。
從磁盤【讀】文件到內存,就只有【Input】操做,反過來,把數據【寫】到磁盤文件裏,就只是一個【Output】操做。
現代操做系統不容許普通的程序直接操做磁盤,因此,讀寫文件就是請求操做系統打開一個文件對象(一般稱爲文件描述符)。

69、Python中,全部具備read和write方法的對象,均可以歸類爲file類型。Python內置了一個open()方法,用於對文件進行讀寫操做。
open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None):
參數errors='ignore',若是遇到編碼錯誤後忽略處理。
-----------------------------------------------------------------------------------------------------
r | 只讀 | 默認模式,若是文件不存在就報錯,存在就正常讀取。 
----------------------------------------------------------------------------------------------------- 
w | 只寫 | 若是文件不存在,新建文件而後寫入;若是存在,先清空文件內容,再寫入。 
-----------------------------------------------------------------------------------------------------
a | 追加 | 若是文件不存在,新建文件,而後寫入;若是存在,在文件的最後追加寫入。 
-----------------------------------------------------------------------------------------------------
x | 新建 | 若是文件存在則報錯,若是不存在就新建文件,而後寫入內容,比w模式更安全。 
-----------------------------------------------------------------------------------------------------
b | 二進制模式 | 好比rb、wb、ab,以bytes類型操做數據 
-----------------------------------------------------------------------------------------------------
+ | 讀寫模式 | 好比r+、w+、a+ 
-----------------------------------------------------------------------------------------------------
對於"w+"模式,在讀寫以前都會清空文件的內容,建議不要使用!
對於"a+"模式,永遠只能在文件的末尾寫入,有侷限性,建議不要使用!
對於"r+"模式,也就是讀寫模式,配合seek()和tell()方法,能夠實現更多操做。

讀文件:
f.read(size):讀取必定大小的數據, 而後做爲字符串或字節對象返回。
f.readline():讀取一行內容。
f.readlines():讀取全部行,一行一行讀入列表中。
f.tell():獲取當前文件指針位置(字節數)。
f.seek(offset, whence=1):移動文件指針(字節數)。offset 偏移量,whence=0 從文件開頭計算,whence=1 從當前位置計算,whence=2 從文件末尾計算。
f.close():關閉文件對象。

不管讀寫,都先打開(open)文件的路徑,即入口。
例:try:
f=open('D:\Personal\Desktop\PyNote.py','r') #先打開文件
print(f.read()) #一次性所有讀取
except IOError as e:
print('讀入文件出錯',e,sep='||')
finally:
f.close() #不管如何須要關閉流

*推薦使用:另外一種簡潔讀文件方法(沒必要調用close()方法),使用" with...as... "上下文管理器,操做文件IO是個好習慣:
with open('D:\Personal\Desktop\PyNote.py','r') as file:
print(file.read()) 

70、寫文件:
當咱們寫文件時,操做系統每每不會馬上把數據寫入磁盤,而是放到內存緩存起來,空閒的時候再慢慢寫入。
只有調用close()方法時,操做系統才保證把沒有寫入的數據所有寫入磁盤。
忘記調用close()的後果是數據可能只寫了一部分到磁盤,剩下的丟失了。因此,仍是用with語句來得保險,例:
*推薦使用:
with open('D:\Personal\Desktop\PyNote1.txt','w',encoding='utf8') as file:
file.write('寫文件!') #返回字符長度

71、字符流(StringIO)。StringIO和BytesIO是在內存中操做str和bytes的方法,使得和讀寫文件具備一致的接口。流必須先讀出來再寫入文件中。
from io import StringIO,並先建立一個StringIO實例。如下例一、2都可用getvalue()方法獲取流。
例1:使用write()寫入流中。
f=StringIO() #建立一個StringIO實例
f.write('字符流IO')
print(f.getvalue()) #用getvalue()方法獲取流。
#write()結束後指針在末尾,使用方法tell()能知道指針位置,因此read()方法讀取不到。
#除非用方法seek(i)將指針定位開始位置,則能夠用read()方法讀取。
例2:初始化流,用read()方法讀取流。
f = StringIO('Hello!\nHi!\nGoodbye!') #初始化流,指針在開頭
while True:
s = f.readline() #可用read()方法讀取流
if s == '':
break
print(s.strip()) #strip()去除首尾空格
72、字節流(BytesIO)。相似於字符流。如下例一、2都可用getvalue()方法獲取流。
例1:使用write()寫入流中。
from io import BytesIO
b=BytesIO() #建立一個BytesIO實例
b.write('字節流'.encode()) 
print(b.getvalue()) #用getvalue()方法獲取流。
#write()結束後指針在末尾,使用方法tell()能知道指針位置,因此read()方法讀取不到。
#除非用方法seek(i)將指針定位開始位置,則能夠用read()方法讀取。
例2:初始化流,用read()方法讀取流。
b=BytesIO('字節流'.encode()) #初始化流,指針在開頭
print(b.read()) #可用read()方法讀取流

7三、目錄與路徑:導入os包,import os (當前文件路徑:sys.argv[0])
(1)建立目錄:os.mkdir('目錄')
(2)刪除目錄:os.rmdir('目錄')
(3)返回目錄列表:os.listdir('目錄'),返回的是文件列表,而非完整路徑。
(4)返回絕對路徑:os.path.abspath('路徑'),其中的‘路徑’也能夠是指定的完整路徑。當‘路徑’是"."表示當前完整目錄。
(5)拼接路徑(處理不一樣操做系統路徑規則):os.path.join('D:\Personal','mydir') -->結果:'D:\Personal\mydir'6)返回目錄:os.path.dirname('D:\Personal\Desktop\mydir.py') -->結果:'D:\Personal\Desktop'7)拆出目錄和文件名:os.path.split('D:\Personal\Desktop\mydir.py') -->結果:'D:\\Personal\\Desktop''mydir.py'8)拆出擴展名:os.path.splitext('D:\Personal\Desktop\mydir.py') -->結果:'D:\\Personal\\Desktop\\mydir''.py'9)返回文件名(含擴展名):os.path.basename('D:\Personal\Desktop\mydir.py') -->結果:'mydir.py'10)文件最後修改時間戳:os.path.getmtime('路徑') 
(11)目錄樹:os.walk('路徑')

變量 "__file__" :能夠獲取到當前文件的路徑!

解壓與壓縮(import gzip)。
解壓(讀):
f = gzip.open('file.txt.gz', 'rb') #打開解壓路徑
file_content = f.read() #直接解壓
f.close()

壓縮(寫):
air=open('Air.xml')
fh=StringIO(air.read()) #字符流緩存
airzip=gzip.open('AirZip.xml.gz','wb') #打開壓縮路徑
airzip.write(fh.getvalue().encode()) #直接壓縮
air.close()
airzip.close()

備註:
os :負責程序與操做系統的交互,提供了訪問操做系統底層的接口;
sys:負責程序與python解釋器的交互,提供了一系列的函數和變量,用於操控python的運行時環境;
platform:提供操做平臺信息的模塊,如是Windows平臺仍是Linux平臺。

#********************** os內置模塊 **********************#
os.name 查看當前操做系統的名稱。windows平臺下返回"nt",Linux則返回"posix"
os.curdir 等價於".",表示當前目錄
os.pardir 等價於"..",表示上級目錄
os.getcwd() 取當前工做目錄名
os.chdir() 切換工做目錄,至關於shell下的cd
os.chmod() 改變目錄權限 
os.rename(oldname, newname) 重命名文件
os.walk() 生成目錄樹下的全部文件名
os.mkdir/makedirs('dirname') 建立目錄/多層目錄
os.rmdir/removedirs('dirname') 刪除目錄/多層目錄
os.remove('path/filename') 刪除文件
os.listdir('dirname') 列出指定目錄的文件 
os.path.basename('path/filename') 去掉目錄路徑,返回文件名
os.path.dirname('path/filename') 去掉文件名,返回目錄路徑
os.path.join(path1[,path2[,...]]) 將分離的各部分組合成一個路徑名
os.path.split('path') 返回(dirname(), basename())元組
os.path.splitext() 返回(filename, extension)元組
os.path.getatime/ctime/mtime() 分別返回最近訪問、建立、修改時間(時間戳)
os.path.getsize() 返回文件大小(字符數)
os.path.exists() 是否存在
os.path.isabs() 是否爲絕對路徑
os.path.isdir() 是否爲目錄
os.path.isfile() 是否爲文件

#********************** sys內置模塊 **********************#
sys.argv 命令行參數List,第一個元素是程序自己路徑
sys.hexversion 獲取Python解釋程序的版本值,16進制格式如:0x020403F0
sys.version 獲取Python解釋程序的版本信息
sys.maxint 最大的Int值
sys.maxunicode 最大的Unicode值
sys.modules 返回系統導入的模塊字段,key是模塊名,value是模塊
sys.path 返回模塊的搜索路徑,初始化時使用'PYTHONPATH'環境變量的值
sys.platform 返回操做系統平臺名稱 
sys.exec_prefix 返回平臺獨立的python文件安裝的位置
sys.byteorder 本地字節規則的指示器,big-endian平臺的值是'big',little-endian平臺的值是'little'
sys.copyright 記錄python版權相關的東西
sys.api_version 解釋器的C的API版本
sys.stdin 標準輸入
sys.stdout 標準輸出
sys.stderr 錯誤輸出
sys.modules.keys() 返回全部已經導入的模塊列表
sys.exc_info() 獲取當前正在處理的異常類,exc_type、exc_value、exc_traceback當前處理的異常詳細信息
sys.exit(n) 退出程序,正常退出時exit(0)
sys.exc_clear() 用來清除當前線程所出現的當前的或最近的錯誤信息 
sys.stdin input()調用了sys.stdin.read()
sys.stdout write()調用了sys.stdout.write()
sys.stderr

7四、(1)(a)pickle序列化:把對象轉成字節(持久化二進制文件)。常常遇到在Python程序運行中獲得了一些字符串、列表、字典等數據,
想要長久的保存下來,方便之後使用,而不是簡單的放入內存中關機斷電就丟失數據。它能夠將對象轉換爲一種能夠傳輸或存儲的格式。如:
import pickle
1. pickle.dumps(obj):將Python數據序列化爲bytes字符串,帶"s"即str。

2. pickle.dump(obj, file):將Python數據序列化到文件內。
file=open('D:\Personal\Desktop\mypy.txt','wb') # 'wb',以字節寫入
pickle.dump(obj,file,protocol=0) # 不帶字母"s"的方法與文件相關。protocol=0 爲ASCII,1是舊式二進制,2是新式二進制協議
file.close() 

3. pickle.loads(bytes_object):反序列化,將pickle格式的bytes字符串轉換爲python類型。

3. pickle.load(file):反序列化,從pickle格式的文件中讀取數據並轉換爲python類型。
file=open('D:\Personal\Desktop\myp1y.txt','rb') # 'rb',以字節讀取
pickle.load(file) # 反序列,load,將字節轉成Python對象
file.close()

pickle序列化的缺點:1.只能用於Python,而且可能不一樣版本的Python彼此都不兼容。2.不安全。

(b)shelve:字典式持久化。它依賴於pickle模塊,但比pickle用起來簡單。它的用法和字典相似,支持全部字典類型的操做。
shelve.open(filename, flag='c', protocol=None, writeback=False):建立或打開一個shelve對象。
參數:writeback=True 優勢是,能夠動態修改數據,並減小出錯的機率。缺點是,在open()的時候會增長額外的內存消耗。

(2)struct結構體:相似C語言的結構體,包含不一樣類型的數據。將特定的結構體類型打包成字節型數據(二進制流)而後再網絡傳輸,
而接收端也應該能夠經過某種機制進行解包還原出原始的結構體數據。網絡通訊當中,大多傳遞的數據是以二進制流存在的。
import struct # 打包方法:pack(fmt,values)
bin_data = struct.pack('>i3sf', 1, b'abc', 2.7) # 按格式打包成字節,">"字節順序,"i"32位整型,"3s"長度爲3的字符串,"f"浮點型。
# 字符串須要轉成字節,且指定長度。 
struct.unpack('>i3sf',bin_data) # 解析,解包還原成Python對象,返回元組 
struct.calcsize(fmt):用於計算格式字符串所對應的結果的長度,如:struct.calcsize(‘ii’),返回8。由於兩個int類型所佔用的長度是8個字節。
或:
strc=struct.Struct(fmt) # Struct類,初始化打包/解包格式fmt
strc.pack(data)
strc.unpack(bin_data)

75、json序列化(持久化,結果必定是雙引號格式,而且不能有多餘的逗號)。json不只是標準格式,而且比XML更快,並且能夠直接在Web頁面中讀取,很是方便。
json是一種輕量級的數據交換格式,json是跨語言,跨平臺的,便於接口數據交互。

json序列化:
import json
json.dumps(dic_obj, indent=4) # 參數是字典類型,dumps將Python對象轉成json格式(字符串)。indent=4 縮進格式

json反序列化(解析):
json_str='{"name":"wcw","addr":"bj"}' # 注意用單引號包起來
inv_json=json.loads(json_str) # loads加載json數據轉成Python對象
print(inv_json) # 結果是字典

類對象的json序列化:
stu = Student('wcw',20,100) # 實例
json.dumps(stu.__dict__, indent=4) # 用內置屬性__dict__

pickle也能夠對類對象序列化!

76、多線程(threading)。
Python的標準庫提供了兩個模塊:threading和_thread。_thread是低級模塊,threading是高級模塊,絕大多數狀況下,只使用threading這個高級模塊。
multiprocessing模塊的徹底模仿了threading模塊的接口,兩者在使用層面,有很大的類似性。

一些屬性與方法:
os.getpid():獲取操做系統的進程ID。
threading.current_thread():返回當前線程。
getName(),setName():獲取,設置線程/進程名稱。
start():開啓線程/進程。
terminate():強制終止線程/進程。
is_alive():線程/進程是不是激活狀態。
setDaemon():把子線程/進程都設爲主線程的守護線程/進程,當主線程結束後,守護子線程/進程也會隨之結束。必須在start()以前。
join([timeout]):使子線程/進程按順序執行,timeout是執行超時時間。

有兩種方式來建立線程:一種是自定義線程類,即繼承Thread類,並重寫它的run()方法;
另外一種是在實例化threading.Thread對象的時候,將線程要執行的任務函數做爲參數傳入線程。

1)自定義線程類:
class Threads(threading.Thread):
def __init__(self,name):
super(Threads, self).__init__()
self.name=name 
def run(self): # 重寫run()方法
time.sleep(1)
print('{0}啓用線程:{1}'.format(self.name,threading.current_thread())) 

if __name__ == '__main__':
t= Threads('ThrName')
t.start()
t.join()
print('end...')

2)實例化Thread:
# 寫個任務函數
def dowaiting():
t1 = time.time()
print('進入線程:', datetime.datetime.fromtimestamp(t1).time())
time.sleep(2)
t2 = time.time()
print('退出線程:', datetime.datetime.fromtimestamp(t2).time())

if __name__ == '__main__':
thr = threading.Thread(target=dowaiting) # 實例化Thread,傳入任務函數
thr.start()
time.sleep(1)
print('join開始')
thr.join()
print('join結束')

77、線程鎖:當多個線程同時操做一個對象,若是沒有很好地保護該對象,會形成程序結果的不可預期,這被稱爲「線程不安全」。
爲了保證數據安全,咱們設計了線程鎖,即同一時刻只容許一個線程操做該數據。 

(1)互斥鎖(Lock):互斥鎖是一種獨佔鎖,同一時刻只有一個線程能夠訪問共享的數據。
使用很簡單,初始化鎖對象,而後將鎖當作參數傳遞給任務函數,在任務中加鎖,使用後釋放鎖。
例:
num = 0
def plus(lk):
global num # global聲明此處的num是外面的全局變量num
with lk: # 全部的線程鎖都有一個加鎖和釋放鎖的動做,很是相似文件的打開和關閉。能夠用"with"上下文管理器。
for _ in range(10000):
num += 1
print('子線程%s結束,num = %d' % (threading.current_thread().getName(), num))

if __name__ == '__main__':
lock = threading.Lock() # 實例化互斥鎖
for i in range(2):
t = threading.Thread(target=plus, args=(lock,), name='-互斥鎖線程-')
t.start()
time.sleep(2) # 等待2秒,確保2個子線程都已經結束運算
print("主線程執行完畢後,num = ", num)

(2)信號量鎖(Semahpore):這種鎖容許必定數量的線程同時更改數據,它不是互斥鎖。
好比地鐵安檢,排隊人不少,工做人員只容許必定數量的人進入安檢區,其它的人繼續排隊。
例:
def testsema(n, se):
with se:
print('運行第%d個線程。' % n)
time.sleep(1)

if __name__ == '__main__':
semas = threading.Semaphore(5)
for i in range(1, 21):
thr = threading.Thread(target=testsema, args=(i, semas))
thr.start()

(3)事件鎖(Event):全局定義了一個"Flag",若是Flag值爲True,線程再也不阻塞。若是Flag的值爲False,那麼當程序執行wait()方法時就會阻塞。
事件主要提供了四個方法set()、wait()、clear()和is_set():
set():將事件的Flag設置爲True,不阻塞。
clear():將事件的Flag設置爲False,阻塞。 
wait():等待Flag值。
is_set():判斷當前Flag值。
例:
event = threading.Event()
def lighter():
green_time = 3 # 綠燈時間
red_time = 3 # 紅燈時間
event.set() # 初始設爲綠燈
while True:
print("\33[32;0m 綠燈亮...\33[0m")
time.sleep(green_time)
event.clear()
print("\33[31;0m 紅燈亮...\33[0m")
time.sleep(red_time)
event.set()

def run(name):
while True:
if event.is_set(): # 判斷當前是否"放行"狀態
print("一輛[%s] 開過去了..." % name)
time.sleep(1)
else:
print("一輛[%s] 看到紅燈,當即停下了..." % name)
event.wait()
print("[%s] 看到綠燈亮了,當即走起..." % name)

if __name__ == '__main__':
light = threading.Thread(target=lighter,)
light.start()
for name in ['東風', '吉利', '奇瑞']:
car = threading.Thread(target=run, args=(name,))
car.start() 

(4)線程通信,同進程通訊queue。(見80節)

78、全局解釋器鎖(GIL)。
在大多數環境中,單核CPU狀況下,本質上某一時刻只能有一個線程被執行,多核CPU時則 能夠支持多個線程同時執行。
可是在Python中,不管CPU有多少核,同時只能執行一個線程。這是因爲GIL的存在致使的。
Python中想要充分利用多核CPU,就用多進程。由於每一個進程有各自獨立的GIL,互不干擾,這樣就能夠真正意義上的並行執行。
在Python中,多進程的執行效率優於多線程(僅僅針對多核CPU而言)。建議在IO密集型任務中使用多線程,在計算密集型任務中使用多進程。
另外,深刻研究Python的協程機制,會有驚喜的。

79、多進程(multiprocessing)。Python提供了很是好用的多進程包multiprocessing。
python中的多線程沒法利用多核優點,若是想要充分地使用多核CPU的資源(os.cpu_count()查看),則使用多進程。
須要再次強調的一點是:與線程不一樣,進程是獨立的,沒有任何共享狀態,進程修改的數據,改動僅限於該進程內。 

任何進程默認就會啓動一個線程,咱們把該線程稱爲主線程。
對於操做系統來講,一個任務就是一個進程(Process)。有些進程還不止同時幹一件事,把進程內的這些"子任務"稱爲線程(Thread)。
線程是最小的執行單元,而進程由至少一個線程組成。

!注意:在Windows中進程類Process必須放到" if __name__ == '__main__' "下,顯然這隻能用於調試和學習,不能用於實際環境。

(1)實例進程類Process
if __name__=='__main__': # 必須在main中執行
p=Process(target='子進程代碼塊',name='自定義子進程名',arg=('子進程的參數',),kwargs={'子進程字典'}) # 實例一個子進程,target傳入函數,arg是元組。
p.start() # 運行進程,自動調用run()方法
p.join([timeout]) # 子進程/線程的執行超時時間(默認直到執行結束)
p.terminate() # 強制終止進程,不會進行任何清理操做,不會釋放鎖,進而致使死鎖,當心使用
p.is_alive() # 若是子進程仍然運行,返回True
2)自定義進程類
class ClsProcess(multiprocessing.Process):
def __init__(self, intv):
super(ClsProcess, self).__init__()
self.intv = intv
def run(self): # 重寫run()方法
n = 3
while n > 0:
print('如今時間是:{0}'.format(time.ctime()))
time.sleep(self.intv)
n -= 1
if __name__ == '__main__':
p = ClsProcess(1)
p.start() # 自動調用類中的run()方法。
p.join()

進程鎖:
與threading相似,在multiprocessing裏也有同名的鎖類Lock,Semaphore和Event等,連用法都是同樣同樣的,這一點很是友好!
進程之間數據不共享,加鎖的目的是爲了保證多個進程修改同一塊數據時,同一時間只能有一個修改,即串行的修改,沒錯,速度是慢了,犧牲了速度而保證了數據安全。

例:進程互斥鎖Lock,與線程互斥鎖用法類似:
def work(filename, lock): # 模擬買票,給任務加鎖
with lock: # 添加進程鎖參數,因爲進程鎖也是上下文(__enter__爲acquire(),__exit__爲release()),因此可以使用with處理
with open(filename, encoding='utf-8') as f:
dic = json.loads(f.read())
print('剩餘票數: %s' % dic['count'])
if dic['count'] > 0:
dic['count'] -= 1
time.sleep(random.randint(1, 3)) # 模擬網絡延遲
with open(filename, 'w', encoding='utf-8') as f:
f.write(json.dumps(dic))
print('%s 購票成功' % os.getpid())
else:
print('%s 購票失敗' % os.getpid())

if __name__ == '__main__':
lock = Lock() # 使用進程鎖,傳入"任務"的參數中
for i in range(5):
p = Process(target=work, args=('db.json', lock))
p.start()
p.join()

80、線程/進程通訊:線程/進程彼此之間互相隔離,要實現線程/進程間通訊,Python提供了隊列queue(線程通訊)、管道Pipe(進程通訊)等多種方式來交換數據。
(1)消息隊列Queue([maxsize])。隊列先進先出,底層以管道加鎖的方式實現。
生產者消費者模式是經過一個容器來解決生產者和消費者的強耦合問題。
生產者和消費者彼此之間不直接通信,而經過阻塞隊列來進行通信,因此生產者生產數據以後不用等待消費者處理,直接扔給阻塞隊列,
消費者不找生產者要數據,而是直接從阻塞隊列裏取,阻塞隊列就至關於一個緩衝區,平衡了生產者和消費者的處理能力。
例:
import queue
## 生產者,隊列q入參
def producer(q,data):
for item in data:
time.sleep(random.randint(1, 2))
print('生產者生產了:%s' % item)
q.put(item) # 數據放入隊列中
## 消費者,隊列q入參
def consumer(q):
while True: # 循環取數據
time.sleep(random.randint(1, 2))
res = q.get() # 從隊列中取數據。get_nowait():不須要一直等待,一旦隊列空了,則拋出異常,此時能夠捕獲它
if res is None: break
print('消費者拿到了:%s' % res)
if __name__ == '__main__':
que = queue.Queue() # 使用隊列通訊

# 生產者和消費者分別開啓線程,而後通訊
pro = threading.Thread(target=producer, args=(que,[1, 2, 3]))
con = threading.Thread(target=consumer, args=(que,))
pro.start()
con.start()
pro.join()
print('主線程')

que.empty():調用此方法時que爲空則返回True,該結果不可靠,好比在返回True的過程當中,若是隊列中又加入了項目。
que.full() :調用此方法時que已滿則返回True,該結果不可靠,好比在返回True的過程當中,若是隊列中的項目被取走。

(2)管道Pipe([duplex]):管道是雙工通訊模式。
在進程之間建立一條管道,並返回元組(conn1,conn2),其中conn1,conn2表示管道兩端的鏈接對象,強調一點:必須在產生Process對象以前產生管道。
參數dumplex:默認管道是全雙工的;若將duplex設成False,管道是單工,conn1只能用於發送,conn2只能用於接收。
例:
from multiprocessing import Pipe
def prodctor(p, data):
psend, precv = p
# precv.close()
for d in data:
psend.send(d)
time.sleep(0.5)
else: # 循環結束時
psend.close()

def consumer(p, name):
psend, precv = p
# psend.close()
while True:
try:
chanpin = precv.recv()
print('{0}獲取產品:{1}'.format(name, chanpin))
except EOFError:
precv.close()
break

if __name__ == '__main__':
psend, precv = Pipe()

# 生產者和消費者分別開啓進程,而後通訊
pro = Process(target=prodctor, args=((psend, precv), [1, 2, 3, 4, 5]))
con = Process(target=consumer, args=((psend, precv), '消費者'))
pro.start()
con.start()
print(psend.fileno())
pro.join()
con.join()
psend.close()
precv.close()
print('=>主進程')

8一、線程/進程池(Pool):由於在切換線程/進程的時候,須要切換上下文環境,線程不少的時候,依然會形成CPU的大量開銷。爲解決這個問題,線程池的概念被提出來了。
預先建立好一個數量較爲優化的線程/進程組,在須要的時候馬上可以使用,就造成了線程/進程池。
若是池尚未滿,那麼就會建立一個新的線程/進程用來執行該請求;但若是池中的線程/進程數已經達到規定最大值,那麼該請求就會等待。

Python沒有內置的線程池模塊,須要本身實現或使用第三方模塊,但提供了進程池模塊(from multiprocessing import Pool)。
apply():同步執行(串行)
apply_async():異步執行(並行)
terminate():馬上關閉進程池
close():等待全部進程結束後,才關閉進程池。
join():主進程等待全部子進程執行完畢。必須在close或terminate()以後。 
例:
if __name__=='__main__':
p = Pool(processes=4) # 容許最多同時放入4個進程,自由調配子程序。默認是本機的CPU核數。
for i in range(20): # 開啓20個進程
res = p.apply_async(func=task, args=(x,), callback='回調函數') # 異步運行進程池,func傳入函數,arg是元組,有返回結果

p.close() # 調用join()以前必須先調用close()
p.join() # 等待目前子進程結束後,繼續運行下一個子進程。若是沒有則進入主進程

res.get() # 獲得子程序返回結果
res.ready() # 子程序是否調用完成
res.successful() # 子程序是否調用成功

進程池方法apply_async()中的回調函數callback說明:
a、不須要回調函數的場景:若是在主進程中等待進程池中全部任務都執行完畢後,再統一處理結果,則無需回調函數,如上例。
b、須要回調函數的場景: 進程池中任何一個任務一旦處理完了,就當即告知主進程,主進程則調用一個函數去處理該結果,該函數即回調函數。
例:
def get_page(url):
print('<進程 %s> 正在下載頁面: %s' % (os.getpid(), url))
time.sleep(random.randint(1, 3))
return url+'/???' # 用url充當下載後的結果

def parse_page(page_content): # 以子進程的返回值做爲參數
print('<進程 %s> 正在解析頁面: %s' % (os.getpid(), page_content))
time.sleep(1)
print('{%s 回調函數處理結果: 成功!}' % os.getpid())

if __name__ == '__main__':
urls = [
'http://www.taobao.com/v1.0/1',
'http://www.taobao.com/v1.0/2',
'http://www.taobao.com/v1.0/3',
'http://www.taobao.com/v1.0/4',
'http://www.taobao.com/v1.0/5',
'http://www.taobao.com/v1.0/7' ]
p = Pool()
# 異步的方式提交任務,而後把任務的結果交給callback處理
# 注意:會專門開啓一個進程來處理callback指定的任務(單獨的一個進程,並且只有一個)
for url in urls:
p.apply_async(get_page, args=(url,), callback=parse_page) # 以子進程的返回值做爲callback的參數
# 異步提交完任務後,主進程先關閉p(必須先關閉),而後再用p.join()等待全部任務結束(包括callback)
p.close()
p.join()
print('{主進程 %s}' % os.getpid())

82、ThreadLocal:一個ThreadLocal變量雖然是全局變量,但每一個線程都只能讀寫本身線程的獨立副本,互不干擾。
*做用:解決在一個線程中多個函數之間互相傳遞參數的問題。
ThreadLocal最經常使用的地方就是爲每一個線程綁定一個數據庫鏈接,HTTP請求,用戶身份信息等,
這樣一個線程的全部調用到的處理函數均可以很是方便地訪問這些資源。例: 
import threading
local = threading.local() #實例一個ThreadLocal對象,用於封裝屬性,並能保證多線程使用該屬性而不互相干擾
#線程調用的方法
def func1(name, age, score):
local.name = name #封裝屬性
local.age = age
local.score = score
func2() #調用某個函數,將參數傳給func2

def func2():
name = local.name #讀取屬性
age = local.age
score = local.score
print('name:%s,age:%d,score:%0.1f' % (name, age, score), threading.current_thread().ident)

thr = threading.Thread(target=func1, args=('汪春旺', 25, 99.5))
thr.start() 
thr.join()

83、進程 VS 線程。
要實現多任務,一般咱們會設計Master-Worker模式,Master(主進程/線程)負責分配任務,Worker(子進程/線程)負責執行任務。

進程優勢:穩定性高,由於一個子進程崩潰了,不會影響主進程和其餘子進程。
進程缺點:耗CPU和內存。

線程優勢:效率高。
線程缺點:任何一個線程掛掉均可能直接形成整個進程崩潰,由於全部線程共享進程的內存。

任務分爲:計算密集型和IO密集型。
計算密集型(C等)任務主要消耗CPU資源,多核提高的是計算性能; -->>使用多進程
IO密集型(Python等)任務主要涉及到網絡、磁盤IO,多核對IO操做沒什麼用處; -->>使用多線程

在Thread和Process中,應當優選Process,由於Process更穩定,並且,Process能夠分佈到多臺機器上,而Thread最多隻能分佈到同一臺機器的多個CPU上。

分佈式進程:Python的multiprocessing模塊不但支持多進程,其中managers子模塊還支持把多進程分佈到多臺機器上。

8四、異步IO(即"協程",coroutine):對於IO密集型任務咱們還有一種選擇就是協程。協程是運行在單線程中的"併發",協程相比多線程的一大優點就是
省去了多線程之間的切換開銷,得到了更高的運行效率。因此能夠用協程取代多線程。

要想建立協程,只須要包含至少一個yield表達式(一般在一個無線循環中)的函數,到達該yield表達式時,協程的執行被掛起並等待數據,
收到數據後(不會影響其餘協程),協程從該yield處恢復處理,如此循環。
Python3.4中加入了asyncio模塊,引入"@asyncio.coroutine"裝飾器和yield from語法。 
協程能取代多線程和多進程,如讀寫磁盤文件、網絡數據的異步問題。
多線程和多進程的模型雖然解決了異步問題,可是系統不能無上限地增長線程,系統切換線程的開銷也很大。

協程優勢:
1). 能實現異步;
2). 協程的切換開銷更小,屬於程序級別的切換,操做系統徹底感知不到,於是更加輕量級;
  3). 單線程內就能夠實現併發的效果,最大限度地利用cpu單核。
那怎麼利用多核CPU呢?最簡單的方法是"多進程+協程",既充分利用多核,又充分發揮協程的高效率,從而得到極高的性能。

生成器和協程的區別:生成器是數據的產生者,協程是數據的消費者。 
sync:同步;
async:異步。

8五、協程標庫(asyncio):基於事件循環,從asyncio模塊中直接獲取一個 "EventLoop" 的引用,而後把須要執行的協程扔到"EventLoop"中執行。
1)@asyncio.coroutine聲明一個協程;
2)關鍵字yield from來等待協程的返回結果;
3)多個協程能夠封裝成一組Task而後併發執行,Task是Future的子類。
例: 
@asyncio.coroutine # 聲明一個協程,或@coroutine,先導入asyncio
def hellopf():
print('Hello!',threading.current_thread())
yield from asyncio.sleep(2) # asyncio.sleep()是一個協程
# 示例中sleep爲異步IO的表明,在實際項目中,能夠使用協程異步的讀寫網絡、讀寫文件、渲染界面等
# yield from語法可讓咱們方便地調用另外一個generator
print('World!',threading.current_thread())

task=[hellopf(),hellopf()]
loop=asyncio.get_event_loop() # 1.建立事件循環對象
loop.run_until_complete(asyncio.wait(task)) # 2.運行循環。多個任務用wait(),若是是單個任務,不須要asyncio.wait()
loop.close() # 3.關閉事件循環

# ------------------------------------------------------------------ #
Python3.5變化:
a.把@asyncio.coroutine替換爲"async"(置於def以前);
b.把yield from替換爲await。

例:
async def wget(host):
print('wget %s...' %host)
connect = asyncio.open_connection(host, 80)
reader, writer = await connect
header = 'GET/HTTP/1.0\r\nHost: %s\r\n\r\n' %(host)
writer.write(header.encode('utf-8'))
await writer.drain()
while True:
line = await reader.readline()
if line == b'\r\n':
break
print('%s header > %s' % (host, line.decode('utf-8').rstrip()))
# Ignore the body, close the socket
writer.close()

loop = asyncio.get_event_loop()
tasks = [wget(host) for host in ['www.sina.com.cn', 'www.sohu.com', 'www.163.com']]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()

8六、正則表達式("re"模塊)。強烈建議使用Python的原生字符"r"前綴,就不用考慮轉義的問題。
1)元字符:表示一些特殊的含義,通常不是指具體字符。
-------------------------------------------------------------------------------------------
. | 小數點能夠匹配除了換行符\n之外的任意一個字符
-------------------------------------------------------------------------------------------
[] | 匹配字符集合中的一個字符
-------------------------------------------------------------------------------------------
[^] | 對字符集求反,也就是上面的反操做。尖號必須在方括號裏的最前面
-------------------------------------------------------------------------------------------
- | 定義[]裏的一個字符區間,例如[a-z]
-------------------------------------------------------------------------------------------
() | 對錶達式進行分組,將圓括號內的內容當作一個總體,並得到匹配的值
-------------------------------------------------------------------------------------------
\ | 對緊跟其後的一個字符進行轉義
-------------------------------------------------------------------------------------------
| | 邏輯或操做符 
-------------------------------------------------------------------------------------------

2)轉義字符:具備特殊功能的字符。
-------------------------------------------------------------------------------------------
\r, \n | 匹配回車和換行符
-------------------------------------------------------------------------------------------
\t | 匹配製表符
-------------------------------------------------------------------------------------------
\\ | 匹配斜槓\
-------------------------------------------------------------------------------------------
\^ | 匹配^符號
-------------------------------------------------------------------------------------------
\$ | 匹配$符號
-------------------------------------------------------------------------------------------
\. | 匹配小數點.
-------------------------------------------------------------------------------------------

3)預約義字符:匹配預約義字符集中的任意一個字符。
-------------------------------------------------------------------------------------------
\d | 任意一個數字,0~9 中的任意一個
-------------------------------------------------------------------------------------------
\w | 任意一個字母或數字或下劃線,也就是 A~Z,a~z,0~9,_ 中的任意一個
-------------------------------------------------------------------------------------------
\s | 空格、製表符、換頁符等空白字符的其中任意一個
-------------------------------------------------------------------------------------------
\D | \d的反集,也就是非數字的任意一個字符,等同於[^\d]
-------------------------------------------------------------------------------------------
\W | \w的反集,也就是[^\w]
-------------------------------------------------------------------------------------------
\S | \s的反集,也就是[^\s]
-------------------------------------------------------------------------------------------

4)重複
-------------------------------------------------------------------------------------------
{n} | 表達式重複n次,好比\d{2}至關於\d\d,a{3}至關於aaa
-------------------------------------------------------------------------------------------
{m,n} | 表達式至少重複m次,最多重複n次。好比ab{1,3}能夠匹配ab或abb或abbb
-------------------------------------------------------------------------------------------
{m,} | 表達式至少重複m次,好比\w\d{2,}能夠匹配a12,_1111,M123等等
-------------------------------------------------------------------------------------------
? | 匹配表達式0次或者1次,至關於{0,1},好比a[cd]?能夠匹配a,ac,ad
-------------------------------------------------------------------------------------------
+ | 表達式至少出現1次,至關於{1,},好比a+b能夠匹配ab,aab,aaab等等
-------------------------------------------------------------------------------------------
* | 表達式出現任意次,至關於{0,},好比\^*b能夠匹配b,^^^b等等
-------------------------------------------------------------------------------------------

5)位置
-------------------------------------------------------------------------------------------
^ | 在字符串開始的地方匹配,符號自己不匹配任何字符
-------------------------------------------------------------------------------------------
$ | 在字符串結束的地方匹配,符號自己不匹配任何字符
-------------------------------------------------------------------------------------------
\b | 匹配一個單詞邊界,也就是單詞和空格之間的位置,符號自己不匹配任何字符
-------------------------------------------------------------------------------------------
\B | 匹配非單詞邊界,即左右兩邊都是\w範圍或者左右兩邊都不是\w範圍時的字符縫隙
-------------------------------------------------------------------------------------------

經常使用方法與比較:
1)re.match(pattern, string, flags):嘗試從字符串的【開頭】匹配【一個】模式。
text="JGood 666666 is a handsome boy, he is cool, clever, and so on..."
m=re.match(r"(\w+)\s", text) #結果是"JGood "
m=re.match(r"\d+", text) #結果是None,由於數字不在開頭

2)re.search(pattern, string, flags):在【整個】字符串內查找模式匹配,只到找到第一個匹配就返回。
text="JGood 666666 is a handsome boy, he is cool, clever, and so on..."
m=re.search(r"\d+", text) #結果是"666666"

3)re.findall(pattern, string, flags):獲取字符串中全部匹配的字符串。
text="JGood 666666 is a handsome boy, he is cool, clever, and so on..."
m=re.findall(r'\e',text) #結果是['e', 'e', 'e', 'e']

4)re.finditer(pattern, string, flags):獲取字符串中全部匹配的字符串,並把它們做爲一個迭代器返回。

5)用正則表達式分割字符串比用固定的字符更靈活,如:
re.split(r'\s+', 'a b c') #必須是re包的split()方法。以一個或多個空格分割。

6)reg_obj=re.compile(pattern, flags):把模板pattern編譯成"正則對象",提升效率。如reg_obj.search(string)。

7)正則分組:分組就是去已經匹配到的內容裏面再篩選出須要的內容,至關於二次過濾。實現分組靠圓括號(),而獲取分組的內容靠的是group()、groups()和groupdict()方法。
group():獲取匹配到的總體結果
group(1):獲取匹配到的分組1的結果
groups():獲取匹配到的分組結果元組
groupdict():獲取匹配到的分組中全部命名的字典

對於findall()、finditer():沒有group()、groups()、groupdict()方法。

正則匹配默認是貪婪匹配,也就是匹配儘量多的字符。加問號"?"能夠去除貪婪匹配(匹配單個)。如:re.match(r'^(\d+?)(0*)$', '102300').groups()。

87、一些經常使用的內置模塊。
(1)datetime:日期時間模塊。
Python中時間日期格式化符號:
%y 兩位數的年份(00-99)
※ %Y 四位數的年份(000-9999)
※ %m 月(01-12)
※ %d 天(0-31)
※ %H 24小時制(0-23%I 12小時制(01-12) 
※ %M 分(00-59)
※ %S 秒(00-59#---經常使用格式:日期只有'年'符號大寫,時間符號全大寫
%a 本地簡化星期名稱
%A 本地完整星期名稱
%b 本地簡化的月份名稱
%B 本地完整的月份名稱
%c 本地相應的日期表示和時間表示
%j 年內的一天(001-366%p 本地A.M.或P.M.的等價符
%U 一年中的星期數(00-53)星期天爲星期的開始
%w 星期(0-6),星期天爲星期的開始
%W 一年中的星期數(00-53)星期一爲星期的開始
%x 本地相應的日期表示
%X 本地相應的時間表示
%Z 當前時區的名稱
%% '%'號自己

Ⅰ.datetime模塊中的datetime類:這是一個日期和時間組合的類,由年、月、日、時、分、秒、微秒組成。
from datetime import datetime
(a) datetime.today() # 獲取當前本地日期時間
datetime.now([tz]) # 獲取當前日期時間,若是提供了參數tz,則獲取tz參數所指時區的本地時間
datetime(2017,5,20,13,14,0) # 指定日期時間,返回datetime對象
dtobj.year、dtobj.month、dtobj.day # 年、月、日
dtobj.hour、dtobj.minute、dtobj.second # 時、分、秒
dtobj.date() # 獲取datetime對象對應的date對象
dtobj.time() # 獲取datetime對象對應的time對象
combine(date, time) # 把指定的date和time對象整合成一個datetime對象

(b) 時間戳(timestamp)一旦肯定,其UTC(時區)時間就肯定了。
若是要存儲datetime,最佳方法是將其轉換爲時間戳(timestamp)再存儲,由於時間戳與時區徹底無關。時間戳是一個浮點數。
datetime.timestamp('datetime對象') # 日期時間-->時間戳,如果字符串須要把字符串轉成datetime對象
datetime.fromtimestamp('時間戳') # 時間戳-->日期時間

import time
now_timestamp = time.time() # 獲取當前時間戳

(c) dtobj.isoformat([sep]) # 返回一個"%Y-%m-%dT%H:%M:%S"字符串,sep是"日期 時間"的分隔符,默認是"T"
datetime.strptime('2017-5-21','%Y-%m-%d') # 字符串-->日期時間 (經常使用,注意參數的分隔符一致便可) 
datetime.strftime(now,'%Y-%m-%d %H:%M:%S') # 日期時間-->字符串 

(d) 時間的加減,timedelta類屬於datetime模塊。
now + timedelta(hours=1)

(e) 時區(UTC):
utc_curr = datetime.utcnow() # 返回當前UTC日期時間的datetime對象
bj_utc = datetime.astimezone(utc_curr,timezone(timedelta(hours=8))) # astimezone(),轉換成指定時區 

Ⅱ.datetime模塊中的date類:這是一個日期類,由年、月、日組成。
from datetime import date
date.max # date對象所能表示的最大日期,是一個date對象
date.min # date對象所能表示的最小日期,是一個date對象
date.today() # 返回當前本地日期,是一個date對象
date.fromtimestamp() # 根據給定的時間戳,返回一個date對象
date.weekday() # 參數必須是一個date類型的對象,返回該日期是一週中的第幾天,星期一,返回0
date.isoweekday() # 參數必須是一個date類型的對象,返回該日期是一週中的第幾天,星期一,返回1
date.isocalendar() # 參數必須是一個date類型的對象,返回date類型對象中的year(年),week(周),weekday(一週中的第幾天)
date_obj.strftime(fmt) # 返回自定義格式的日期字符串
date_obj.isoformat() # 返回一個"%Y-%m-%d"日期字符串
date_obj.replace(year, month, day) # 拷貝一個新的日期對象,用指定的年,月,日參數替換原有對象中的屬性
date_obj.year/month/day # 返回日期對象的年/月/日
date_obj < date_obj # 比較日期大小,返回布爾

Ⅲ.datetime模塊中的time類:這是一個時間類,由時、分、秒以及微秒組成。
from datetime import time
time.min、time.max # time類所能表示的最小、最大時間
time_obj = time(23,59,59) # time對象
time_obj.hour/minute/second # 返回時、分、秒
time_obj.isoformat() # 返回"%H:%M:%S"格式的字符串
time_obj.strftime(fmt) # 返回自定義格式的時間字符串
time_obj.replace(year, month, day) # 拷貝一個新的時間對象,用指定的時、分、秒參數替換原有對象中的屬性
2)subprocess:建立子進程。能夠在Python的代碼裏執行操做系統級別的命令。使用run()方法調用子進程,執行操做系統命令。
run()方法返回的是一個CompletedProcess類型對象,不能直接獲取咱們一般想要的結果。要獲取命令執行的結果或者信息,
在調用run()方法的時候,請指定stdout=subprocess.PIPE,且建議shell=True。
例:s = subprocess.run('ipconfig', shell=True, stdout=subprocess.PIPE)
獲取結果:s.stdout.decode('gbk')

(3)random:生成僞隨機數(實際上計算機隨機函數所產生的「隨機數」並不隨機)。
random.randint(a, b):返回一個a <= N <= b的隨機整數N。
random.uniform(a, b):返回一個介於a和b之間的浮點數。
random.sample(population, k):從population樣本或集合中隨機抽取K個元素(不重複)造成新的序列。經常使用於不重複的隨機抽樣、打亂序列。
random.choice(seq):從非空序列seq中隨機選取一個元素。若是seq爲空則彈出 IndexError異常。

(4)base64模塊:對二進制數據編碼,避免顯示亂碼(用記事本打開exe、jpg、pdf這些文件時,咱們都會看到一大堆亂碼);
base64是把3字節一組變爲4字節一組,因此,Base64編碼的長度永遠是4的倍數;
base64是一種任意二進制到文本字符串的編碼方法,經常使用於在URL、Cookie、網頁中傳輸少許二進制數據。
base64.b64encode(b'') #編碼
base64.b64decode(b'') #解碼
base64.urlsafe_b64encode(b'') #對於URL二進制編碼時,把字符+和/分別變成-和_
base64.urlsafe_b64decode(b'')

(5)hashlib:哈希(摘要)算法模塊。把任意長度的輸入,經過某種hash算法(單向算法),變換成固定長度的輸出,該輸出就是散列,也稱摘要。
要注意,摘要算法不是加密算法,不能用於加密數據(由於沒法經過摘要反推明文),只能用於防止數據被篡改,
可是它的單向計算特性決定了能夠在不存儲明文口令的狀況下驗證用戶口令。
那麼哈希算法有什麼用呢?最經常使用的就是密碼加密!密碼加密不像數據加密,一般不須要反向解析出明文。
1、hashlib.md5():MD5是最多見的哈希算法,速度很快,結果是一個32位的十六進制字符串表示。如: 
import hashlib
md5 = hashlib.md5('how to use md5 in python hashlib?'.encode()) # 返回hash對象
print(md5.hexdigest()) # digest()獲取bytes類型的摘要,hexdigest()獲取十六進制str類型的摘要

二、hashlib.sha1():"sha1"中是數字"1",不是字母"l"。與md5()用法一致,結果是一個40位的十六進制字符串。

3、hash_obj.update(bytesarg):更新hash對象,連續調用該方法至關於連續追加更新摘要。

(6)shutil:主要用於拷貝、移動、刪除、壓縮、解壓的模塊。
shutil.copyfile(src, dst):拷貝文件。
shutil.copy(src,dst):拷貝文件,包括權限。
shutil.copy2(src, dst):拷貝文件,包括權限和狀態。
shutil.copytree(src, dst, symlinks=False, ignore=None, copy_function=copy2):遞歸地複製目錄及其子目錄的文件和狀態信息。
參數:symlinks 指定是否複製軟連接,當心陷入死循環;
ignore 指定不參與複製的文件,其值應該是一個ignore_patterns()方法;
copy_function 指定複製的模式。
shutil.rmtree(path[, ignore_errors[, onerror]]):歸地刪除目錄及子目錄內的文件。
shutil.move(src, dst):遞歸地移動文件。

shutil.make_archive(base_name, format[, root_dir[, base_dir[, verbose[, dry_run[, owner[, group[, logger]]]]]]]):建立壓縮文件。
參數:base_name 壓縮後的文件名。若是不指定絕對路徑,則壓縮文件保存在當前目錄下。
format 壓縮格式,能夠是「zip」, 「tar」, 「bztar」 ,「gztar」,「xztar」中的一種。
root_dir 設置壓縮包裏的根目錄,通常使用默認值。
base_dir 要進行壓縮的源文件或目錄。
owner 用戶,默認當前用戶。
group 組,默認當前組。
logger 用於記錄日誌,一般是logging.Logger對象。
shutil.unpack_archive(filename[, extract_dir[, format]]):解壓。
參數:filename 是壓縮文檔的完整路徑
extract_dir 是解壓縮路徑,默認爲當前目錄。
format 是壓縮格式。默認使用文件後綴名代碼的壓縮格式。

(7)timeit:計時器,測試代碼運行時間。
timeit(stmt='pass', setup='pass', timer=<defaulttimer>, number=1000000)
參數:stmt 要執行的那段代碼;
setup 執行代碼的準備工做,不計入時間,通常是import之類的;
timer 這個在win32下是time.clock(),linux下是time.time(),默認的,不用管;
number要執行stmt多少遍,記得修改默認值!

(8)collections:集合模塊。 
一、namedtuple(tbname,field):命名的元組。將"tbname"視爲表名,"field"視爲字段名。如:
tb = namedtuple('score','chinese,math')
tr = tb('99','100') #賦值
print(tr.chinese, tr.math) #取值

2、deque(iterable):雙隊列。爲了高效實現插入和刪除操做的雙向列表list,適合用於隊列。由於list是線性存儲,數據量大的時候,插入和刪除效率很低。
deque除了實現list的append()和pop()外,還支持appendleft()和popleft()。rotate(i),從倒數第i個位置往前放。

3、defaultdict(default_func):使用dict時,若是引用的Key不存在,就會拋出KeyError。若是但願key不存在時,返回一個默認值,就能夠用defaultdict。如:
def_dic = defaultdict(lambda:'不存在該值')
def_dic['k1'] = 'a1'

4、OrderedDict類:使用dict時,Key是無序的,若是要保持Key的順序,能夠用OrderedDict,如:
orddic=OrderedDict({'1':'a','2':'b','3':'c'})

5、Counter類:是一個簡單的計數器,例如,統計字符出現的個數。
c=Counter()
for t in 'wangchunwang':
c[t]=c[t]+1
print(c.most_common())

6、heapq:堆。會自動排序。
heap=[]
heapq.heappush(heap,(2,'two'))
heapq.heappush(heap,(1,'one'))

(9)itertools模塊:操做可迭代對象,返回值不是list,而是Iterator,只能用"for"循環迭代的時候才真正計算。
1、count類,無限計數。
2、cycle類,無限循環每一個元素。
3、repeat類,重複整個參數。
4、chain類,將迭代對象串聯。
5、groupby類,把迭代器中相鄰的重複元素挑出來放在一塊兒。

(10)contextlib模塊:上下文。
@contextmanager,上下文裝飾器。

(11)關於XML。
操做XML經常使用的兩種方法:DOM(基於對象)和SAX(基於事件)。
DOM方法會把整個XML讀入內存,解析爲樹,所以佔用內存大,解析慢,優勢是能夠任意遍歷樹的節點。
SAX方法是流模式,邊讀邊解析,佔用內存小,解析快,缺點是咱們須要本身處理事件(繼承sax.ContentHandler類,重寫方法)。
正常狀況下,優先考慮SAX,由於DOM實在太佔內存。

ElementTree模塊解析XML(XML元素樹,解析和寫入節點): 
from xml.etree import ElementTree
tree=ElementTree.parse('sax_test.xml') #得到元素樹解析器 
root=tree.getroot() #獲取根節點
print(root)
stations=set({})
for ele in tree.getiterator('station_name'): #迭代任意節點
stations.add(ele.text) #獲取元素文本;attrib獲取屬性
12)關於HTMLParser。
HTML本質上是XML的子集,可是HTML的語法沒有XML那麼嚴格,因此不能用標準的DOM或SAX來解析HTML。Python提供了HTMLParser來很是方便地解析HTML。

(13)URL:統一資源定位(如HTML頁面,圖片等)。它的組成可分紅6部分,格式爲:
protocol://hostname[:port]/path/[;param][?query][#frag]
說明:
-----------------------------------------------------------------------------------------------------------------------------
| protocol | 必須,協議部分,如http,ftp
-----------------------------------------------------------------------------------------------------------------------------
| hostname:port | 必須,主機(ip或域名)與端口部分;ftp可能用到"user:passwd@ip:port"
-----------------------------------------------------------------------------------------------------------------------------
| path | 必須,虛擬目錄
-----------------------------------------------------------------------------------------------------------------------------
| param | 可選,參數部分,若是向服務器傳入參數,極少用
-----------------------------------------------------------------------------------------------------------------------------
| query | 可選,查詢部分,若是須要從服務器那裏查詢內容,很經常使用
-----------------------------------------------------------------------------------------------------------------------------
| frag | 可選,錨部分,網頁中可能會分爲不一樣的片斷,若是訪問網頁後直接到達指定位置,能夠在這部分設置,較經常使用
-----------------------------------------------------------------------------------------------------------------------------
以上6個部分對應urlparse解析結果(scheme, netloc, path, params, query, fragment)

urlparse模塊中核心函數:
urlparse(urlstr): 將urlstr解析成6個部分。
urlunparse(urltup): 將urltup組成完整的URL。
urljoin(baseurl,newurl): 將baseurl根目錄和newurl組成新的完整的URL。

urllib模塊中的核心函數:
urlopen(urlstr): 打開URL。
urlretrieve(urlstr,filename): 下載URL文件到filename文件中。
quote(urldata,safe='/'): 將urldata中特殊字符進行編碼成"%xx",safe中的字符不編碼。
unquote(urldata): 將urldata中編過碼的字符解碼。
urlencode(dict): 將'dict'編譯成URL中的"query部分",其中空格編譯成"+",其他沒法識別的字符編譯成"%xx">>> request模塊:from urllib import request

1、GET
請求指定的網址:req = request.Request(url='http://www.douban.com/', method='GET')
with request.urlopen(url=req) as rep:
print(rep.status,rep.reason) # 狀態,描述
print(rep.getheaders())

模擬瀏覽器,添加HHTP頭:req = request.Request(url='http://www.douban.com/', method='GET', headers={'User-Agent': 'Mozilla/6.0'})
with request.urlopen(url=req) as rep:
print(rep.getheaders())
print(rep.read().decode())

2、POST
若是要以POST發送一個請求,只須要把urlopen()中參數data以bytes形式傳入。
email=input('微博帳號:')
passwd=input('密碼:')
login_info=urllib.parse.urlencode({
'username':email,
'password':passwd,
'entry': 'mweibo',
'client_id': '',
'savestate': '1',
'ec': '',
'pagerefer': 'https://passport.weibo.cn/signin/welcome?entry=mweibo&r=http%3A%2F%2Fm.weibo.cn%2F'
})
req=request.Request(url='https://passport.weibo.cn/sso/login', data=login_info.encode(), method='POST')
req.add_header('Origin', 'https://passport.weibo.cn')
req.add_header('User-Agent', 'Mozilla/6.0')
req.add_header('Referer', 'https://passport.weibo.cn/signin/login?entry=mweibo&res=wel&wm=3349&r=http%3A%2F%2Fm.weibo.cn%2F')
with request.urlopen(url=req) as rep:
print(rep.status,rep.read())

3、簡單的爬蟲(抓取圖片)
# 獲取頁面
def getHTMLContent(url):
req=request.Request(url=url,method='GET')
html=request.urlopen(req,timeout=30)
return html.read()

# 解析出圖片的URL
def getImgUrl(html):
reg_patt=re.compile(pattern=r'<img.+?src="(.+?\.jpg)"\s+width')
img_urls=reg_patt.findall(string=html.decode())
return img_urls

# 批量下載圖片並保存
def downMultImg(img_urls,n=10,path='Images/'):
count=1
for url in img_urls:
request.urlretrieve(url=url, filename='{0}{1}{2}'.format(path,count,'.jpg'))
count=count+1
if count==n+1:
print('共下載%d張圖片' %(n))
return
# 封裝
def download(url):
html=getHTMLContent(url)
img_urls=getImgUrl(html)
downMultImg(img_urls,n=20)

if __name__ == '__main__':
url='http://tieba.baidu.com/p/2256306796'
download(url)

8八、第三方庫。基本上,全部的第三方模塊都會在PyPI-the Python Package Index上註冊,只要找到對應的模塊名字,便可用"pip install modulename""easy_install modulename"安裝。
(1)pillow,圖像處理庫。
在命令行cmd直接輸入:pip install pillow 進行安裝。例:製做驗證碼:
from PIL import Image #導入pillow
def rand_draw_color():
return (random.randint(0, 200), random.randint(50, 200), random.randint(20, 200)) 
def font_color():
return (random.randint(10, 100), random.randint(10, 100), random.randint(10, 100))
def rand_char():
return chr(random.randint(65,90))
#圖像的尺寸
width=60*4
height=60
#建立圖像
img=Image.new('RGB',(width,height),color=(255,255,255))
#建立畫布(用於塗鴉)
draw=ImageDraw.Draw(img)
#填充畫布顏色,按像素填充
for draw_color_x in range(width):
for draw_color_y in range(height):
draw.point((draw_color_x,draw_color_y),fill=rand_draw_color()) # 當調用函數帶括號時,表獲取函數返回值,即函數有"return"語句
# 當調用函數不帶括號時,表僅僅引用函數,即函數無"return"語句
#輸出4個隨機字符
for char_count in range(4):
draw.text((60*char_count+15,10),rand_char(),fill=font_color(),font=ImageFont.truetype(font='Font/msyh.ttf',size=38))
#模糊處理
#img=img.filter(ImageFilter.GaussianBlur) #這裏必須是賦值處理
img.save('Images/vali_code.jpg','JPEG')

(2)virtualenv爲應用提供了隔離的Python運行環境,解決了不一樣應用間多版本的衝突問題。

89、圖形界面(GUI),調用內置的tkinter。例:
import tkinter
from tkinter import messagebox

topFrame=tkinter.Tk()
topFrame.title('提示')

def btComm(ev=None):
messagebox.showinfo('網址','www.wcw.com')

butt=tkinter.Button(master=topFrame,text='點擊一下',font=('Helvetica',12,'bold'),command=btComm)
butt.pack() # 裝箱。Packer佈局

topFrame.mainloop() # 必須調用循環方法

90、數據庫編程。
關係型:閉源收費數據庫:Oracle、DB2; 開源免費數據庫:MySQL、SQLite(嵌入式數據庫,輕量,Python內置)
1、SQLite編程
#鏈接數據庫文件,若無則新建
conn = sqlite3.connect('test.db')
#建立遊標,實際操做者
cursor = conn.cursor()
cursor.execute(sql) #執行query
cursor.close() #關閉遊標
conn.commit() #執行insert等操做後要調用commit()提交事務
conn.close() #關閉鏈接

二、MySQL編程--使用pymysql模塊
cmd安裝驅動:pip install pymysql, 例:
import pymysql
# 鏈接數據庫,注意編碼。在MySQL客戶端命令行若有亂碼,執行語句"set names gbk;"
coon = pymysql.connect(user='root', password='0000', host='127.0.0.1', port=3306, database='test', charset='utf8') 
cursor = coon.cursor() # 建立遊標

user_id = 5
name = 'WcwNina'
age = 22
sex = ''
department = '營銷部'
salary = 9000
# 執行SQL語句,返回影響的行數。變量放入列表裏,防止SQL注入!
sql = 'insert into user(user_id,name,age,sex,department,salary) values(%s,%s,%s,%s,%s,%s)'
effect_row = cursor.execute(sql, (user_id,name,age,sex,department,salary))
effect_row2 = cursor.execute('select salary from user')
coon.commit() # 提交
cursor.close()
coon.close()
print(cursor.fetchmany(2))
cursor.scroll(0) # 遊標下移一位

三、MySQL框架:SQLAlchemy驅動模塊,把關係數據庫的表結構映射到class對象上(即"ORM"技術:對象關係映射)。
經常使用的SQL語句可能會致使安全問題(由於是字符串的語句,會存在SQL注入)。SQLAlchemy兼容多種關係型數據庫。
安裝SQLAlchemy:pip install sqlalchemy。例: 
from sqlalchemy import *
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

### 建立引擎,指定字符集。這裏鏈接庫爲test,echo參數爲True時,會顯示每條執行的SQL語句,生產環境下可關閉
engine = sqlalchemy.create_engine('mysql+pymysql://root:0000@localhost:3306/test?charset=utf8', echo=False) 

### 聲明ORM基類
Base = declarative_base() 
### 建模型 (表結構映射)
class Department(Base):
__tablename__ = 'department' # 表名

RowID = Column(Integer, primary_key=True, autoincrement=True) # 自增主鍵字段
Dep_Code = Column(String(3), nullable=False, unique=True, index=True)
Dep_Name = Column(String(20), nullable=True, default='--')
FK_id = Column(Integer, ForeignKey('table.field')) # 外鍵

__table_args__ = (
UniqueConstraint('RowID', 'Dep_Code'), # 聯合惟一約束
Index('Dep_Code', 'Dep_Name'), # 聯合索引
)

### 建立表結構 (後臺會自動創建一張表)
Base.metadata.create_all(engine)

### 創建會話,相似遊標
Session = sessionmaker(bind=engine)
session = Session()

## 插入記錄,使用關係映射類
dept_obj = Department(Dep_Code='004',Dep_Name='人事部')
session.add(dept_obj)
session.commit()

## 查詢記錄,默認查出全部結果
data = session.query(Department).all()[:2] # 結果分片 
data = session.query(Department).get(Department.RowID=1) # 只能返回一條結果,不然會異常 
data = session.query(Department).filter(Department.RowID>1).offset(2).limit(1).all() # 偏移2個位置,返回1條結果。limit()和offset)()經常使用於分頁
data = session.query(Department.Dep_Code, Department.Dep_Name).filter(Department.RowID<3).order_by(Department.RowID.desc()).all() # 返回指定字段,倒序結果 
data = session.query(Department).filter(text("RowID<:rid and Dep_Name=:name")).params(rid=3, name='WcwNina').all() # 佔位符設置變量參數 
data = session.query(Department).filter(Department.Dep_Code=='003').filter(Department.Dep_Name=='軟件部').all() # 多條件查詢,相似"and"。注意filter參數是bool型! 
data = session.query(Department).filter(Department.RowID.between(1,3), Department.Dep_Name.like('%部')).all() # "between"限定字段範圍,"like"模糊查詢 
data = session.query(Department).filter(Department.RowID.in_([1,2,3])).all() # "in_"範圍查詢 
data = session.query(Department).filter(~Department.RowID.in_([1,2,3])).all() # "~"排除範圍,相似"!=" 
data = session.query(Department).filter(and_(Department.RowID<3, Department.Dep_Code!='003')).all() # "and_",and查詢 
data = session.query(Department).filter(or_(Department.RowID<3, Department.Dep_Code=='003')).all() # "or_",or查詢 
data = session.query(Users, Favor).filter(Users.id == Favor.nid).all() # 聯表(內聯)查詢 
data = session.query(Users).join(Favor, [on '外鍵條件']).filter(Users.id>1).all() # "join"外鍵聯表查詢,默認內聯查詢
data = session.query(Users).outerjoin(Favor, [on '外鍵條件']).filter(Users.id>1).all() # "outerjoin"外鍵聯表查詢,外聯查詢

## 更新記錄,查出記錄後更新
data = session.query(Department).filter(Department.Dep_Code=='003').first().update({Dep_Name: '軟件部'}) # first()返回第一條結果
session.commit()

## 統計
counts = session.query(Department).filter(Department.Dep_Name.like('%部')).count() # count()函數

## 分組
from sqlalchemy import func # func模塊提供了一些經常使用函數
session.query(func.count(Department.Dep_Name),func.max(RowID), Department.Dep_Name).group_by(Department.Dep_Name).all()

## 回滾
session.rollback()
data = session.query(Department).filter(Department.Dep_Code.in_(['004']))

91、網絡模型結構可由7層(國際標準)簡化爲4層(民間流行):數據鏈路層(網卡MAC)、網絡層(IP)、傳輸層(協議)、應用層(數據)。

網絡編程(C/S架構):主要指網絡通訊,實現計算機之間的對話和文件傳輸。
IP地址其實是一個32位整數(稱爲IPv4),以字符串表示的IP地址如192.168.0.1其實是把32位整數按8位分組後的數字表示,目的是便於閱讀。
IPv6地址其實是一個128位整數,它是目前使用的IPv4的升級版,以字符串表示相似於2001:0db8:85a3:0042:1000:8a2e:0370:7334。
TCP協議則是創建在IP協議之上的。TCP協議負責在兩臺計算機之間創建可靠鏈接,保證數據包按順序到達。
端口有什麼做用?在兩臺計算機通訊時,只發IP地址是不夠的,由於同一臺計算機上跑着多個網絡程序。

Socket又稱"套接字",應用程序一般經過"套接字"向網絡發出請求或者應答網絡請求,使主機間或者一臺計算機上的進程間能夠通信。

(1)TCP協議編程(面向鏈接、序列化、不重複)。建立TCP鏈接時,主動發起鏈接的叫客戶端,被動響應鏈接的叫服務器。
80端口是Web服務的標準端口。SMTP服務是25端口,FTP服務是21端口,等等。端口號小於1024的是Internet標準服務的端口,端口號大於1024的,能夠任意使用。
備註:發送和接收的數據是字節,須要編碼encode()和解碼decode()。
accept()和recv()方法都是阻塞的,所謂的阻塞,指的是程序會暫停在那,一直等到有數據過來。
重點在於數據的接收和發送!

socket編程思路:
1)服務端
1.建立套接字,綁定套接字到本地IP和端口:socket.socket(socket.AF_INET,socket.SOCK_STREAM) --> s.bind()
2.開始監聽鏈接:s.listen()
3.進入永久循環,不斷接受客戶端的鏈接請求:s.accept()
4.在永久循環裏,接收傳來的數據,或者發送數據給對方:s.recv() , s.sendall()
5.傳輸完畢後,關閉套接字:s.close() (通常不關閉)

2)客戶端
1.建立套接字,鏈接服務器地址:socket.socket(socket.AF_INET,socket.SOCK_STREAM) --> s.connect()
2.鏈接後發送數據和接收數據:s.sendall(), s.recv()
3.傳輸完畢後,關閉套接字:s.close()

例1:客戶端訪問網絡:必須知道服務器的IP地址和端口號。
import socket
# 建議網絡鏈接
sock=socket()
sock.connect(('www.sina.com.cn',80))
sock.send(b'GET/HTTP/1.1\r\nHost:www.sina.com.cn\r\nConnection:close\r\n\r\n') # 注意HTTP協議格式
# 接收數據,使用永循環
buffer=[]
while True:
data=sock.recv(1024)
if data:
buffer.append(data)
else:
break
data=b''.join(buffer)
sock.close()
# 保存內容
header, html = data.split(b'\r\n\r\n', 1)
print(header.decode('utf-8'))
with open('sina.html', 'wb') as f:
f.write(html)

例2:服務器:服務器進程首先要綁定一個端口並監聽來自其餘客戶端的鏈接,須要一直開啓。 
#####-服務器端-##### 
#----1.創建套接字,綁定IP端口----
so_server=socket(type=SOCK_STREAM) # type=SOCK_STREAM,表示"流式"套接字,可靠鏈接的TCP協議 
so_server.bind(('127.0.0.1',9999)) 
so_server.listen(5) # 監聽端口,入參數指定等待鏈接的最大數量 
print('等待鏈接...')

#----3.使用永循環,收發數據。這是重點部分----
def tcp_link(so_link,addr_link):
print('正在鏈接',addr_link)
so_link.send('歡迎!'.encode()) # 向客戶端發送send()
while True:
data=so_link.recv(1024) # 接收客戶端數據recv()
if not data or data.decode()=='exit':
break
so_link.send('你好,%s'.encode() %data)
so_link.close()
print('關閉鏈接', addr_link)

#----2.服務器經過永久循環來接受客戶端的鏈接----
while True:
so, addr=so_server.accept() # 接受客戶端鏈接,返回socket對象和客戶端地址
thr=Thread(target=tcp_link, args=(so, addr)) # socket模塊,默認是單線程,同時只能處理一個鏈接請求,如要實現多用戶服務,須要使用多線程。
thr.start()
thr.join() 

#####-客戶端-##### 
from socket import socket
so_client=socket(type=SOCK_STREAM)
so_client.connect(('127.0.0.1',9999)) # 鏈接服務器
print(so_client.recv(1024).decode()) # 接收服務器"歡迎"數據。若是數據大,則採用緩存append
for data in ['Michael', 'Tracy', 'Sarah']: # 向服務器發數據,並接收返回數據
so_client.send(data.encode())
print(so_client.recv(1024).decode())
so_client.send('exit'.encode())
so_client.close()

(2)UDP協議編程(面向無鏈接、無序、可重複)。優勢是和TCP比,速度快、開銷小。
因爲UDP沒有握手的過程,所以沒有connect()、listen()、accept()方法。
##### 服務器端 #####
so=socket(type=SOCK_DGRAM) # type=SOCK_DGRAM,表示"數據報式"套接字,不可靠無鏈接的UDP協議
so.bind(('127.0.0.1',9999))
def udp_recv():
while True:
data,addr=so.recvfrom(1024)
print('請求客戶端:',addr)
so.sendto('你好,%s'.encode() %data,addr)
thr=Thread(target=udp_recv)
thr.start()
thr.join()

##### 客戶端 #####
so=socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
for data in ['Michael', 'Tracy', 'Sarah']:
so.sendto(data.encode(),('127.0.0.1',9999))
print((so.recv(1024)).decode())
so.close() 

(3)高級網絡編程使用socketserver模塊,更方便,更強大。
使用socketserver要點:
1.建立一個繼承自"socketserver.BaseRequestHandler"的類;
2.這個類中必須重寫一個名字爲"handle"的方法,不能是別的名字,在此進行業務邏輯處理!
3.將這個新建的類,連同服務器的IP和端口做爲參數傳遞給"ThreadingTCPServer()"實例化;
4.啓動"ThreadingTCPServerObj.serve_forever()"92、發郵件協議:SMTP
收郵件協議:POP三、IMAP 

例(SMTP):
mail_host = "mail.dhcc.com.cn" # 設置SMTP服務器
from_user = "wangchunwang@dhcc.com.cn" # 發件用戶名
from_pass = "DHCCwcw@070134" # 發件密碼(若是是QQ,可能使用受權碼)

to_user = '575504815@qq.com' # 收件用戶名

message = MIMEText('Python 郵件發送測試...', 'plain', 'utf-8') # plain表示發送文本
message['From'] = Header(("**旺<%s>" %from_user), 'utf-8') # 發件人顯示名稱
message['To'] = Header(("收件人<%s>" %to_user), 'utf-8') # 收件人顯示名稱

subject = 'Python SMTP 郵件測試' # 主題
message['Subject'] = Header(subject, 'utf-8')

try:
smtpObj = smtplib.SMTP_SSL(mail_host,465) # 實例SMTP,建議使用SMTP_SSL !!
# smtpObj.set_debuglevel(1)
smtpObj.login(from_user, from_pass) # 登陸發件用戶
smtpObj.sendmail(from_user, to_user, message.as_string()) # 開始發送
print("郵件發送成功")
smtpObj.quit()
except smtplib.SMTPException as e:
print("Error: 沒法發送郵件->",e.args)

9三、Web開發(B/S架構):即網頁、網站的開發。
1)WEB服務器(HTTP服務器):與客戶端打交道,處理前端靜態內容(session、request、response、HTML、js、CSS等),如Apache、Nginx、IIS。只有Apache是純web服務器!
2)應用服務器:爲應用程序處理後臺業務邏輯,客戶端應用程序能夠調用的方法,生成動態內容,如 Weblogic(Java)、WebSphere(IBM)。
然而,如今大多數應用服務器也包含了Web服務器的功能,如Tomcat、IIS、WSGI。

1、HTTP請求方法:GET與POST,GET僅請求資源,POST會附帶用戶數據(區別於HTML表單的get、post方法)。一個HTTP請求只處理一個資源。
響應代碼:200表示成功,3xx表示重定向,4xx表示客戶端發送的請求有錯誤,5xx表示服務器端處理時發生了錯誤。
web服務器工做:接受HTTP請求、解析HTTP請求、發送HTTP響應。 
HTTP GET請求的格式,每一個Header一行一個,換行符是" \r\n ":
GET /path HTTP/1.1
Header1: Value1
Header2: Value2
Header3: Value3

HTTP POST請求的格式,包含body經過" \r\n\r\n "來分隔:
POST /path HTTP/1.1
Header1: Value1
Header2: Value2
Header3: Value3
body data goes here...

2、Web過程:
a.瀏覽器發送一個HTTP請求;
b.服務器收到請求,生成一個HTML文檔;
c.服務器把HTML文檔做爲HTTP響應的Body發送給瀏覽器;
d.瀏覽器收到HTTP響應,從HTTP Body取出HTML文檔並顯示。

3、HTML定義了頁面的內容,CSS來控制頁面元素的樣式,而JavaScript負責頁面的交互邏輯。

4、CGI:通用網關接口;
WSGI:Web服務器網關接口。例:
def app(request,response): # web app用來處理請求和響應。request處理請求信息;response處理響應信息。
response('200 OK',[('Content-Type','text/html')])
body='<h1>Hello,world!%s</h1>' %(request['PATH_INFO'][1:])
return [body.encode()] #返回列表類型

httpd=make_server('localhost',2017,app)
httpd.serve_forever()

94、web服務框架:不少框架都自帶了WSGI,好比 Flask,webpy,Django、CherryPy等。
例:
app=Flask(__name__)
#獲取首頁
@app.route('/',methods=['GET'])
def home():
return '<h1>HOME</h1>'

95、MVC模式:M(模型) —— 業務數據(或業務邏輯),這是應用程序的主體;
V(視圖) —— 用戶交互界面(模板);
C(控制器)—— 接收來自界面的請求,處理用戶界面數據顯示。

9六、動態執行代碼。(1)eval(expression, globals=None, locals=None):只能執行單一表達式,globals和locals存放變量,一般爲字典,如eval('x**y+99',{'x':2,'y':3});
(2)exec(object, globals=None, locals=None):能夠執行代碼塊(函數或模塊),返回值爲None。
exec()不能存取任何數據,解決辦法:將引用對象放入字典中。例:
import math
code='''
def area_sphere(r):
return '{0:e}'.format(4*math.pi*r**2)
'''
context={}
context['math']=math # 將引用對象模塊放入字典
exec(code,context) # exec執行對象也能放入字典
area=context['area_sphere'] # 從字典中提取執行結果
print(area(5))

97、上下文管理器:在正常處理系統資源(文件、線程鎖和鏈接)以前須要先執行一些準備動做,及其以後須要繼續執行一些收尾動做。 
例如:當須要操做文件或數據庫的時候,首先須要獲取文件句柄或者數據庫鏈接對象,當執行完相應的操做後,須要執行釋放文件句柄或者關閉數據庫鏈接的動做。
又如,當多線程程序須要訪問臨界資源的時候,線程首先須要獲取互斥鎖,當執行完成並準備退出臨界區的時候,須要釋放互斥鎖。 
上下文管理器須要實現__enter__()和__exit__()特殊方法,經過with...as...語句來使用上下文管理器。
a、__enter__(self):進入上下文管理器時調用此方法,其返回值將被放入with-as語句中as說明符指定的變量中。
b、__exit__(self, exc_type, exc_val, exc_tb):離開上下文管理器調用此方法。若是有異常出現,exc_type、exc_val、exc_tb分別爲異常的類型、值和追蹤信息。
此方法返回值爲True或者False,分別指被引起的異常是否獲得了處理,若是返回False,引起的異常會被傳遞出上下文。
例:
class OpenFile(object):
def __init__(self,filename,mode):
self.filename=filename
self.mode=mode
def __enter__(self):
self.f=open(self.filename,self.mode)
return self.f #做爲as說明符指定的變量的值
def __exit__(self,type,value,tb):
self.f.close()
return False #異常會被傳遞出上下文
#######
with OpenFile('my_file.txt','w') as f:
f.write('Hello,')
f.write('World!')

9八、描述符(Descriptor):首先它是一個類,且實現了__get__(self,instance,owner),__set__(self,instance,value),__delete__(self,instance)
中一個或多個魔法方法,描述符使用時做爲另外一個類的類屬性(必定是類屬性!!!)。其中,instance是這個描述符的屬性實例,owner是描述符所在的類。
描述符通常用於較底層的代碼,最多見的描述符有 property、staticmethod、classsmethod(用描述符實現的裝飾器),用來控制屬性訪問。例:
class Desc(object):
def __init__(self):
self.dic={}

def __set__(self, instance, value):
print('Desc set:',instance,value)
if value<0 or value >100:
raise ValueError('值必須在0~100之間!')
self.dic[instance]=value

def __get__(self, instance, owner):
print('Desc get:', instance, owner)
return self.dic[instance]

####
class Score(object):
descScore=Desc() # 描述符使用時做爲另外一個類的類屬性,必定是類屬性!!!不是實例屬性!!!
def __init__(self,score):
self.descScore=score
###
s=Score(100)
print(s.descScore)

99、抽象基類(ABC):相似於Java的接口interface,抽象基類定義了一些抽象屬性和抽象方法,抽象類並不能直接實例化。目的:共性共用。
要定義抽象類,須要將"元類Meta"設置爲ABCMeta,這一步是必須的,由於抽象類的實現離不開元類。
在抽象類中,@abstractmethod和@abstractproperty裝飾的方法/特性其子類必須實現,且能夠去改變其參數和返回值。
抽象基類支持對已經存在的類進行註冊,使其屬於該基類,使用register()進行註冊,如向抽象基類A註冊類B:A.register(B) 。


>> 文章持續更新中...(轉載請註明出處)
相關文章
相關標籤/搜索