日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > python >内容正文

python

Python复习 基础知识

發(fā)布時(shí)間:2024/1/8 python 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Python复习 基础知识 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
動(dòng)態(tài)語言:變量類型不固定稱之為動(dòng)態(tài)語言

什么是動(dòng)態(tài)語言呢?   可以簡單的理解為直接被解釋執(zhí)行的語言稱為動(dòng)態(tài)語言。

而需要編譯環(huán)境將程序轉(zhuǎn)換為其它的編碼再執(zhí)行的語言稱為靜態(tài)語言。
  當(dāng)前靜態(tài)語言有:java、C/C++、C#、DELPHI、VB等。
  動(dòng)態(tài)語言有:asp、php、cgi、lisp、Perl、python,Smalltalk、Ruby等。

?

數(shù)據(jù)類型:?

dict:無序,可變,大括號(hào),唯一內(nèi)置的映射類型,字典是作為哈希表(支持快速檢索的數(shù)據(jù)結(jié)構(gòu))來實(shí)現(xiàn)的。

tuple:有序,不可變,有in,無append、extend;無remove、pop;無index

list:有序,可變,小括號(hào)

?

字典 dict:?

2.7文檔:https://docs.python.org/2/library/stdtypes.html#mapping-types-dict

key,鍵必須獨(dú)一無二,可以hash,支持 __hash__方法。list無 __hash__ 方法,所以不能作為key.

values containing lists, dictionaries or other mutable types (that are compared by value rather than by object identity) may not be used as keys.

Python中可哈希的對(duì)象有:

  • 數(shù)值、字符串,以及只含有數(shù)值或字符串的元組
  • 用戶自定義類的實(shí)例(默認(rèn)是可哈希的,也可以通過實(shí)現(xiàn)__hash__()和__cmp__()來修改默認(rèn)行為)


value,值可以取任何數(shù)據(jù)類型,但必須是不可變的,如字符串,數(shù)或元組。

dict:和list比較有以下幾個(gè)特點(diǎn):

  • 查找和插入的速度極快,不會(huì)隨著key的增加而增加;
  • 需要占用大量的內(nèi)存,內(nèi)存浪費(fèi)多。
  • list:

  • 查找和插入的時(shí)間隨著元素的增加而增加;
  • 占用空間小,浪費(fèi)內(nèi)存很少。
  • 所以,dict是用空間來換取時(shí)間的一種方法。

    tuple:

    用 Tuple 的好處
    Tuple 比 list 操作速度快.如果您定義了一個(gè)值的常量集,并且唯一要用它做的是不斷地遍歷它,請(qǐng)使用 tuple 代替 list.
    如果對(duì)不需要修改的數(shù)據(jù)進(jìn)行 “寫保護(hù)”,可以使代碼更安全.使用 tuple 而不是 list 如同擁有一個(gè)隱含的 assert 語句,說明這一數(shù)據(jù)是常量.如果必須要改變這些值,則需要執(zhí)行 tuple 到 list 的轉(zhuǎn)換
    Tuple 與 list 的轉(zhuǎn)換
    Tuple 可以轉(zhuǎn)換成 list,反之亦然.內(nèi)置的 tuple 函數(shù)接收一個(gè) list,并返回一個(gè)有著相同元素的 tuple
    而 list 函數(shù)接收一個(gè) tuple 返回一個(gè) list.從效果上看,tuple 凍結(jié)一個(gè) list,而 list 解凍一個(gè) tuple.
    Tuple 的其他應(yīng)用
    一次賦多值
    >>> v = ('a','b','e')
    >>> (x,y,z) = v

    ?

    參數(shù)傳值

    函數(shù):Python允許你在list或tuple前面加一個(gè)*號(hào),把list或tuple的元素變成可變參數(shù)傳進(jìn)去:

    參數(shù)組合: 

      參數(shù)定義的順序必須是:必選參數(shù)、默認(rèn)參數(shù)、可變參數(shù)和關(guān)鍵字參數(shù)。

    Python的函數(shù)具有非常靈活的參數(shù)形態(tài),既可以實(shí)現(xiàn)簡單的調(diào)用,又可以傳入非常復(fù)雜的參數(shù)。

    默認(rèn)參數(shù)一定要用不可變對(duì)象,如果是可變對(duì)象,運(yùn)行會(huì)有邏輯錯(cuò)誤!

    要注意定義可變參數(shù)和關(guān)鍵字參數(shù)的語法:

    *args是可變參數(shù),args接收的是一個(gè)tuple;

    **kw是關(guān)鍵字參數(shù),kw接收的是一個(gè)dict。

    以及調(diào)用函數(shù)時(shí)如何傳入可變參數(shù)和關(guān)鍵字參數(shù)的語法:

    可變參數(shù)既可以直接傳入:func(1, 2, 3),又可以先組裝list或tuple,再通過*args傳入:func(*(1, 2, 3));

    關(guān)鍵字參數(shù)既可以直接傳入:func(a=1, b=2),又可以先組裝dict,再通過**kw傳入:func(**{'a': 1, 'b': 2})。

    使用*args和**kw是Python的習(xí)慣寫法,當(dāng)然也可以用其他參數(shù)名,但最好使用習(xí)慣用法。

    ?

    遞歸函數(shù)

      防止棧溢出

      解決遞歸調(diào)用棧溢出的方法是通過尾遞歸優(yōu)化

    def fact(n):return fact_iter(n, 1)def fact_iter(num, product):if num == 1:return productreturn fact_iter(num - 1, num * product)

    可以看到,return fact_iter(num - 1, num * product)僅返回遞歸函數(shù)本身,num - 1和num * product在函數(shù)調(diào)用前就會(huì)被計(jì)算,不影響函數(shù)調(diào)用。

    尾遞歸事實(shí)上和循環(huán)是等價(jià)的,沒有循環(huán)語句的編程語言只能通過尾遞歸實(shí)現(xiàn)循環(huán)。

      

    切片

    L[0:3] //若第一個(gè)索引是0,還可以省略 L[:3]

    //取倒數(shù)第一個(gè)元素
    L[-1]

    迭代

      dict默認(rèn)迭代是key

      可以用 for value in d.itervalues()

      若要同時(shí)迭代 key和value

      可以用 for k,v in d.iteritems()

      判斷一個(gè)對(duì)象是否是可迭代對(duì)象(返回BOOL類型):isinstance('abc', Iterable)?

    ?

    列表生成式(List Comprehensions)

    [x*x for x in range(1,11)if x % 2 == 0]

    [4,16,36,64,100]

    [m + n for m in 'ABC' for n in 'XYZ']

    ['AX','AY','AZ','BX','BY','BZ','CX','CY','CZ']

    ?

    生成器(generator)

      一邊循環(huán)一邊計(jì)算,把列表生成器 的[] 改為 ()

    >>> L = [x * x for x in range(10)] >>> L [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] >>> g = (x * x for x in range(10)) >>> g<generator object <genexpr> at 0x104feab40>

    generator 保存的是算法

    斐波那契數(shù)列 Fibonacci

    遞歸

    def fib2(n):if n == 0:return 0elif n ==1:return 1return fib2(n-1) + fib2(n-2)print(fib2(7))memo = {0:0, 1:1} def fib3(n):if not n in memo:memo[n] = fib3(n-1) + fib3(n-2)return memo[n]print(fib3(7))

    (迭代解法)

    def fib(max):n, a, b = 0, 0, 1while n < max:print ba, b = b, a+bn = n + 1

    generator :

    def fib(max):n, a, b = 0, 0, 1while n < max:yield b a, b = b, a + bn = n+1

    與函數(shù)區(qū)別:

      函數(shù)是順序執(zhí)行,遇到return或最后就返回。而變成generator的函數(shù)后,在調(diào)用 next()的時(shí)候執(zhí)行,遇到 yield 語句 返回,再次執(zhí)行時(shí)從上次返回的yield 語句處繼續(xù)執(zhí)行

    ?

    函數(shù)式編程(Functional Programming)

    函數(shù)式編程的一個(gè)特點(diǎn)就是,允許把函數(shù)本身作為參數(shù)傳入另一個(gè)函數(shù),還允許返回一個(gè)函數(shù)!

    ? Python對(duì)函數(shù)式編程提供部分支持。由于Python允許使用變量,因此,Python不是純函數(shù)式編程語言。

    ?

    高階函數(shù)(Higher -order function)

      1,變量可以指向函數(shù)

      2,函數(shù)名也是變量

      3,傳入函數(shù)

        函數(shù)可以接受另一個(gè)函數(shù)作為參數(shù),稱為高階函數(shù)

      

    map / reduce 函數(shù)

      map(),高階函數(shù),接收兩個(gè)參數(shù),一個(gè)是函數(shù),一個(gè)是序列,map將傳入的函數(shù)依次作用到序列的每個(gè)元素,并把結(jié)果作為新的list返回。

      將list所有數(shù)字轉(zhuǎn)為字符串

    >>>map(str, [1,2,3,4,5,6,7,8,9]) ['1', '2', '3', '4', '5', '6', '7', '8', '9']

    reduce 必須接收兩個(gè)參數(shù)

    reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4) 利用 map() 函數(shù),把用戶輸入的不規(guī)范的英文名字,變?yōu)槭鬃帜复髮?其他小寫的規(guī)范名字。輸 入: ['adam', 'LISA', 'barT'] ,輸出: ['Adam', 'Lisa', 'Bart']  

    Python提供的 sum() 函數(shù)可以接受一個(gè)list并求和,請(qǐng)編寫一個(gè) prod() 函數(shù),可以接受一個(gè)list并利用 reduce() 求 積。

    ?

    def capi(w):return w.capitalize() print map(capi,L)

    filter:

    def is_odd(n):return n % 2 == 1filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15]) # 結(jié)果: [1, 5, 9, 15]

    sorted:

      高階函數(shù),可以接受一個(gè)比較函數(shù)來實(shí)現(xiàn)自定義的排序。

      比如倒序函數(shù):

    def rebversed_cmp(x, y):if x > y:return -1if x < y:return 1return 0

    傳入自定義的比較函數(shù) reversed_cmp,就可以實(shí)現(xiàn)倒序排序:

    sorted([36, 5, 12, 9, 21], reversed_cmp)

    ?

    返回函數(shù) ,閉包

    注意到返回的函數(shù)在其定義內(nèi)部引用了局部變量args。

    所以,當(dāng)一個(gè)函數(shù)返回了一個(gè)函數(shù)后,其內(nèi)部的局部變量還被新函數(shù)引用,所以,閉包用起來簡單,實(shí)現(xiàn)起來可不容易。

    另一個(gè)需要注意的問題是,返回的函數(shù)并沒有立刻執(zhí)行,而是直到調(diào)用了f()才執(zhí)行。我們來看一個(gè)例子:

    def count():fs = []for i in range(1, 4):def f():return i*ifs.append(f)return fs f1, f2, f3 = count()

    在上面的例子中,每次循環(huán),都創(chuàng)建了一個(gè)新的函數(shù),然后,把創(chuàng)建的3個(gè)函數(shù)都返回了。

    你可能認(rèn)為調(diào)用f1(),f2()和f3()結(jié)果應(yīng)該是1,4,9,但實(shí)際結(jié)果是:

    >>> f1() 9 >>> f2() 9 >>> f3() 9

    全部都是9!(即都循環(huán)了三次)。原因就在于返回的函數(shù)引用了變量i,但它并非立刻執(zhí)行。等到3個(gè)函數(shù)都返回時(shí),它們所引用的變量i已經(jīng)變成了3,因此最終結(jié)果為9。

    返回閉包時(shí)牢記的一點(diǎn)就是:返回函數(shù)不要引用任何循環(huán)變量,或者后續(xù)會(huì)發(fā)生變化的變量。

    如果一定要引用循環(huán)變量怎么辦?方法是再創(chuàng)建一個(gè)函數(shù),用該函數(shù)的參數(shù)綁定循環(huán)變量當(dāng)前的值,無論該循環(huán)變量后續(xù)如何更改,已綁定到函數(shù)參數(shù)的值不變:

    >>> def count(): ... fs = [] ... for i in range(1, 4): ... def f(j): ... def g(): ... return j*j ... return g ... fs.append(f(i)) ... return fs ... >>> f1, f2, f3 = count() >>> f1() 1 >>> f2() 4 >>> f3() 9

    缺點(diǎn)是代碼較長,可利用lambda函數(shù)縮短代碼。:

    f1, f2 = [(lambda j = i : j ** 2) for i in range(1, 3)]

    ?for后面的i 是個(gè)全局變量,在傳遞進(jìn)函數(shù)參數(shù)時(shí)已經(jīng)被作為某個(gè)數(shù)字了,分解開就是

    f1() = lambda j = 1 : j**2

    f2() = lambda j = 2 : j**2   

    ?

    lambda:匿名函數(shù)

      將一個(gè)List里的每個(gè)元素都平方,

    map(lambda x: x*x, [y for y in range(10)])

    ?

    裝飾器:
    ?將函數(shù)賦值給變量

    ?函數(shù)對(duì)象有一個(gè) __name__ 屬性 ,可以拿到函數(shù)的名字

    ?在代碼運(yùn)行期間 動(dòng)態(tài) 增加功能的方式,稱之為“裝飾器”(Decorator)

    def log(func):def wrapper(*args, **kw):print 'call %s():' % func.__name__return func(*args, **kw)return wrapper@log def now()print '123'

    調(diào)用now()函數(shù)

    >>>now()call now():123 @log def now()print '123' 相當(dāng)于: now = log(now)

    log()是一個(gè)decorator,所以,原來的now()函數(shù)仍然存在,只是現(xiàn)在同名的now變量指向了新的函數(shù),于是調(diào)用now()將執(zhí)行新函數(shù),即在log()函數(shù)中返回的wrapper()函數(shù)。

    wrapper()函數(shù)的參數(shù)定義是(*args, **kw),因此,wrapper()函數(shù)可以接受任意參數(shù)的調(diào)用。在wrapper()函數(shù)內(nèi),首先打印日志,再緊接著調(diào)用原始函數(shù)。

    ?

    在面向?qū)ο?#xff08;OOP)的設(shè)計(jì)模式中,decorator被稱為裝飾模式。OOP的裝飾模式需要通過繼承和組合來實(shí)現(xiàn),而Python除了能支持OOP的decorator外,直接從語法層次支持decorator。Python的decorator可以用函數(shù)實(shí)現(xiàn),也可以用類實(shí)現(xiàn)。

    decorator可以增強(qiáng)函數(shù)的功能,定義起來雖然有點(diǎn)復(fù)雜,但使用起來非常靈活和方便。

    ?

    偏函數(shù)(partial function)

      屬于 functools 模塊里邊。把一個(gè)函數(shù)的某些參數(shù)給固定住(即設(shè)置默認(rèn)值),返回一個(gè)新的函數(shù)。

    >>> import functools >>> int2 = functools.partial(int, base = 2) >>> int2('1000000') 64 >>> int('1010101') 85

    ?相當(dāng)于:

    kw = {base:2)

    int('10010', **kw)

    ?

    模塊:

      一個(gè) .py 文件就稱之為一個(gè)模塊(module)

    #!/usr/bin/env python # -*- coding:utf-8 -*-'a test module'__author__='Michael Liao'import sysdef test():args = sys.argvif len(args)==1:print 'Hello, world!'elif len(args)==2:print 'Hello, %s!' % args[1]else:print 'Too many arguments!'if __name__=='__main__':test()

    第1行和第2行是標(biāo)準(zhǔn)注釋,第1行注釋可以讓這個(gè)hello.py文件直接在Unix/Linux/Mac上運(yùn)行,第2行注釋表示.py文件本身使用標(biāo)準(zhǔn)UTF-8編碼;

    第4行是一個(gè)字符串,表示模塊的文檔注釋,任何模塊代碼的第一個(gè)字符串都被視為模塊的文檔注釋;

    第6行使用__author__變量把作者寫進(jìn)去,這樣當(dāng)你公開源代碼后別人就可以瞻仰你的大名;

    以上就是Python模塊的標(biāo)準(zhǔn)文件模板

    使用sys模塊的第一步,就是導(dǎo)入該模塊:import sys

    sys模塊有一個(gè)argv變量,用list存儲(chǔ)了命令行的所有參數(shù)。argv至少有一個(gè)元素,因?yàn)榈谝粋€(gè)參數(shù)永遠(yuǎn)是該.py文件的名稱。例如:

    運(yùn)行python hello.py獲得的sys.argv就是['hello.py'];

    運(yùn)行python hello.py Michael獲得的sys.argv就是['hello.py', 'Michael]。

    if __name__=='__main__':test()

    當(dāng)我們?cè)诿钚羞\(yùn)行hello模塊文件時(shí),Python解釋器把一個(gè)特殊變量__name__置為__main__,而如果在其他地方導(dǎo)入該hello模塊時(shí),if判斷將失敗,因此,這種if測(cè)試可以讓一個(gè)模塊通過命令行運(yùn)行時(shí)執(zhí)行一些額外的代碼,最常見的就是運(yùn)行測(cè)試。

    ?

    ?Python是動(dòng)態(tài)語言,函數(shù)簽名一致接口就一樣,因此,無論導(dǎo)入哪個(gè)模塊后續(xù)代碼都能正常工作。

    函數(shù)簽名就是函數(shù)的聲明信息,包括參數(shù)(個(gè)數(shù),類型)、返回值、調(diào)用約定之類。

    安裝第三方模塊:

      例如圖片:

      先安裝pip: sudo easy_install pip 然后安裝PIL: sudo -H pip install Pillow 最后導(dǎo)入Image模塊: import PIL.Image 或者 from PIL import Image

    ?

    #!/usr/bin/python #coding:utf-8#獲取當(dāng)前路徑 import os print os.getcwd()from PIL import Image im = Image.open('test.png') #打印格式、大小、類型 print im.format, im.size, im.mode #縮略圖 im.thumbnail((200,100)) im.save('thumb.jpg', 'JPEG')

    ?

    使用 __future__(python3.x 和 2.x 的區(qū)別)

    1,編碼

    python2.x里的字符串用'xxx'表示str,Unicode字符串用u'xxx'表示unicode

    而在3.x中,所有字符串都被視為unicode,因此,寫u'xxx'和'xxx'是完全一致的,而在2.x中以'xxx'表示的str就必須寫成b'xxx',以此表示“二進(jìn)制字符串”。  

    ?為了適應(yīng)Python 3.x的新的字符串的表示方法,在2.7版本的代碼中,可以通過unicode_literals來使用Python 3.x的新的語法:

    ?

    #still running on Python 2.7from __future__ import unicode_literals print '\'xxx\' is unicode?', isinstance('xxx',unicode) print 'u\'xxx\' is unicode?', isinstance(u'xxx', unicode) print '\'xxx\' is str?', isinstance('xxx', str) print 'b\'xxx\' is str?', isinstance(b'xxx', str) 'xxx' is unicode? True u'xxx' is unicode? True 'xxx' is str? False b'xxx' is str? True

    2,除法

    Python2.x 都是地板除

    Python3.x 普通除法是精確除法。地板除用//

    from __future__ import divisionprint '10 / 3 = ', 10 / 3 print '10.0 / 3 = ', 10.0 / 3 print '10 // 3 = ', 10 //3

    10 / 3 =? 3.33333333333
    10.0 / 3 =? 3.33333333333
    10 // 3 =? 3

    3,其他。如 Python3 中無xrange

    http://chenqx.github.io/2014/11/10/Key-differences-between-Python-2-7-x-and-Python-3-x/

    ?

    ?

    面向?qū)ο缶幊?br />Object Oriented Programming, OOP。 數(shù)據(jù)封裝、繼承、多態(tài)

    把對(duì)象作為程序的基本單元,一個(gè)對(duì)象包含了數(shù)據(jù)和操作數(shù)據(jù)段函數(shù)

    OOP: 對(duì)象、消息

    面向過程:一組函數(shù)的順序執(zhí)行

    給對(duì)象發(fā)消息實(shí)際上就是調(diào)用對(duì)象對(duì)應(yīng)的關(guān)聯(lián)函數(shù),我們稱之為對(duì)象的方法(Method)。面向?qū)ο蟮某绦驅(qū)懗鰜砭拖襁@樣:

    bart = Student('Bart Simpson', 59) lisa = Student('Lisa Simpson', 87) bart.print_score() lisa.print_score()

    類、實(shí)例、對(duì)象、方法

    封裝

    訪問限制:

      要讓內(nèi)部屬性不被外部訪問,可以把屬性的名稱前加上兩個(gè)下劃線 __

    變量名如果以 __ (兩個(gè)_) 開頭,就變成了一個(gè)私有變量 (private),? 只有內(nèi)部可以訪問,外部不能訪問。

    class Student(object):def __init__(self, name, score):self.__name = nameself.__score = scoredef print_score(self):print '%s: %s' % (self.__name, self.__score)

    改完后,對(duì)于外部代碼來說,沒什么變動(dòng),但是已經(jīng)無法從外部訪問實(shí)例變量.__name和實(shí)例變量.__score了

    如果外部代碼要獲取 name 和 score 可以 給 Student 類增加 get_name 和 get_score 這樣的方法:

    class Student(object):...def get_name(self):return self.__namedef get_score(self):return self.__score

    修改屬性,使用set

    class Student(object):...def set_score(self, score):self.__score = score

    使用方法修改name的優(yōu)點(diǎn):可以對(duì)參數(shù)做檢查,避免傳入無效的參數(shù)

    在Python中,以雙下劃線開頭并結(jié)尾的,是特殊變量。可以直接訪問,不是private變量。

    繼承和多態(tài)

    繼承:好處,獲得父類的全部功能

    多態(tài):具體調(diào)用的方法,由運(yùn)行時(shí)該對(duì)象的確切類型決定。

    開閉原則:

      對(duì)擴(kuò)展開放:允許新增Animal子類;

      對(duì)修改封閉:不需要修改依賴Animal類型的run_twice()等函數(shù)。

    有繼承才能有多態(tài)

    ?

    獲取對(duì)象信息:

    使用type

    >>>type(123)<type 'int'>>>> type(abs)<type 'builtin_function_or_method'>>>> import types>>> type('abc') == types.StringTypeTrue

    使用dir(), 獲取一個(gè)對(duì)象的所有屬性和方法。

    在len()內(nèi)部,自動(dòng)去調(diào)用該對(duì)象中的__len__()方法,下面代碼是等價(jià)的

    >>> len('ABC') 3 >>> 'ABC'.__len__() 3

    使用 __slots__

      限制Class的 屬性,只允許對(duì)Student 實(shí)例添加name和age屬性

    >>> class Student(object): ... __slots__ = ('name', 'age') #用tuple定義允許綁定的屬性名稱 ...

    使用@property

    在set_score里邊設(shè)置檢查參數(shù)

    class Student(object):def get_score(self):return self._scoredef set_score(self, value):if not isinstance(value, int):raise ValueError('score must be an integer!')if value < 0 and value > 100:raise ValueError('score must between 0 ~ 100!')self._score = value

    以上復(fù)雜,可以使用 @property 裝飾器(即把函數(shù)當(dāng)成參數(shù)傳入,增加方法),把一個(gè)方法變成屬性調(diào)用。

    class Student(object)@property #負(fù)責(zé)把一個(gè)getter 方法變成屬性def score(self):return self._score@score.setter #負(fù)責(zé)把一個(gè)setter方法變成屬性賦值def score(self,value):def score(self, value):if not isinstance(value, int):raise ValueError('score must be an integer!')if value < 0 or value > 100:raise ValueError('score must between 0 ~ 100!')self._score = value

    >>> s = Student()

    >>> s.score = 60 # OK,實(shí)際轉(zhuǎn)化為s.set_score(60)

    >>> s.score # OK,實(shí)際轉(zhuǎn)化為s.get_score()

    60

    >>> s.score = 9999

    Traceback (most recent call last):

    ...

    ValueError: score must between 0 ~ 100!

    ?

    多重繼承

    class Bat(Mammal, Flyable):pass

    Mixin
    ?非單獨(dú)的屬性,例如RunnableMixin

    Python自帶了TCPServer和UDPServer這兩類網(wǎng)絡(luò)服務(wù),而要同時(shí)服務(wù)多個(gè)用戶就必須使用多進(jìn)程或多線程模型,這兩種模型由ForkingMixin和ThreadingMixin提供。通過組合,我們就可以創(chuàng)造出合適的服務(wù)來。

    ?

    由于Python允許使用多重繼承,因此,Mixin就是一種常見的設(shè)計(jì)。

    只允許單一繼承的語言(如Java)不能使用Mixin的設(shè)計(jì)。

    ?

    定制類:

    __str__ 方法

    class Student (object)def __int__(self, name):self.name = namedef __str__(self):return 'Student object (name: %s)' % self.name

    >>> print Student('Michael')

    Student object (name:Michael)

    直接敲變量不用print,打印出來的實(shí)例還是不好看:

    >>> s = Student('Michael') >>> s <__main__.Student object at 0x109afb310>

    這是因?yàn)橹苯语@示變量調(diào)用的不是__str__(),而是__repr__(),兩者的區(qū)別是__str__()返回用戶看到的字符串,而__repr__()返回程序開發(fā)者看到的字符串,也就是說,__repr__()是為調(diào)試服務(wù)的。

    解決辦法是再定義一個(gè)__repr__()。但是通常__str__()和__repr__()代碼都是一樣的,所以,有個(gè)偷懶的寫法:

    class Student(object):def __init__(self, name):self.name = namedef __str__(self):return 'Student object (name=%s)' % self.name__repr__ = __str__

    __iter__ 迭代

    __getitem__按照下標(biāo)取出元素

    __getattr__ 動(dòng)態(tài)返回一個(gè)屬性

    __call__

    class Student(object):def __init__(self, name):self.name = namedef __call__(self):print('My name is %s.' % self.name)

    >>> s = Student('Michael')

    >>> s()

    My name is Michael.

    使用元類,metaclass

      可以使用 type() 動(dòng)態(tài)創(chuàng)建類以外,還可以使用 元類

      即當(dāng)我們定義了類以后,就可以根據(jù)這個(gè)類創(chuàng)建出實(shí)例。所以先定義類,然后創(chuàng)建實(shí)例。

      但是如果我們想創(chuàng)建出類呢?那就必須根據(jù)metaclass創(chuàng)建出類,所以:先定義metaclass,然后創(chuàng)建類。

    ?

    連接起來就是:先定義metaclass,就可以創(chuàng)建類,最后創(chuàng)建實(shí)例。

    ?

    錯(cuò)誤處理:

    try...except...finally

    Python 所有的錯(cuò)誤都是從 BaseException 類派生的

    調(diào)用堆棧如果錯(cuò)誤沒有被捕獲,它就會(huì)一直往上拋,最后被Python解釋器捕獲,打印一個(gè)錯(cuò)誤信息,然后程序退出。

    logging,可以記錄錯(cuò)誤信息。打印錯(cuò)誤后會(huì)繼續(xù)執(zhí)行,并正常退出。

    def main():try:bar('0')except StandardError, e:logging.exception(2)

    使用 raise 拋出錯(cuò)誤。

    ?

    調(diào)試:

    使用assert

    # err.py
    def
    foo(s):n = int(s)assert n != 0, 'n is zero!'return 10/n def main():foo('0')

    使用 -0 來關(guān)閉 assert

    $ python -O err.py

    使用 logging

    使用pdb

    pdb.set_trace()

    # err.py import pdbs = '0' n = int(s) pdb.set_trace() # 運(yùn)行到這里會(huì)自動(dòng)暫停 print 10 / n

    運(yùn)行代碼,程序會(huì)自動(dòng)在pdb.set_trace()暫停并進(jìn)入pdb調(diào)試環(huán)境,可以用命令p查看變量,或者用命令c繼續(xù)運(yùn)行:

    $ python err.py > /Users/michael/Github/sicp/err.py(7)<module>() -> print 10 / n (Pdb) p n 0 (Pdb) c Traceback (most recent call last):File "err.py", line 7, in <module>print 10 / n ZeroDivisionError: integer division or modulo by zero

    雖然用IDE調(diào)試起來比較方便,但是最后你會(huì)發(fā)現(xiàn),logging才是終極武器。

    單元測(cè)試:

      測(cè)試驅(qū)動(dòng)開發(fā),TDD:Test-Driven Development

      單元測(cè)試是是用來對(duì)一個(gè)模塊、一個(gè)函數(shù)或者一個(gè)類來進(jìn)行正確性檢驗(yàn)的測(cè)試工作

    編寫單元測(cè)試時(shí),我們需要編寫一個(gè)測(cè)試類,從unittest.TestCase繼承。

    運(yùn)行單元測(cè)試:

    $ python -m unittest mydict_test

    在命令行通過參數(shù) -m unittest 直接運(yùn)行單元測(cè)試

    setUp與tearDown

    可以在單元測(cè)試中編寫兩個(gè)特殊的setUp()和tearDown()方法。這兩個(gè)方法會(huì)分別在每調(diào)用一個(gè)測(cè)試方法的前后分別被執(zhí)行。

    setUp()和tearDown()方法有什么用呢?設(shè)想你的測(cè)試需要啟動(dòng)一個(gè)數(shù)據(jù)庫,這時(shí),就可以在setUp()方法中連接數(shù)據(jù)庫,在tearDown()方法中關(guān)閉數(shù)據(jù)庫,這樣,不必在每個(gè)測(cè)試方法中重復(fù)相同的代碼:

    ?

    文檔測(cè)試

      Python 內(nèi)置的“文檔測(cè)試”(doctest)模塊可以直接提取注釋中的代碼并執(zhí)行測(cè)試。

    IO編程

      異步IO與同步IO

      異步性能好,效率高,復(fù)雜(包括輪詢模式和回調(diào)模式)

    文件讀寫:

    >>> f = open('/User/michael/test.txt', 'r')

    使用try。。finally

    try:f = open('/path/to/file', 'r')print f.read() finally:if f:f.close()

    簡潔方法,使用with語句自動(dòng)調(diào)用close() 方法:

    with open('/path/to/file', 'r') as f:print f.read()

    調(diào)用read()會(huì)一次性讀取文件的全部內(nèi)容,如果文件有10G,內(nèi)存就爆了,所以,要保險(xiǎn)起見,可以反復(fù)調(diào)用read(size)方法,每次最多讀取size個(gè)字節(jié)的內(nèi)容。另外,調(diào)用readline()可以每次讀取一行內(nèi)容,調(diào)用readlines()一次讀取所有內(nèi)容并按行返回list。因此,要根據(jù)需要決定怎么調(diào)用。

    如果文件很小,read()一次性讀取最方便;如果不能確定文件大小,反復(fù)調(diào)用read(size)比較保險(xiǎn);如果是配置文件,調(diào)用readlines()最方便:

    for line in f.readlines():print(line.strip()) # 把末尾的'\n'刪掉

    讀文件

    要以讀文件的模式打開一個(gè)文件對(duì)象,使用Python內(nèi)置的open()函數(shù),傳入文件名和標(biāo)示符:

    >>> f = open('/Users/michael/test.txt', 'r')

    標(biāo)示符'r'表示讀,這樣,我們就成功地打開了一個(gè)文件。

    如果文件不存在,open()函數(shù)就會(huì)拋出一個(gè)IOError的錯(cuò)誤,并且給出錯(cuò)誤碼和詳細(xì)的信息告訴你文件不存在:

    >>> f=open('/Users/michael/notfound.txt', 'r') Traceback (most recent call last):File "<stdin>", line 1, in <module> IOError: [Errno 2] No such file or directory: '/Users/michael/notfound.txt'

    如果文件打開成功,接下來,調(diào)用read()方法可以一次讀取文件的全部內(nèi)容,Python把內(nèi)容讀到內(nèi)存,用一個(gè)str對(duì)象表示:

    >>> f.read() 'Hello, world!'

    最后一步是調(diào)用close()方法關(guān)閉文件。文件使用完畢后必須關(guān)閉,因?yàn)槲募?duì)象會(huì)占用操作系統(tǒng)的資源,并且操作系統(tǒng)同一時(shí)間能打開的文件數(shù)量也是有限的:

    >>> f.close()

    由于文件讀寫時(shí)都有可能產(chǎn)生IOError,一旦出錯(cuò),后面的f.close()就不會(huì)調(diào)用。所以,為了保證無論是否出錯(cuò)都能正確地關(guān)閉文件,我們可以使用try ... finally來實(shí)現(xiàn):

    try:f = open('/path/to/file', 'r')print f.read() finally: if f: f.close()

    但是每次都這么寫實(shí)在太繁瑣,所以,Python引入了with語句來自動(dòng)幫我們調(diào)用close()方法:

    with open('/path/to/file', 'r') as f:print f.read()

    這和前面的try ... finally是一樣的,但是代碼更佳簡潔,并且不必調(diào)用f.close()方法。

    調(diào)用read()會(huì)一次性讀取文件的全部內(nèi)容,如果文件有10G,內(nèi)存就爆了,所以,要保險(xiǎn)起見,可以反復(fù)調(diào)用read(size)方法,每次最多讀取size個(gè)字節(jié)的內(nèi)容。另外,調(diào)用readline()可以每次讀取一行內(nèi)容,調(diào)用readlines()一次讀取所有內(nèi)容并按行返回list。因此,要根據(jù)需要決定怎么調(diào)用。

    如果文件很小,read()一次性讀取最方便;如果不能確定文件大小,反復(fù)調(diào)用read(size)比較保險(xiǎn);如果是配置文件,調(diào)用readlines()最方便:

    for line in f.readlines():print(line.strip()) # 把末尾的'\n'刪掉

    file-like Object

    像open()函數(shù)返回的這種有個(gè)read()方法的對(duì)象,在Python中統(tǒng)稱為file-like Object。除了file外,還可以是內(nèi)存的字節(jié)流,網(wǎng)絡(luò)流,自定義流等等。file-like Object不要求從特定類繼承,只要寫個(gè)read()方法就行。

    StringIO就是在內(nèi)存中創(chuàng)建的file-like Object,常用作臨時(shí)緩沖。

    二進(jìn)制文件

    前面講的默認(rèn)都是讀取文本文件,并且是ASCII編碼的文本文件。要讀取二進(jìn)制文件,比如圖片、視頻等等,用'rb'模式打開文件即可:

    >>> f = open('/Users/michael/test.jpg', 'rb') >>> f.read() '\xff\xd8\xff\xe1\x00\x18Exif\x00\x00...' # 十六進(jìn)制表示的字節(jié)

    字符編碼

    要讀取非ASCII編碼的文本文件,就必須以二進(jìn)制模式打開,再解碼。比如GBK編碼的文件:

    >>> f = open('/Users/michael/gbk.txt', 'rb') >>> u = f.read().decode('gbk') >>> u u'\u6d4b\u8bd5' >>> print u 測(cè)試

    如果每次都這么手動(dòng)轉(zhuǎn)換編碼嫌麻煩(寫程序怕麻煩是好事,不怕麻煩就會(huì)寫出又長又難懂又沒法維護(hù)的代碼),Python還提供了一個(gè)codecs模塊幫我們?cè)谧x文件時(shí)自動(dòng)轉(zhuǎn)換編碼,直接讀出unicode:

    import codecs with codecs.open('/Users/michael/gbk.txt', 'r', 'gbk') as f: f.read() # u'\u6d4b\u8bd5'

    寫文件

    寫文件和讀文件是一樣的,唯一區(qū)別是調(diào)用open()函數(shù)時(shí),傳入標(biāo)識(shí)符'w'或者'wb'表示寫文本文件或?qū)懚M(jìn)制文件:

    >>> f = open('/Users/michael/test.txt', 'w') >>> f.write('Hello, world!') >>> f.close()

    你可以反復(fù)調(diào)用write()來寫入文件,但是務(wù)必要調(diào)用f.close()來關(guān)閉文件。當(dāng)我們寫文件時(shí),操作系統(tǒng)往往不會(huì)立刻把數(shù)據(jù)寫入磁盤,而是放到內(nèi)存緩存起來,空閑的時(shí)候再慢慢寫入。只有調(diào)用close()方法時(shí),操作系統(tǒng)才保證把沒有寫入的數(shù)據(jù)全部寫入磁盤。忘記調(diào)用close()的后果是數(shù)據(jù)可能只寫了一部分到磁盤,剩下的丟失了。所以,還是用with語句來得保險(xiǎn):

    with open('/Users/michael/test.txt', 'w') as f:f.write('Hello, world!')

    要寫入特定編碼的文本文件,請(qǐng)效仿codecs的示例,寫入unicode,由codecs自動(dòng)轉(zhuǎn)換成指定編碼。

    ?

    操作文件和目錄

    # 查看當(dāng)前目錄的絕對(duì)路徑: >>> os.path.abspath('.') '/Users/michael' # 在某個(gè)目錄下創(chuàng)建一個(gè)新目錄, # 首先把新目錄的完整路徑表示出來: >>> os.path.join('/Users/michael', 'testdir') '/Users/michael/testdir' # 然后創(chuàng)建一個(gè)目錄: >>> os.mkdir('/Users/michael/testdir') # 刪掉一個(gè)目錄: >>> os.rmdir('/Users/michael/testdir')

    拆分路徑:

    >>> os.path.split('/Users/michael/testdir/file.txt') ('/Users/michael/testdir', 'file.txt')

    過濾文件:

    >>> [x for x in os.listdir('.') if os.path.isdir(x)] ['.lein', '.local', '.m2', '.npm', '.ssh', '.Trash', '.vim', 'Adlm', 'Applications', 'Desktop', ...]

    要列出所有的.py文件,也只需一行代碼:

    >>> [x for x in os.listdir('.') if os.path.isfile(x) and os.path.splitext(x)[1]=='.py'] ['apis.py', 'config.py', 'models.py', 'pymonitor.py', 'test_db.py', 'urls.py', 'wsgiapp.py']

    ?

    序列化:(pickling)

      把變量從內(nèi)存中變成可存儲(chǔ)或傳輸?shù)倪^程稱之為序列化

      把變量從內(nèi)存中變成可存儲(chǔ)或傳輸?shù)倪^程稱之為反序列化, unpickling

    序列化,兩個(gè)模塊,cPickle、pickle,cPickle是C語言寫的pickle是Python寫的

      序列化后就可以寫入磁盤,或者網(wǎng)絡(luò)傳輸。

    >>> d = dict(name='Bob', age=20, score=88) >>> pickle.dumps(d) # 把任意一個(gè)對(duì)象序列化成一個(gè) str,然后,就可以把這個(gè)str寫入文件。或者用 pickle.dump() >>> f = open('dump.txt', 'wb') >>> pickle.dump(d, f) #把一個(gè)對(duì)象序列化后寫入一個(gè) file-like Object: >>> f.close()

    當(dāng)我們要把對(duì)象從磁盤讀到內(nèi)存時(shí),可以先把內(nèi)容讀到一個(gè)str,然后用pickle.loads()方法反序列化出對(duì)象,也可以直接用pickle.load()方法從一個(gè)file-like Object中直接反序列化出對(duì)象。我們打開另一個(gè)Python命令行來反序列化剛才保存的對(duì)象:

    >>> f = open('dump.txt', 'rb') >>> d = pickle.load(f) >>> f.close() >>> d {'age': 20, 'score': 88, 'name': 'Bob'}

    JSON

    JSON不僅是標(biāo)準(zhǔn)格式,并且比XML更快,而且可以直接在Web頁面中讀取,非常方便。

    JSON表示的對(duì)象就是標(biāo)準(zhǔn)的JavaScript語言的對(duì)象

    JSON和Python內(nèi)置的數(shù)據(jù)類型對(duì)應(yīng)如下:

    JSON類型Python類型
    {}dict
    []list
    "string"'str'或u'unicode'
    1234.56int或float
    true/falseTrue/False
    nullNone

    ?

    dumps()方法還提供了一大堆的可選參數(shù):

    https://docs.python.org/2/library/json.html#json.dumps

    將對(duì)象轉(zhuǎn)為 JSON

    ?

    進(jìn)程和線程

      多任務(wù)的實(shí)現(xiàn)有3種方式:

    • 多進(jìn)程模式;
    • 多線程模式;
    • 多進(jìn)程+多線程模式。

    多進(jìn)程(multiprocessing):

      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)程內(nèi)返回。

      子進(jìn)程永遠(yuǎn)返回0,而父進(jìn)程返回子進(jìn)程的ID。這樣做的理由是,一個(gè)父進(jìn)程可以fork出很多子進(jìn)程,所以,父進(jìn)程要記下每個(gè)子進(jìn)程的ID,而子進(jìn)程只需要調(diào)用getppid()就可以拿到父進(jìn)程的ID。

    #Python的os模塊封裝了常見的系統(tǒng)調(diào)用,其中就包括fork,可以在Python程序中輕松創(chuàng)建子進(jìn)程:# multiprocessing.py import osprint 'Process (%s) start...' % os.getpid() 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)#運(yùn)行結(jié)果如下: Process (876) start... I (876) just created a child process (877). I am child process (877) and my parent is 876.#有了fork調(diào)用,一個(gè)進(jìn)程在接到新任務(wù)時(shí)就可以復(fù)制出一個(gè)子進(jìn)程來處理新任務(wù),
    常見的Apache服務(wù)器就是由父進(jìn)程監(jiān)聽端口,每當(dāng)有新的http請(qǐng)求時(shí),
    就fork出子進(jìn)程來處理新的http請(qǐng)求。

    multiprocessing

    multiprocessing模塊提供了一個(gè)Process類來代表一個(gè)進(jìn)程對(duì)象,

    下面的例子演示了啟動(dòng)一個(gè)子進(jìn)程并等待其結(jié)束:

    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',))#創(chuàng)建子進(jìn)程時(shí),只需要傳入一個(gè)執(zhí)行函數(shù)和函數(shù)的參數(shù),print 'Process will start.'p.start()#創(chuàng)建一個(gè)Process實(shí)例,用start()方法啟動(dòng),這樣創(chuàng)建進(jìn)程比fork()還要簡單。p.join() #join() 方法可以等待子進(jìn)程結(jié)束后再繼續(xù)往下運(yùn)行,通常用于進(jìn)程間的同步。print 'Process end.' Parent process 928. Process will start. Run child process test (929)... Process end.

    ?

    Pool

      如果要啟動(dòng)大量的子進(jìn)程,可以用進(jìn)程池的方式批量創(chuàng)建子進(jìn)程:

    # -*- coding:utf-8 -*-from multiprocessing import Pool import os, time, randomdef long_time_task(name):print 'Run task %s (%s)...' % (name, os.getpid())start = time.time()time.sleep(random.random() * 3)end = time.time()print 'Task %s runs %0.2f seconds.' % (name, (end - start))if __name__=='__main__':print 'Parent process %s.' % os.getpid()p = Pool()for i in range(5):p.apply_async(long_time_task, args=(i,))print 'Waiting for all subprocesses done...'p.close()p.join() //print 'All subprocesses done.' Parent process 862. Waiting for all subprocesses done... Run task 0 (864)... Run task 1 (865)... Run task 2 (866)... Run task 3 (867)... Task 1 runs 0.42 seconds. Run task 4 (865)... Task 0 runs 1.41 seconds. Task 4 runs 1.65 seconds. Task 3 runs 2.42 seconds. Task 2 runs 2.64 seconds. All subprocesses done.***Repl Closed***

    解讀:

    對(duì)Pool對(duì)象調(diào)用join()方法會(huì)等待所有子進(jìn)程執(zhí)行完畢,調(diào)用join()之前必須先調(diào)用close(),調(diào)用close()之后就不能繼續(xù)添加新的Process了。

    請(qǐng)注意輸出的結(jié)果,task 0,1,2,3是立刻執(zhí)行的,而task 4要等待前面某個(gè)task完成后才執(zhí)行,這是因?yàn)镻ool的默認(rèn)大小在我的電腦上是4,因此,最多同時(shí)執(zhí)行4個(gè)進(jìn)程。這是Pool有意設(shè)計(jì)的限制,并不是操作系統(tǒng)的限制。如果改成:

    p = Pool(5)

    就可以同時(shí)跑5個(gè)進(jìn)程。

    由于Pool的默認(rèn)大小是CPU的核數(shù),如果你不幸擁有8核CPU,你要提交至少9個(gè)子進(jìn)程才能看到上面的等待效果。

    多線程

    Python的標(biāo)準(zhǔn)庫提供了兩個(gè)模塊:thread和threading,thread是低級(jí)模塊,threading是高級(jí)模塊,對(duì)thread進(jìn)行了封裝。絕大多數(shù)情況下,我們只需要使用threading這個(gè)高級(jí)模塊。

    啟動(dòng)一個(gè)線程就是把一個(gè)函數(shù)傳入并創(chuàng)建Thread實(shí)例,然后調(diào)用start()開始執(zhí)行:

    ?

    import time, threading#新線程執(zhí)行的代碼: def loop():print 'thread %s is running...' % threading.current_thread().namen = 0while n < 5:n = n + 1print 'thread %s >>> %s' % (threading.current_thread().name, n)time.sleep(1)print 'thread %s ended.' % threading.current_thread().nameprint 'thread %s is running...' % threading.current_thread().name t = threading.Thread(target = loop, name = 'LoopThread') t.start() t.join() #join作用是阻塞主進(jìn)程(擋住,無法執(zhí)行join以后的語句 print 'thread %s ended.' % threading.current_thread().name thread MainThread is running... thread LoopThread is running... thread LoopThread >>> 1 thread LoopThread >>> 2 thread LoopThread >>> 3 thread LoopThread >>> 4 thread LoopThread >>> 5 thread LoopThread ended. thread MainThread ended.***Repl Closed***

    join ()方法:

    主線程A中,創(chuàng)建了子線程B,并且在主線程A中調(diào)用了B.join(),那么,

    主線程A會(huì)在調(diào)用的地方等待,直到子線程B完成操作后,才可以接著往下執(zhí)行,

    那么在調(diào)用這個(gè)線程時(shí)可以使用被調(diào)用線程的join方法。

    ?原型join([timeout]) 里面的參數(shù)時(shí)可選的,代表線程運(yùn)行的最大時(shí)間,

    即如果超過這個(gè)時(shí)間,不管這個(gè)此線程有沒有執(zhí)行完畢都會(huì)被回收,

    然后主線程或函數(shù)都會(huì)接著執(zhí)行的。

    ?

    由于任何進(jìn)程默認(rèn)就會(huì)啟動(dòng)一個(gè)線程,我們把該線程稱為主線程,主線程又可以啟動(dòng)新的線程,

    Python的threading模塊有個(gè)current_thread()函數(shù),它永遠(yuǎn)返回當(dāng)前線程的實(shí)例。

    主線程實(shí)例的名字叫MainThread,子線程的名字在創(chuàng)建時(shí)指定,我們用LoopThread命名子線程。

    名字僅僅在打印時(shí)用來顯示,完全沒有其他意義,

    如果不起名字Python就自動(dòng)給線程命名為Thread-1,Thread-2……

    ?

    Lock

    多線程和多進(jìn)程最大的不同在于,

    多進(jìn)程中,同一個(gè)變量,各自有一份拷貝存在于每個(gè)進(jìn)程中,互不影響,

    多線程中,所有變量都由所有進(jìn)程共享,所以,任何一個(gè)變量都可以被任何一個(gè)線程修改,

    因此,線程之間共享數(shù)據(jù)最大的危險(xiǎn)在于多個(gè)線程同時(shí)改一個(gè)變量,把內(nèi)容改亂了。

    ?

    鎖,當(dāng)某個(gè)線程開始執(zhí)行change_it()時(shí),我們說,該線程因?yàn)楂@得了鎖,

    因此其他線程不能同時(shí)執(zhí)行change_it(),只能等待,直到鎖被釋放后,獲得該鎖以后才能改。

    由于鎖只有一個(gè),無論多少線程,同一時(shí)刻最多只有一個(gè)線程持有該鎖,

    所以,不會(huì)造成修改的沖突。創(chuàng)建一個(gè)鎖就是通過threading.Lock()來實(shí)現(xiàn):

    balance = 0 lock = threading.Lock()def run_thread(n):for i in range(100000):# 先要獲取鎖: lock.acquire()try:# 放心地改吧: change_it(n)finally:# 改完了一定要釋放鎖:lock.release()

    鎖的好處就是確保了某段關(guān)鍵代碼只能由一個(gè)線程從頭到尾完整地執(zhí)行,壞處當(dāng)然也很多,首先是阻止了多線程并發(fā)執(zhí)行,包含鎖的某段代碼實(shí)際上只能以單線程模 式執(zhí)行,效率就大大地下降了。其次,由于可以存在多個(gè)鎖,不同的線程持有不同的鎖,并試圖獲取對(duì)方持有的鎖時(shí),可能會(huì)造成死鎖,導(dǎo)致多個(gè)線程全部掛起,既 不能執(zhí)行,也無法結(jié)束,只能靠操作系統(tǒng)強(qiáng)制終止。

    ?

    用C、C++或Java來改寫相同的死循環(huán),直接可以把全部核心跑滿,4核就跑到400%,8核就跑到800%,為什么Python不行呢?

    因?yàn)镻ython的線程雖然是真正的線程,但解釋器執(zhí)行代碼時(shí),有一個(gè)GIL鎖:Global Interpreter Lock,任何Python線程執(zhí)行前,必須先獲得GIL鎖,然后,每執(zhí)行100條字節(jié)碼,解釋器就自動(dòng)釋放GIL鎖,讓別的線程有機(jī)會(huì)執(zhí)行。這個(gè)GIL全局鎖實(shí)際上把所有線程的執(zhí)行代碼都給上了鎖,所以,多線程在Python中只能交替執(zhí)行,即使100個(gè)線程跑在100核CPU上,也只能用到1個(gè)核。

    GIL是Python解釋器設(shè)計(jì)的歷史遺留問題,通常我們用的解釋器是官方實(shí)現(xiàn)的CPython,要真正利用多核,除非重寫一個(gè)不帶GIL的解釋器。

    所以,在Python中,可以使用多線程,但不要指望能有效利用多核。如果一定要通過多線程利用多核,那只能通過C擴(kuò)展來實(shí)現(xiàn),不過這樣就失去了Python簡單易用的特點(diǎn)。

    不過,也不用過于擔(dān)心,Python雖然不能利用多線程實(shí)現(xiàn)多核任務(wù),但可以通過多進(jìn)程實(shí)現(xiàn)多核任務(wù)。多個(gè)Python進(jìn)程有各自獨(dú)立的GIL鎖,互不影響。

    ?

    ThreadLocal

    目的:

    在多線程環(huán)境下,每個(gè)線程都有自己的數(shù)據(jù)。一個(gè)線程使用自己的局部變量比使用全局變量好,因?yàn)榫植孔兞恐挥芯€程自己能看見,不會(huì)影響其他線程,而全局變量的修改必須加鎖。

    但是局部變量也有問題,就是在函數(shù)調(diào)用的時(shí)候,傳遞起來很麻煩

    # -*- coding:utf-8 -*-import threading#創(chuàng)建全局ThreadLocal對(duì)象: local_school = threading.local()def process_student():print 'Hello, %s (in %s)' % (local_school.student, threading.current_thread().name)def process_thread(name):#綁定ThreadLocal的student:local_school.student = nameprocess_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)

    全局變量local_school就是一個(gè)ThreadLocal對(duì)象,每個(gè)Thread對(duì)它都可以讀寫student屬性,但互不影響。你可以把local_school看成全局變量,但每個(gè)屬性如local_school.student都是線程的局部變量,可以任意讀寫而互不干擾,也不用管理鎖的問題,ThreadLocal內(nèi)部會(huì)處理。

    可以理解為全局變量local_school是一個(gè)dict,不但可以用local_school.student,還可以綁定其他變量,如local_school.teacher等等。

    ThreadLocal最常用的地方就是為每個(gè)線程綁定一個(gè)數(shù)據(jù)庫連接,HTTP請(qǐng)求,用戶身份信息等,這樣一個(gè)線程的所有調(diào)用到的處理函數(shù)都可以非常方便地訪問這些資源。

    ?

    多線程vs多進(jìn)程

    多線程:優(yōu)點(diǎn),效率高,但是任何一個(gè)線程掛掉都有可能直接造成整個(gè)進(jìn)程奔潰,

    因?yàn)樗芯€程共享進(jìn)程的內(nèi)存。

    多進(jìn)程:優(yōu)點(diǎn),穩(wěn)定,創(chuàng)建進(jìn)程的代價(jià)大

    ?

    計(jì)算密集型 vs. IO密集型

    是否采用多任務(wù)的第二個(gè)考慮是任務(wù)的類型。我們可以把任務(wù)分為計(jì)算密集型和IO密集型。

    對(duì)于計(jì)算密集型任務(wù),最好用C語言編寫。

    涉及到網(wǎng)絡(luò)、磁盤IO的任務(wù)都是IO密集型任務(wù),這類任務(wù)的特點(diǎn)是CPU消耗很少,任務(wù)的大部分時(shí)間都在等待IO操作完成(因?yàn)镮O的速度遠(yuǎn)遠(yuǎn)低于CPU 和內(nèi)存的速度)。對(duì)于IO密集型任務(wù),任務(wù)越多,CPU效率越高,但也有一個(gè)限度。常見的大部分任務(wù)都是IO密集型任務(wù),比如Web應(yīng)用。

    對(duì)于IO密集型任務(wù),最合適的語言就是開發(fā)效率最高(代碼量最少)的語言,腳本語言是首選,C語言最差。

    ?

    現(xiàn)代操作系統(tǒng)對(duì)IO操作已經(jīng)做了巨大的改進(jìn),最大的特點(diǎn)就是支持異步IO。如果充分利用操作系統(tǒng)提供的異步IO支持,就可以用單進(jìn)程單線程模型來執(zhí)行多任 務(wù),這種全新的模型稱為事件驅(qū)動(dòng)模型,Nginx就是支持異步IO的Web服務(wù)器,它在單核CPU上采用單進(jìn)程模型就可以高效地支持多任務(wù)。在多核CPU 上,可以運(yùn)行多個(gè)進(jìn)程(數(shù)量與CPU核心數(shù)相同),充分利用多核CPU。由于系統(tǒng)總的進(jìn)程數(shù)量十分有限,因此操作系統(tǒng)調(diào)度非常高效。用異步IO編程模型來 實(shí)現(xiàn)多任務(wù)是一個(gè)主要的趨勢(shì)。

    ?

    分布式進(jìn)程

    # -*- coding:utf-8 -*- taskmanager.py
    import random, time, Queue from multiprocessing.managers import BaseManger#發(fā)送任務(wù)的隊(duì)列: task_queue = Queue.Queue() #接受結(jié)果的隊(duì)列: result_queue = Queue.Queue()#從BaseManager繼承的QueueManager: class QueueManager(BaseManger):pass #把兩個(gè)Queue都注冊(cè)到網(wǎng)絡(luò)上,callable參數(shù)關(guān)聯(lián)了Queue對(duì)象: QueueManager.register('get_task_queue', callable=lambda: task_queue) QueueManager.register('get_result_queue', callable=lambda: result_queue) # 綁定端口5000, 設(shè)置驗(yàn)證碼'abc': manager = QueueManager(address=('', 5000), authkey='abc') # 啟動(dòng)Queue: manager.start() manager.start() # 獲得通過網(wǎng)絡(luò)訪問的Queue對(duì)象: task = manager.get_task_queue() result = manager.get_result_queue() # 放幾個(gè)任務(wù)進(jìn)去: for i in range(10):n = random.randint(0, 10000)print('Put task %d...' % n)task.put(n) # 從result隊(duì)列讀取結(jié)果: print('Try get results...') for i in range(10):r = result.get(timeout=10)print('Result: %s' % r) # 關(guān)閉: manager.shutdown()

    請(qǐng)注意,當(dāng)我們?cè)谝慌_(tái)機(jī)器上寫多進(jìn)程程序時(shí),創(chuàng)建的Queue可以直接拿來用,但是,在分布式多進(jìn)程環(huán)境下,添加任務(wù)到Queue不可以直接對(duì)原始的task_queue進(jìn)行操作,那樣就繞過了QueueManager的封裝,必須通過manager.get_task_queue()獲得的Queue接口添加。

    然后,在另一臺(tái)機(jī)器上啟動(dòng)任務(wù)進(jìn)程(本機(jī)上啟動(dòng)也可以):

    # taskworker.pyimport time, sys, Queue from multiprocessing.managers import BaseManager# 創(chuàng)建類似的QueueManager: class QueueManager(BaseManager):pass# 由于這個(gè)QueueManager只從網(wǎng)絡(luò)上獲取Queue,所以注冊(cè)時(shí)只提供名字: QueueManager.register('get_task_queue') QueueManager.register('get_result_queue')# 連接到服務(wù)器,也就是運(yùn)行taskmanager.py的機(jī)器: server_addr = '127.0.0.1' print('Connect to server %s...' % server_addr) # 端口和驗(yàn)證碼注意保持與taskmanager.py設(shè)置的完全一致: m = QueueManager(address=(server_addr, 5000), authkey='abc') # 從網(wǎng)絡(luò)連接: m.connect() # 獲取Queue的對(duì)象: task = m.get_task_queue() result = m.get_result_queue() # 從task隊(duì)列取任務(wù),并把結(jié)果寫入result隊(duì)列: for i in range(10):try:n = task.get(timeout=1)print('run task %d * %d...' % (n, n))r = '%d * %d = %d' % (n, n, n*n)time.sleep(1)result.put(r)except Queue.Empty:print('task queue is empty.') # 處理結(jié)束: print('worker exit.')

    任務(wù)進(jìn)程要通過網(wǎng)絡(luò)連接到服務(wù)進(jìn)程,所以要指定服務(wù)進(jìn)程的IP。

    現(xiàn)在,可以試試分布式進(jìn)程的工作效果了。先啟動(dòng)taskmanager.py服務(wù)進(jìn)程:

    $ python taskmanager.py Put task 3411... Put task 1605... Put task 1398... Put task 4729... Put task 5300... Put task 7471... Put task 68... Put task 4219... Put task 339... Put task 7866... Try get results...

    taskmanager進(jìn)程發(fā)送完任務(wù)后,開始等待result隊(duì)列的結(jié)果。現(xiàn)在啟動(dòng)taskworker.py進(jìn)程:

    $ python taskworker.py 127.0.0.1 Connect to server 127.0.0.1... run task 3411 * 3411... run task 1605 * 1605... run task 1398 * 1398... run task 4729 * 4729... run task 5300 * 5300... run task 7471 * 7471... run task 68 * 68... run task 4219 * 4219... run task 339 * 339... run task 7866 * 7866... worker exit.

    taskworker進(jìn)程結(jié)束,在taskmanager進(jìn)程中會(huì)繼續(xù)打印出結(jié)果:

    Result: 3411 * 3411 = 11634921 Result: 1605 * 1605 = 2576025 Result: 1398 * 1398 = 1954404 Result: 4729 * 4729 = 22363441 Result: 5300 * 5300 = 28090000 Result: 7471 * 7471 = 55815841 Result: 68 * 68 = 4624 Result: 4219 * 4219 = 17799961 Result: 339 * 339 = 114921 Result: 7866 * 7866 = 61873956

    這個(gè)簡單的Manager/Worker模型有什么用?其實(shí)這就是一個(gè)簡單但真正的分布式計(jì)算,把代碼稍加改造,啟動(dòng)多個(gè)worker,就可以把任務(wù)分布到幾臺(tái)甚至幾十臺(tái)機(jī)器上,比如把計(jì)算n*n的代碼換成發(fā)送郵件,就實(shí)現(xiàn)了郵件隊(duì)列的異步發(fā)送。

    Queue對(duì)象存儲(chǔ)在哪?注意到taskworker.py中根本沒有創(chuàng)建Queue的代碼,所以,Queue對(duì)象存儲(chǔ)在taskmanager.py進(jìn)程中:

    而Queue之所以能通過網(wǎng)絡(luò)訪問,就是通過QueueManager實(shí)現(xiàn)的。由于QueueManager管理的不止一個(gè)Queue,所以,要給每個(gè)Queue的網(wǎng)絡(luò)調(diào)用接口起個(gè)名字,比如get_task_queue。

    authkey有什么用?這是為了保證兩臺(tái)機(jī)器正常通信,不被其他機(jī)器惡意干擾。如果taskworker.py的authkey和taskmanager.py的authkey不一致,肯定連接不上。

    ?

    ?正則表達(dá)式

    ?

    • [0-9a-zA-Z\_]可以匹配一個(gè)數(shù)字、字母或者下劃線;
    • [0-9a-zA-Z\_]+可以匹配至少由一個(gè)數(shù)字、字母或者下劃線組成的字符串,比如'a100','0_Z','Py3000'等等;

    • [a-zA-Z\_][0-9a-zA-Z\_]*可以匹配由字母或下劃線開頭,后接任意個(gè)由一個(gè)數(shù)字、字母或者下劃線組成的字符串,也就是Python合法的變量;

    • [a-zA-Z\_][0-9a-zA-Z\_]{0, 19}更精確地限制了變量的長度是1-20個(gè)字符(前面1個(gè)字符+后面最多19個(gè)字符)。

    A|B可以匹配A或B,所以(P|p)ython可以匹配'Python'或者'python'。

    ^表示行的開頭,^\d表示必須以數(shù)字開頭。

    $表示行的結(jié)束,\d$表示必須以數(shù)字結(jié)束。

    你可能注意到了,py也可以匹配'python',

    但是加上^py$就變成了整行匹配,就只能匹配'py'了

    re模塊

    Python提供re模塊,包含所有正則表達(dá)式的功能。

    >>> import re >>> re.match(r'^\d{3}\-\d{3,8}$', '010-12345') <_sre.SRE_Match object at 0x1026e18b8> >>> re.match(r'^\d{3}\-\d{3,8}$', '010 12345') >>>

    match()方法判斷是否匹配,如果匹配成功,返回一個(gè)Match對(duì)象,否則返回None。常見的判斷方法就是

    import retest = '用戶輸入的字符串'if re.match(r'正則表達(dá)式',test):print 'ok' else:print 'failed'

    切分字符串

    用正則表達(dá)式切分字符串比用固定的字符更靈活,請(qǐng)看正常的切分代碼:

    >>> 'a b c'.split(' ') ['a', 'b', '', '', 'c']

    嗯,無法識(shí)別連續(xù)的空格,用正則表達(dá)式試試:

    >>> re.split(r'\s+', 'a b c') ['a', 'b', 'c']

    無論多少個(gè)空格都可以正常分割。加入,試試:

    >>> re.split(r'[\s\,]+', 'a,b, c d') ['a', 'b', 'c', 'd']

    再加入;試試:

    >>> re.split(r'[\s\,\;]+', 'a,b;; c d') ['a', 'b', 'c', 'd']

    ?分組(group)

    ?

    編譯

    當(dāng)我們?cè)赑ython中使用正則表達(dá)式時(shí),re模塊內(nèi)部會(huì)干兩件事情:

  • 編譯正則表達(dá)式,如果正則表達(dá)式的字符串本身不合法,會(huì)報(bào)錯(cuò);

  • 用編譯后的正則表達(dá)式去匹配字符串。

  • >>> import re # 編譯: >>> re_telephone = re.compile(r'^(\d{3})-(\d{3,8})$') # 使用: >>> re_telephone.match('010-12345').groups() ('010', '12345') >>> re_telephone.match('010-8086').groups() ('010', '8086')


    re_email = re.compile(r'[a-z\.]{3,20})@([a-z]+\.[a-z]{3})')

    ?

    常用內(nèi)建模塊

    batteried included

    ?

    collection是Python內(nèi)建的一個(gè)集合摸塊,提供了許多有用的集合類。

    namedtuple

    tuple 可以表示不變集合,例如,一個(gè)點(diǎn)的二維坐標(biāo)可以表示為:

    >>> p = (1, 2)

    nametuple 是一個(gè)函數(shù),它用來創(chuàng)建一個(gè)自定義的tuple對(duì)象

    并且規(guī)定了tuple元素的個(gè)數(shù),并可以用屬性而不是索引來引用tuple的某個(gè)元素。

    這樣一來,我們用namedtuple可以很方便地定義一種數(shù)據(jù)類型,它具備tuple的不變性,又可以根據(jù)屬性來引用,使用十分方便。

    >>> from collections import namedtuple >>> Point = namedtuple('Point', ['x', 'y']) >>> p = Point(1, 2) >>> p.x 1 >>> p.y 2

    ?deque

    ?list 訪問快,但是插入和刪除慢,因?yàn)長ist是線性存儲(chǔ)。

    deque是雙向鏈表,適合用于隊(duì)列和棧

    >>> from collections import deque

    >>> q = deque(['a', 'b', 'c'])

    >>> q.append('x')

    >>> q.appendleft('y')

    >>> q

    deque(['y', 'a', 'b', 'c', 'x'])

    deque 可以實(shí)現(xiàn)List的:append(), pop(), appendleft(), popleft()

    defultdict

    使用dict時(shí),如果引用的Key不存在,就會(huì)拋出KeyError。如果希望key不存在時(shí),返回一個(gè)默認(rèn)值,就可以用defaultdict:

    >>> from collections import defultdit

    >>> dd = defaultdict(lambda: 'N/A')

    >>> dd['key1'] = 'abc'

    >>> dd['key1']

    ?'abc'

    >>> dd['key2']

    ?'N/A'

    OrderedDict

    >>> od = OrderedDict([('a', 1), ('b', 2), ('c', 3)]) >>> od # OrderedDict的Key是有序的 OrderedDict([('a', 1), ('b', 2), ('c', 3)])

    Counter

    Counter是一個(gè)簡單的計(jì)數(shù)器,例如,統(tǒng)計(jì)字符出現(xiàn)的個(gè)數(shù):

    >>> from collections import Counter >>> c = Counter() >>> for ch in 'programming': ... c[ch] = c[ch] + 1 ... >>> c Counter({'g': 2, 'm': 2, 'r': 2, 'a': 1, 'i': 1, 'o': 1, 'n': 1, 'p': 1})

    Counter實(shí)際上也是dict的一個(gè)子類,上面的結(jié)果可以看出,字符'g'、'm'、'r'各出現(xiàn)了兩次,其他字符各出現(xiàn)了一次。

    Base64

    base64是一種用64 個(gè)字符來表示任意二進(jìn)制數(shù)據(jù)的方法。

    Base64編碼會(huì)把3字節(jié)的二進(jìn)制數(shù)據(jù)編碼為4字節(jié)的文本數(shù)據(jù),長度增加33%,好處是編碼后的文本數(shù)據(jù)可以在郵件正文、網(wǎng)頁等直接顯示。

    對(duì)二進(jìn)制數(shù)據(jù)進(jìn)行處理,每3個(gè)字節(jié)一組,一共是3x8=24bit,劃為4組,每組正好6個(gè)bit

    如果要編碼的二進(jìn)制數(shù)據(jù)不是3的倍數(shù),最后會(huì)剩下1個(gè)或2個(gè)字節(jié)怎么辦?Base64用\x00字節(jié)在末尾補(bǔ)足后,再在編碼的末尾加上1個(gè)或2個(gè)=號(hào),表示補(bǔ)了多少字節(jié),解碼的時(shí)候,會(huì)自動(dòng)去掉。

    ?

    由于=字符也可能出現(xiàn)在Base64編碼中,但=用在URL、Cookie里面會(huì)造成歧義,所以,很多Base64編碼后會(huì)把=去掉

    自動(dòng)去掉=的:

    def b64decode_self(str):

      return base64.b64decode(str+'='*(4-len(str)%4))

    ?

    struct

    在Python中,比方說要把一個(gè)32位無符號(hào)整數(shù)變成字節(jié),也就是4個(gè)長度的str

    1bit:表示1比特

    1byte:表示1字節(jié)

    1byte=8bit

    >>> import struct >>> struct.pack('>I', 10240099) '\x00\x9c@c'pack的第一個(gè)參數(shù)是處理指令,'>I'的意思是:>表示字節(jié)順序是big-endian,也就是網(wǎng)絡(luò)序,I表示4字節(jié)無符號(hào)整數(shù)。后面的參數(shù)個(gè)數(shù)要和處理指令一致。unpack把str變成相應(yīng)的數(shù)據(jù)類型:>>> struct.unpack('>IH', '\xf0\xf0\xf0\xf0\x80\x80') (4042322160, 32896)

    Windows的位圖文件(.bmp)是一種非常簡單的文件格式,我們來用struct分析一下。

    首先找一個(gè)bmp文件,沒有的話用“畫圖”畫一個(gè)。

    讀入前30個(gè)字節(jié)來分析:

    >>> s = '\x42\x4d\x38\x8c\x0a\x00\x00\x00\x00\x00\x36\x00\x00\x00\x28\x00\x00\x00\x80\x02\x00\x00\x68\x01\x00\x00\x01\x00\x18\x00'

    BMP格式采用小端方式存儲(chǔ)數(shù)據(jù),文件頭的結(jié)構(gòu)按順序如下:

    兩個(gè)字節(jié):'BM'表示W(wǎng)indows位圖,'BA'表示OS/2位圖; 一個(gè)4字節(jié)整數(shù):表示位圖大小; 一個(gè)4字節(jié)整數(shù):保留位,始終為0; 一個(gè)4字節(jié)整數(shù):實(shí)際圖像的偏移量; 一個(gè)4字節(jié)整數(shù):Header的字節(jié)數(shù); 一個(gè)4字節(jié)整數(shù):圖像寬度; 一個(gè)4字節(jié)整數(shù):圖像高度; 一個(gè)2字節(jié)整數(shù):始終為1; 一個(gè)2字節(jié)整數(shù):顏色數(shù)。

    所以,組合起來用unpack讀取:

    >>> struct.unpack('<ccIIIIIIHH', s) ('B', 'M', 691256, 0, 54, 40, 640, 360, 1, 24)

    結(jié)果顯示,'B'、'M'說明是Windows位圖,位圖大小為640x360,顏色數(shù)為24。

    請(qǐng)編寫一個(gè)bmpinfo.py,可以檢查任意文件是否是位圖文件,如果是,打印出圖片大小和顏色數(shù)。

    import struct def test(img_dir):with open(img_dir, 'rb')as f:tu = struct.unpack('<ccIIII\IIHH', f.read(30))if tu[0] == 'B' and tu[1] == 'M':print 'windows bitmap,size:%s, width:%s,\height:%s' %(tu[2],tu[6], tu[7])elif tu[0] == 'B' and tu[1] == 'A':print 'OS\2:, width:%s, height:%s' %(tu[6], tu[7])else:print 'sorry'f.close()test('/Users/Y1Y/Desktop/1.bmp')

    ?

    ?socket

    # 導(dǎo)入socket庫: import socket # 創(chuàng)建一個(gè)socket: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 建立連接: s.connect(('www.sina.com.cn', 80))

    創(chuàng)建Socket時(shí),AF_INET指定使用IPv4協(xié)議,如果要用更先進(jìn)的IPv6,就指定為AF_INET6。SOCK_STREAM指定使用面向流的TCP協(xié)議,這樣,一個(gè)Socket對(duì)象就創(chuàng)建成功,但是還沒有建立連接。

    客戶端要主動(dòng)發(fā)起TCP連接,必須知道服務(wù)器的IP地址和端口號(hào)。新浪網(wǎng)站的IP地址可以用域名www.sina.com.cn自動(dòng)轉(zhuǎn)換到IP地址,但是怎么知道新浪服務(wù)器的端口號(hào)呢?

    答案是作為服務(wù)器,提供什么樣的服務(wù),端口號(hào)就必須固定下來。由于我們想要訪問網(wǎng)頁,因此新浪提供網(wǎng)頁服務(wù)的服務(wù)器必須把端口號(hào)固定在80端口,因?yàn)?0端口是Web服務(wù)的標(biāo)準(zhǔn)端口。其他服務(wù)都有對(duì)應(yīng)的標(biāo)準(zhǔn)端口號(hào),例如SMTP服務(wù)是25端口,FTP服務(wù)是21端口,等等。端口號(hào)小于1024的是Internet標(biāo)準(zhǔn)服務(wù)的端口,端口號(hào)大于1024的,可以任意使用。

    因此,我們連接新浪服務(wù)器的代碼如下:

    s.connect(('www.sina.com.cn', 80))

    注意參數(shù)是一個(gè)tuple,包含地址和端口號(hào)。

    建立TCP連接后,我們就可以向新浪服務(wù)器發(fā)送請(qǐng)求,要求返回首頁的內(nèi)容:

    # 發(fā)送數(shù)據(jù): s.send('GET / HTTP/1.1\r\nHost: www.sina.com.cn\r\nConnection: close\r\n\r\n')

    ?

    轉(zhuǎn)載于:https://www.cnblogs.com/IDRI/p/5741333.html

    總結(jié)

    以上是生活随笔為你收集整理的Python复习 基础知识的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

    久久久久久久久久久高潮一区二区 | 亚洲码国产日韩欧美高潮在线播放 | 国产精品粉嫩 | 久久久久久久久久久高潮一区二区 | www.69xx| 天天色天天 | 在线观看日韩中文字幕 | 亚洲经典在线 | 亚洲在线黄色 | 96久久久 | 黄色福利网 | 国产精品女同一区二区三区久久夜 | 日本久久久精品视频 | 国产区精品在线 | 丰满少妇对白在线偷拍 | 91av原创| 玖玖在线观看视频 | 四虎影视精品成人 | av无限看 | av在线观| a'aaa级片在线观看 | 久久久黄色av | 中文字幕亚洲精品日韩 | 婷婷五月情 | 在线国产专区 | 国产一区二区精品久久91 | 亚洲天天干 | 成年人免费在线播放 | 中文字幕视频观看 | 欧美极品少妇xxxxⅹ欧美极品少妇xxxx亚洲精品 | av五月婷婷 | 99操视频 | 在线观看视频你懂 | 精品国产免费看 | 国产亚洲精品久久 | 久久最新视频 | 久草电影免费在线观看 | 麻豆国产精品永久免费视频 | 日韩精品不卡在线 | 国产免码va在线观看免费 | 亚洲国产精品视频在线观看 | 亚洲国产精品视频 | 久久视讯| 天天色天天综合网 | 亚洲高清视频在线观看 | 麻花豆传媒一二三产区 | 99视频这里只有 | 91亚洲狠狠婷婷综合久久久 | 日韩一区二区三区观看 | 成人在线观看免费 | 狠色在线| 麻豆视频国产在线观看 | 天天射综合网站 | 亚洲精品乱码久久久久久高潮 | 国产精品一区二区三区免费看 | 99精品国产高清在线观看 | 中文字幕视频播放 | 欧美一级乱黄 | 国产永久免费 | 国产日韩av在线 | 国产精品美女久久久久久免费 | 亚洲一区二区黄色 | 美女久久久久 | 蜜臀久久99精品久久久久久网站 | 99热这里只有精品在线观看 | 一级成人网 | 国产日韩精品欧美 | 久久精品99精品国产香蕉 | 国产精品久久久久永久免费看 | 黄色av一区二区 | 久久伊人八月婷婷综合激情 | 免费一级黄色 | 国产九九九视频 | 亚洲精品久久久久999中文字幕 | 日韩欧美综合 | www.亚洲视频.com| 日韩欧美久久 | 久久免费美女视频 | 激情欧美日韩一区二区 | 92国产精品久久久久首页 | 国产精品久久久久婷婷二区次 | 久久综合综合久久综合 | 欧美在线视频一区二区 | 国产精品视频99 | 欧美精品视 | 狠狠久久综合 | 91中文字幕网 | 亚洲精品午夜国产va久久成人 | 久久国产视频网站 | 久久午夜羞羞影院 | 亚洲免费成人av电影 | 91.精品高清在线观看 | 91在线中文字幕 | 在线免费观看的av网站 | 91三级在线观看 | 久久视频国产精品免费视频在线 | 三级大片网站 | 伊人天堂网 | 91亚洲精品在线观看 | 四虎在线免费观看 | 亚洲91在线| 日韩精品在线视频 | 国产精品中文 | 日韩在线免费看 | 综合伊人av | 亚洲天天做 | 国产精品久久久久久久久免费 | 国内精品久久久久影院优 | 久久99热这里只有精品国产 | 超碰97人人在线 | 91中文字幕网 | 亚洲一级电影在线观看 | 欧美另类xxx | 超碰公开在线观看 | 天天操天天操天天操天天操天天操 | 色欧美成人精品a∨在线观看 | 久久精品精品电影网 | 一二三精品视频 | 久久精国产 | 91精品国产三级a在线观看 | 精品国产一二三 | 久久人人看 | 国内精品久久久久影院男同志 | 精品一区二区在线观看 | 久久精品视| 国产在线观看,日本 | 国内外成人在线视频 | 日本在线视频网址 | 日韩色av色资源 | 99视频99 | 久草av在线播放 | 免费av大全| 婷婷色社区 | 98久9在线 | 免费 | 性色av一区二区三区在线观看 | 欧美日韩高清免费 | 国产精品精品国产婷婷这里av | 在线视频一区二区 | 在线亚洲播放 | 亚洲视频免费视频 | 国产免费视频一区二区裸体 | 欧美aa级 | 日韩精品一区电影 | 免费情缘 | 成人免费共享视频 | 日韩黄色在线电影 | 欧美福利片在线观看 | 精品电影一区 | 最近最新最好看中文视频 | 久久久免费电影 | 亚洲国产理论片 | 欧美性生活小视频 | 亚洲第五色综合网 | 色综合天天 | 国产精品一区二区三区在线 | 日韩网站在线播放 | 久久99国产精品 | 午夜精品久久 | 亚洲美女在线国产 | 国产亚洲高清视频 | 中文字幕免费看 | 欧美成人999 | 中文字幕五区 | 日韩欧美在线第一页 | 黄色免费电影网站 | 久久精品视频在线免费观看 | 天天五月天色 | 亚洲码国产日韩欧美高潮在线播放 | 久久视频中文字幕 | 亚洲视频每日更新 | 福利久久久 | 久久精品综合网 | 91在线视频观看 | 在线免费高清一区二区三区 | 久久精品老司机 | 特黄免费av | 在线国产欧美 | 中文字幕在线高清 | 波多野结衣视频一区 | 欧美精品乱码久久久久久 | 久久久久久久久久伊人 | 右手影院亚洲欧美 | 国产精品免费成人 | 成年人免费在线观看 | 国产 欧美 日产久久 | 激情网在线观看 | 欧美爽爽爽 | 亚洲精品电影在线 | 亚洲国产三级在线 | 日韩有码在线播放 | 日韩在线不卡av | 在线韩国电影免费观影完整版 | 欧美亚洲成人免费 | 日日干天天射 | 亚洲日本一区二区在线 | 国产区精品在线观看 | 人成在线免费视频 | 亚洲www天堂com | 亚洲手机天堂 | 嫩草伊人久久精品少妇av | 激情黄色一级片 | 久久精品综合一区 | 国产精久久久久久久 | 日本黄色免费播放 | 天天干天天干天天干天天干天天干天天干 | 国产一区二区在线观看免费 | 亚洲第一伊人 | 伊人五月天.com | 午夜性生活片 | 久久夜靖品 | 婷婷亚洲五月 | 欧美极品少妇xxxxⅹ欧美极品少妇xxxx亚洲精品 | 99久久精品免费看国产麻豆 | 在线观看日本高清mv视频 | 午夜久久久久 | 午夜国产福利在线观看 | av福利超碰网站 | 国产美腿白丝袜足在线av | 久久国产品 | 亚洲精品中文字幕在线 | 国产精品九色 | 一区二区三区在线视频观看58 | 亚洲不卡av一区二区三区 | av免费电影在线观看 | 亚洲国产资源 | 久久99精品久久久久蜜臀 | 在线观看中文字幕一区二区 | 五月婷婷在线观看 | 日韩欧美视频 | 麻豆视频国产精品 | 五月天高清欧美mv | 亚洲婷婷在线 | av字幕在线 | 亚洲精品合集 | 欧美性天天 | 超碰在线1 | 99精品视频免费观看 | 一区二区三区动漫 | 天天综合网久久综合网 | 中文字幕在线播放一区 | 美女精品在线 | 开心色插 | 久久久久区 | 国产高清在线不卡 | 亚洲禁18久人片 | 国产三级视频 | av一区二区在线观看中文字幕 | 免费在线国产精品 | 女人18精品一区二区三区 | 国产精品一区二区无线 | 色婷婷激情五月 | 天天操天天操天天操天天操天天操天天操 | 中文亚洲欧美日韩 | 日韩免费播放 | 美女一二三区 | 婷婷丁香狠狠爱 | 亚洲国产欧美一区二区三区丁香婷 | 欧美日韩国产亚洲乱码字幕 | 亚洲精品国 | 九九热在线视频免费观看 | 1024手机在线看 | 黄色影院在线观看 | 国产精品乱码久久久久 | 亚洲午夜精品福利 | 九九免费在线观看视频 | 国产精品欧美日韩 | 国产精品影音先锋 | 日韩欧美一区二区在线观看 | 国产福利91精品 | 天天操夜夜看 | 欧洲一区二区三区精品 | 国产91av视频在线观看 | 久久国产影视 | 干干干操操操 | 色综合天天 | 黄色免费在线视频 | 天天色欧美 | 久久精品4| 国产精品久久久久久欧美 | 91视频91蝌蚪 | 狠狠色丁香久久婷婷综合丁香 | 综合久久久久久 | 亚洲精品在线观看中文字幕 | 中文字幕传媒 | 亚洲九九九 | 激情丁香月 | 亚洲精品一区二区久 | 日日夜操 | 久久精品久久精品久久39 | 日批视频在线播放 | 国产精品久久久久久久妇 | 国产精品剧情在线亚洲 | 免费看污在线观看 | 国产精品中文字幕在线播放 | 午夜视频日本 | 日韩在线免费视频观看 | 黄色片视频在线观看 | 天堂在线一区 | 色激情五月 | 国产一级免费av | 欧美日韩高清一区 | 超碰在线98 | 久久免费精品国产 | 午夜精品久久久久久久99婷婷 | 夜夜干天天操 | 精品影院| 天天操网 | 欧美一区二区三区免费看 | 天天色草| 欧洲精品视频一区二区 | 久色网| 日韩三级.com | 国产精品久久久久久久7电影 | 在线免费观看黄色小说 | 国产女教师精品久久av | 亚洲激情 欧美激情 | 狠狠干狠狠色 | 久青草电影 | 五月激情久久 | 久草免费福利在线观看 | 国产精品久久久区三区天天噜 | 2019中文在线观看 | 成人黄色片在线播放 | 久久伦理电影网 | 丁香激情综合久久伊人久久 | 91视频麻豆 | 天天爽夜夜爽精品视频婷婷 | 久久九九精品久久 | www久久精品 | 成人国产精品免费观看 | 免费观看www视频 | 欧美aa在线| 亚洲精品影视在线观看 | 久久歪歪 | 天天干天天射天天爽 | av丝袜在线 | 婷婷日韩 | 午夜av在线 | 99电影 | 久久专区 | 中文字幕有码在线观看 | 国产香蕉在线 | 丝袜制服综合网 | 午夜国产在线观看 | 中文在线免费一区三区 | 国产精品免费久久久久久久久久中文 | 91亚洲精品久久久久图片蜜桃 | 免费视频久久久久久久 | 麻豆成人小视频 | 夜夜骑日日 | 国产精品一区二区久久精品 | 成人在线观看资源 | av在线电影网站 | 免费看的黄色小视频 | 91久久偷偷做嫩草影院 | 国产精品女视频 | 国产成人一级电影 | 夜夜躁日日躁 | 日韩一级片观看 | 91免费网 | 成人免费在线电影 | 五月婷婷网站 | 久草网站在线观看 | 亚洲妇女av| 中文字幕一区二区三区在线观看 | 亚州国产视频 | 人人舔人人舔 | 超碰久热 | 亚洲天天综合 | 日韩高清激情 | 国产精品一区二区久久 | 91在线视频网址 | 成人av久久 | 久碰视频在线观看 | 91视频在线自拍 | 日本韩国欧美在线观看 | 一区三区视频 | 欧美另类tv| 免费看v片 | 亚洲黄色激情小说 | av三级在线播放 | 国产欧美日韩一区 | 免费 在线 中文 日本 | 日韩免费视频一区二区 | 久久久www成人免费精品张筱雨 | 91精品国产91久久久久久三级 | 久久精品毛片 | 一区二区不卡视频在线观看 | 麻豆视频国产精品 | 亚洲va天堂va欧美ⅴa在线 | 日本一区二区三区视频在线播放 | 伊人狠狠色丁香婷婷综合 | 天堂av在线7 | av电影不卡| 午夜骚影| 日韩免费视频网站 | 亚洲免费精彩视频 | 国产成人精品久久久久蜜臀 | av色一区 | 国产一级视屏 | 色鬼综合网 | 香蕉视频网站在线观看 | 免费久久精品视频 | 爱爱av网| 日日夜夜网 | 久久艹人人 | 免费观看国产精品视频 | 婷婷九月激情 | 91久久电影 | 亚洲国产精品传媒在线观看 | 国产在线观看,日本 | 日韩精品一区电影 | 国产色视频一区二区三区qq号 | 午夜婷婷综合 | 91视频免费视频 | 久久综合日 | 国产精品久久久久久久久久久不卡 | av福利在线免费观看 | 中文字幕刺激在线 | 亚洲日韩欧美一区二区在线 | 欧美精品中文字幕亚洲专区 | 亚洲日本va在线观看 | 九九九九九九精品任你躁 | 国产一区国产精品 | 在线亚洲观看 | 久草免费新视频 | www.夜夜操.com | 91亚色免费视频 | 中文字幕亚洲欧美日韩 | 综合久久精品 | 久久精品国产一区 | 中文字幕在线观看三区 | 二区三区精品 | 99久久综合国产精品二区 | 久草香蕉在线视频 | 成年人视频在线免费 | 精品在线看 | 国产一级视频在线免费观看 | 中文字幕在线不卡国产视频 | 久久伊人精品一区二区三区 | 久久热首页 | 色爽网站| 国产美女在线免费观看 | 九九综合九九 | 日韩免费小视频 | 国产精品美女在线 | 日韩成人免费电影 | 国产主播99 | 狠狠狠色丁香婷婷综合激情 | 免费av大片 | 色婷婷色| 中文字幕婷婷 | 日本99精品 | av在线一| 欧美日韩在线观看一区二区三区 | 天天干夜夜 | 欧美黑人猛交 | 天堂av中文字幕 | 亚洲日韩欧美视频 | 午夜视频在线观看欧美 | 亚洲精品黄色 | 97免费在线视频 | 免费看的国产视频网站 | 在线视频观看91 | 日韩高清在线不卡 | 免费看污的网站 | 日韩久久久久久久 | 国产精品久久久一区二区 | 亚洲精品福利在线观看 | 国产99区 | 国产999精品久久久久久绿帽 | 日韩网站一区 | 97在线观看 | 久草网在线视频 | 韩国精品视频在线观看 | 五月激情av | 国产美女黄网站免费 | 91综合色| 激情欧美一区二区三区 | 麻豆国产精品一区二区三区 | 日p视频| 久久免费av电影 | 中文在线字幕观看电影 | www日韩| 精品在线观看国产 | 992tv人人草 黄色国产区 | 2019av在线视频| 狠狠躁夜夜躁人人爽超碰97香蕉 | 亚洲在线视频播放 | 黄色一级大片在线免费看国产一 | 一区二区三区免费播放 | 99热精品国产| 国产高清在线免费 | 超级碰碰碰免费视频 | 男女全黄一级一级高潮免费看 | 国产三级视频在线 | 中文字幕在线中文 | 成年人电影毛片 | 69成人在线 | 久久久精品小视频 | 国产一级一片免费播放放a 一区二区三区国产欧美 | 日韩综合一区二区三区 | 亚洲在线视频免费观看 | 国产日韩中文字幕 | 韩国三级在线一区 | 99色网站 | 国产精品国产三级国产aⅴ入口 | 亚洲精品视频在线播放 | free. 性欧美.com| 色窝资源| 国产精品破处视频 | 日韩欧美视频免费在线观看 | 一二三久久久 | 国产精品一区二区在线播放 | 亚洲乱码国产乱码精品天美传媒 | 天堂av网站| 欧美国产不卡 | 久久久免费高清视频 | 在线视频中文字幕一区 | 国产自在线| 国产一区福利 | 国产精品精品国产色婷婷 | 天天干,天天射,天天操,天天摸 | 久草在线费播放视频 | 黄色视屏在线免费观看 | 久草在线视频在线 | 久青草电影 | 国产在线更新 | 天天操天天操天天操天天操 | 91高清免费在线观看 | 久久人人精 | 在线观看小视频 | 亚洲最大在线视频 | a黄色影院 | 久久国产成人午夜av影院潦草 | 久久亚洲精品电影 | 天天综合网国产 | 日韩av一区二区三区 | 久久手机免费观看 | 国产亚洲片 | 91在线国内视频 | 国产综合91 | 青青草国产免费 | 911av视频 | 久久国产精品99久久人人澡 | 国产h在线播放 | 欧美淫视频 | 国内成人av| 97视频免费观看 | 色瓜| 亚洲三级在线免费观看 | 欧美永久视频 | 国产日韩精品一区二区 | 久久久高清免费视频 | 六月丁香在线视频 | 亚洲精品视频二区 | 久久免费看av | 精品国产网址 | 中文字幕亚洲欧美 | 水蜜桃亚洲一二三四在线 | 亚洲精品乱码久久久久久按摩 | 97人人精品| 欧美久久成人 | 久草在线免费看视频 | 成人国产精品久久久 | 久久高清视频免费 | 午夜12点| 久久五月婷婷丁香 | 国产成人在线免费观看 | 一区在线观看 | 免费亚洲精品视频 | 日韩欧美高清在线观看 | 国产成人精品在线播放 | 在线观看资源 | 亚洲综合色婷婷 | 色综合久久久久 | 欧美日韩精品免费观看视频 | 91豆花在线观看 | 美女视频一区二区 | 久久婷五月 | 亚洲激情在线 | 国产黄色免费看 | 国产成人免费 | 午夜精品久久久久久久99婷婷 | 亚洲色影爱久久精品 | 亚洲理论在线观看电影 | 精品视频不卡 | 亚洲高清不卡av | 狠狠狠狠狠狠天天爱 | 成人国产一区二区 | 丁香婷婷电影 | 色综合国产 | 欧洲亚洲激情 | 国产精品精品国产 | 免费午夜在线视频 | 亚洲综合丁香 | 欧美精品国产综合久久 | 在线看国产一区 | 日本精品视频在线观看 | 91大神dom调教在线观看 | 国产一区二区三精品久久久无广告 | 久久人人爽爽 | 国产美女被啪进深处喷白浆视频 | 国产在线传媒 | 欧美日韩精品影院 | 人人干,人人爽 | 国产一区二区在线免费播放 | 日日射av | www激情com | 亚洲欧美日韩国产精品一区午夜 | 久久夜av | 国产69久久精品成人看 | 美女黄久久 | 特级毛片在线免费观看 | av在线播放免费 | 干 操 插| 中文字幕高清免费日韩视频在线 | 久久精品国产精品亚洲 | 中文字幕电影高清在线观看 | 欧美激情视频一区二区三区免费 | 日韩黄色一区 | 国产高清精 | 久久激情小说 | 99精品欧美一区二区 | 婷婷四房综合激情五月 | japanese黑人亚洲人4k | 操操操日日 | 亚洲全部视频 | 国产视频欧美视频 | 国产破处在线播放 | 国产夫妻av在线 | 亚洲精品国产精品久久99热 | av中文天堂在线 | 欧美一区二区精美视频 | 91在线一区 | 超碰日韩 | 精品视频中文字幕 | 免费欧美高清视频 | 69xx视频| 最近免费观看的电影完整版 | 五月丁婷婷 | 中文字幕在线看 | 美女精品国产 | 91视频91色 | 国产成人精品av在线观 | 日韩a级黄色 | 毛片视频电影 | 久久欧美综合 | 国产男女无遮挡猛进猛出在线观看 | 久久成人精品电影 | 最新国产精品久久精品 | 国产精品午夜在线观看 | 超碰97.com | 国产精品久久久久久久久久久久午夜片 | 久久精品com | 91久久国产综合精品女同国语 | 丁香婷婷激情国产高清秒播 | 欧美一区二区伦理片 | 久久伦理 | 夜色成人网 | 一区 二区电影免费在线观看 | 99在线观看精品 | 高清中文字幕 | 日韩精品不卡 | 中文字幕在线看视频 | 99久久久久国产精品免费 | 亚洲综合狠狠干 | 在线成人观看 | 国产一区视频免费在线观看 | 久久精品国产v日韩v亚洲 | 狠狠干.com| 日本公乱妇视频 | 综合激情 | 中文字幕在线播放视频 | 国产免费人人看 | 日韩有码专区 | 91麻豆精品国产91 | 中文在线中文资源 | 天天干天天摸 | 九九精品视频在线观看 | 欧美日韩视频一区二区 | 亚洲黄色大片 | 免费午夜在线视频 | 五月天激情视频在线观看 | 97视频久久久| 国产美腿白丝袜足在线av | 免费看的黄色录像 | 91视频xxxx| 日韩免费播放 | 韩国av免费 | 天天操天| 国产高清日韩欧美 | 成人免费一区二区三区在线观看 | 欧美巨大 | 亚洲免费av观看 | 国产经典av | 狠狠操欧美 | 亚洲国产小视频在线观看 | 中文字幕中文字幕在线中文字幕三区 | 91香蕉久久 | 日韩精品一区二区不卡 | 国产v视频 | 亚洲天堂网在线视频观看 | 在线观看岛国片 | 日韩精品中文字幕有码 | av网站大全免费 | 亚洲综合一区二区精品导航 | 国产精品第一页在线 | 欧美精彩视频在线观看 | 成人av电影在线 | 日本在线观看一区二区 | 一区二区三区在线观看中文字幕 | 午夜丰满寂寞少妇精品 | 亚洲精品视频观看 | 日韩av在线影视 | 五月视频 | 99视频在线看 | 麻豆影视在线观看 | 日批网站在线观看 | 不卡av在线播放 | 久久精品精品 | 欧美日韩中文在线 | 国产高清视频免费在线观看 | 亚洲成人av在线播放 | 91av在线免费播放 | 久久精品96 | 天堂资源在线观看视频 | 一区二区三区日韩在线 | 91av在线电影| 久久亚洲婷婷 | 亚洲欧洲国产视频 | 狠狠色丁香婷婷综合欧美 | 久久露脸国产精品 | 香蕉视频久久久 | 国产高清免费 | 久久人人插 | 亚洲精品91天天久久人人 | 91亚洲国产成人久久精品网站 | 国产成人三级在线观看 | 狠狠色伊人亚洲综合成人 | 日韩高清不卡在线 | 日韩精品欧美专区 | 亚洲精品乱码久久久久久 | 人人插人人舔 | 国内精品久久久久久久久久久久 | 一区久久久 | 中文在线a∨在线 | 中文在线字幕免 | 国内视频 | 一区二区三区视频 | 亚洲欧美成人综合 | 亚洲免费在线观看视频 | 五月天九九 | 日韩a在线看 | 久久你懂得 | 美女网站在线 | 天天操导航 | 天天干夜夜爱 | 天天爱综合| 免费日韩 精品中文字幕视频在线 | 一级全黄毛片 | 亚洲国产欧洲综合997久久, | 欧美日韩视频免费看 | 韩国一区在线 | 在线免费av电影 | 色综合天天狠天天透天天伊人 | 日本视频高清 | 天天色天天射天天干 | 亚洲天天综合网 | 免费在线观看av的网站 | 在线观看日本高清mv视频 | 日本aaaa级毛片在线看 | 亚洲精品伦理在线 | 最新日本中文字幕 | 久久国产精品视频观看 | 粉嫩一区二区三区粉嫩91 | 69亚洲视频| 美女网站视频一区 | 色综合久久综合 | 人人盈棋牌 | 欧美视屏一区二区 | 国产激情小视频在线观看 | 色久天 | 日韩午夜av| 在线国产精品一区 | 一区二区视频电影在线观看 | 久久久久国产一区二区三区 | 亚洲色影爱久久精品 | 五月天综合网站 | 成人国产一区二区 | 狠狠干婷婷色 | 中文字幕一区二区三区乱码不卡 | 麻豆视频免费观看 | 国产成人精品一区二区 | 免费不卡中文字幕视频 | 免费看十八岁美女 | 中文字幕亚洲欧美日韩 | 日本不卡123 | 亚洲最新合集 | 五月天丁香视频 | 日韩av一区二区三区四区 | 操操操日日日干干干 | 久久伊人爱 | 成人毛片一区 | 久久综合成人 | 深爱激情亚洲 | 精品成人久久 | 免费不卡中文字幕视频 | 黄色成人毛片 | 在线免费国产视频 | 国产美女免费看 | 99久久99久久精品免费 | 欧美激情精品久久久久久 | 日韩久久久久 | 99人成在线观看视频 | 久久怡红院| 99在线视频播放 | 黄色在线小网站 | 亚洲国产视频直播 | 国产xxxx做受性欧美88 | 三上悠亚一区二区在线观看 | 欧美极品少妇xxxxⅹ欧美极品少妇xxxx亚洲精品 | 美女久久久久久久久久 | 亚洲精品一区二区三区在线观看 | 日韩av黄| 99精品黄色| 亚洲免费观看在线视频 | 久免费视频 | 最新极品jizzhd欧美 | 97香蕉超级碰碰久久免费软件 | 毛片在线网| 成人理论在线观看 | 国产精品乱码一区二区视频 | 人人讲下载 | 久久理论影院 | 狠狠操狠狠干天天操 | 国产精品国产亚洲精品看不卡15 | 97视频久久久 | 久碰视频在线观看 | 国产在线精品国自产拍影院 | 看污网站 | 欧美va天堂va视频va在线 | 欧美成人免费在线 | av一级在线| 色婷婷激情电影 | 韩国一区二区三区视频 | 国产精品国产三级国产不产一地 | 香蕉视频网站在线观看 | 色综合天天做天天爱 | 91丨九色丨蝌蚪丰满 | 欧美韩国日本在线观看 | 欧美日韩伦理在线 | 超碰日韩 | 一本一道波多野毛片中文在线 | 97国产精品一区二区 | 国产精品不卡一区 | 亚洲激情视频 | 日日夜夜人人精品 | 久久激情视频 | 中文字幕色在线视频 | 夜夜操狠狠干 | 中文字幕在线免费看 | 国产999久久久 | 精品久久久久一区二区国产 | 国产精品欧美在线 | 国产美女搞久久 | 激情综合电影网 | 成人蜜桃 | 国产高清在线观看av | 欧美亚洲精品一区 | 黄色三级网站在线观看 | 97色综合| 久久黄色成人 | 色资源网免费观看视频 | av高清在线观看 | 操高跟美女| 久久伦理电影网 | av免费在线免费观看 | 色射色| 精品嫩模福利一区二区蜜臀 | 国产在线观看高清视频 | 2021国产精品 | 欧美极品在线播放 | 黄色av高清| 一区二区激情视频 | 国产色婷婷精品综合在线手机播放 | 亚洲视频观看 | 激情xxxx| av高清网站在线观看 | 国产美女在线观看 | 国产精品久久久久久麻豆一区 | 亚洲天堂精品视频在线观看 | 国产精品福利在线播放 | 国产色女人 | 日本中文字幕在线 | 日本精品久久久久中文字幕 | 婷婷丁香视频 | 亚洲精品国产欧美在线观看 | 天天躁天天操 | 亚洲黄色免费观看 | 久久久久久在线观看 | 99久久er热在这里只有精品66 | 五月婷婷丁香网 | 天天综合导航 | 免费观看一区二区 | 91香蕉视频黄 | 在线黄色av| 丁香视频免费观看 | 日本精品中文字幕在线观看 | 久久久久久伊人 | 免费看成人av | 天堂va欧美va亚洲va老司机 | www·22com天天操| 在线播放国产精品 | 成人免费ⅴa | 亚洲视频axxx | 主播av在线 | 热久精品 | av免费网| 黄色91在线| 亚洲综合一区二区精品导航 | 99riav1国产精品视频 | 亚洲一区视频在线播放 | 一区二区三区四区五区在线 | 日本婷婷色 | 久久久久久久久综合 | 国产精品第10页 | 操高跟美女 | 亚洲永久在线 | 久久久久北条麻妃免费看 | 久av在线 | 激情五月婷婷激情 | 精品国产99 | 99热国产在线中文 | 狠狠色伊人亚洲综合网站色 | 成av在线| 在线激情影院一区 | 免费亚洲精品视频 | 综合网伊人| 在线免费观看羞羞视频 | 国产五码一区 | 久久图| 超碰人人草人人 | 粉嫩av一区二区三区四区 | 国产成人精品一区二区三区福利 | 日p视频在线观看 | 久久精品国亚洲 | 久草在线99 | av大片免费| 国产精品久久久久久久久久尿 | 五月婷婷综合激情网 | 国产精品久久久久婷婷 | japanesefreesex中国少妇 | 久久精品99国产精品日本 | 婷婷福利影院 | 黄色片视频在线观看 | 国产精品2020 | 久久精品中文 | 成人在线观看免费视频 | www亚洲国产 | 天天射网站 | 亚洲精品一区二区三区在线观看 | 最近免费中文字幕大全高清10 | 91mv.cool在线观看 | 国产精品黑丝在线观看 | 久久理论电影 | 天天操天天操天天操天天操天天操天天操 | 国产精品久久久久久久毛片 | 国产高清免费av | 狠狠躁18三区二区一区ai明星 | 欧美日韩一区二区在线 | 亚洲精品字幕 | 亚洲精品视频大全 | 亚洲涩综合 | 91九色porny蝌蚪视频 | 黄视频色网站 | 欧美日韩视频一区二区 | 成人黄色电影在线观看 | 亚洲国产午夜视频 | 久久精品小视频 | 精品久久久久久一区二区里番 | 日韩精品久久久久久 | 91视频久久久 | 91精选在线观看 | 亚洲综合色播 | 日日噜噜噜噜夜夜爽亚洲精品 | 91精品办公室少妇高潮对白 | 日韩三级久久 | 欧美日本啪啪无遮挡网站 | 国产一区二区三区久久久 | 狠狠做深爱婷婷综合一区 | 亚洲视频axxx | 亚洲va韩国va欧美va精四季 | 欧美日韩综合在线 | 麻豆精品在线 | 福利精品在线 | 国产亚洲视频中文字幕视频 | 色网址99|