python 學(xué)習(xí)筆記

pyton review

  • 學(xué)習(xí)指南 https://www.zhihu.com/question/29138020

  • 運(yùn)行

    • 在Windows上運(yùn)行Python時(shí),請(qǐng)先啟動(dòng)命令行,然后運(yùn)行python。
    • 在Mac和Linux上運(yùn)行Python時(shí),請(qǐng)打開(kāi)終端,然后運(yùn)行python3。(本身有Python2版本文件, 為區(qū)分)
  • python 為解釋型語(yǔ)言

  • 解釋器種類(lèi)

    • 默認(rèn)為CPython,
    • IPython 基于CPython
    • PyPy追求執(zhí)行速度執(zhí)行動(dòng)態(tài)編譯 與CPythin可能相同代碼不同執(zhí)行結(jié)果
    • Jython 運(yùn)行于Java平臺(tái)的Python解釋器,編譯Python代碼為Java字節(jié)碼
    • IronPython運(yùn)行于.Net
  • 可以直接 命令行中 python hello.py 執(zhí)行python文件 hello.py

  • Mac與Linux可以直接運(yùn)行.py文件, win不行需要在文件第一行, 還要命令給文件已執(zhí)行權(quán)限chmod a+x hello.py

    #!/usr/bin/env python3
    
  • print()可接受多個(gè)字符串, 用逗號(hào)','隔開(kāi)輸出連接逗號(hào)轉(zhuǎn)變成空格

  • input()輸入, input('please enter your name:')參數(shù)是友好提示

  • 數(shù)字 十六進(jìn)制0xff00, 浮點(diǎn)數(shù) 1.23e-8,計(jì)算機(jī)由于使用二進(jìn)制,所以,有時(shí)候用十六進(jìn)制表示整數(shù)比較方便,十六進(jìn)制用0x前綴和0-9,a-f表示,例如:0xff00,0xa5b4c3d2,等等。

  • 字符串 r''內(nèi)部字符串不轉(zhuǎn)義

  • print('''...''')格式表示多行內(nèi)容與r'''...'''可組合使用

    • print('''line1
      ... line2
      ... line3''')
      line1
      line2
      line3
      
  • boolean值 True,False , 可用 and, or , not 運(yùn)算

  • None值

  • /浮點(diǎn)除, // 地板除, %取余 10/3 浮點(diǎn)型 10//3 整數(shù) 除地板

  • 編碼ASCII,Unicode,為傳輸存儲(chǔ)速度發(fā)明了可變長(zhǎng)編碼UTF-8, A 65, a 97, 0 48

  • python字符串

    • python 字符串 ord('A') chr(20013), 也可以十六進(jìn)制直接寫(xiě)出'\u0030'
    • 'dkjKJDFL'.lower(), 'adf'.upper()
    • b'ABC'直接轉(zhuǎn)化為bytes,非單字節(jié)字符, 需用'中文'.encode('utf-8');
    • 如果encode無(wú)法顯示為ASCII,用\x##表示, 字節(jié)流轉(zhuǎn)義用 decode()
    b'\xe4\xb8\xad\xe6\x96\x87'.decode('utf-8')
    
    • 計(jì)算字符長(zhǎng)度len('中文'),用轉(zhuǎn)換為bytes.len()可計(jì)算字節(jié)數(shù)
    • 為避免編碼問(wèn)題,保存源碼指定保存為UTF-8編碼讀取, 通常在文件開(kāi)頭寫(xiě)入
      #!/usr/bin/env python3
      # -*- coding: utf-8 -*-
      
      • 格式化占位符用% 'hello, %s' % 'world', 順序?qū)?yīng)%s替換字符串, %d替換整數(shù) %f浮點(diǎn)數(shù) %x 十六進(jìn)制整數(shù), %%轉(zhuǎn)義為%, 可定義整數(shù)補(bǔ)零位數(shù)%05d, 浮點(diǎn)數(shù)小數(shù)點(diǎn)后保留位數(shù)%.3f
        'Hi, %s, you have $%d.' % ('Michael', 1000000)
       'Hi, Michael, you have $1000000.'
      
  • list

    • 定義 classmates = ['eric','eric2','eric3']
    • 訪問(wèn) classmats[1], 最后一個(gè)元素下標(biāo) len(classmates)-1
    • 添加元素, classmates.apppend('eric4'), classmates.insert(1,'Jack')
    • 刪除元素, classmates.pop(), 指定下標(biāo) classmates.pop(2)
    • 內(nèi)含元素可以不同類(lèi)型
  • tuple

    • 一旦定義不可修改 tp = ('eric','eric2','eric3')
    • 定義 可簡(jiǎn)化(), 多變量可接收 tuple值,按位置賦值
    • 訪問(wèn)操作相同 tp[1]
    • ps: 一個(gè)元素(1), 括號(hào)優(yōu)先為規(guī)避此問(wèn)題, 一個(gè)元素 加逗號(hào)(1,)
  • 分支結(jié)構(gòu)判斷

      a = 100
      if a>=0:
        print(a)
      elif a>-10:
        print(a)
      else:
        print(-a)
    
  • if x: 只要x為非零數(shù)值, 非空字符串, 非空l(shuí)ist等, 就判斷為T(mén)rue, 否則為False

  • 提供int()用于轉(zhuǎn)int型

  • 循環(huán)結(jié)構(gòu)

    • 簡(jiǎn)單 for name in classmates: print(name), 遍歷集合數(shù)組
    • list(range(101)),生成[0,1,2,3,...100]
    • while n > 0: n = n + 2
  • dict

    • 定義 d = {'eric':0,'eric2':2, 'eric3':3}
    • 訪問(wèn) d['eric2'],
    • 判斷元素, 訪問(wèn)不存在會(huì)報(bào)錯(cuò), 可以在訪問(wèn)前, 判斷元素 'eric' in d, 返回 boolean, d.get('eric')存在返回value不存在返回None(ps: 返回值為None時(shí)交互命令行不顯示結(jié)果), 或者自己指定的返回值, d.get('eric',-1)
    • 添加元素 d['eric4'] = 4, 存在原元素則進(jìn)行替換
    • 刪除元素, d.pop('eric2') 同時(shí)返回value
  • set 不重復(fù) 是一組key的集合, 不儲(chǔ)存value, key不重復(fù)

    • 定義 s = {1,2,3,3,3,3,4,5} s = {1,2,3,4,5}
      > s = set([1,2,3,3,4,5])
      > s
      > {1,2,3,4,5}
      
    • 添加元素 s.add(6), 重復(fù)添加無(wú)效果
    • 刪除元素 s.remove(key)
    • set可以做數(shù)學(xué)意義上的交并集操作 s1 & s2, s1 | s2
  • 調(diào)用函數(shù) abs(22), int('22'), hex(22), bool(22)

  • 定義函數(shù) def my_abs(x):

    • 如果定義一個(gè)什么也不做的空函數(shù), 可以用pass語(yǔ)句,缺少pass運(yùn)行有語(yǔ)法錯(cuò)誤

       def nop():
           pass
      
    • 當(dāng)沒(méi)有return語(yǔ)句時(shí), 函數(shù)執(zhí)行結(jié)束也會(huì)返回結(jié)果, 結(jié)果為None,

    • return None, 可簡(jiǎn)化為return

    • 函數(shù)可返回多個(gè)值

      return nx, my, x,y = move(100,100,60, math.pi/6)

      Ps:返回多個(gè)值實(shí)際為假象, 多個(gè)值打包為tuple, 語(yǔ)法上返回一個(gè)tuple可以省略括號(hào), 多個(gè)標(biāo)量接受tuple, 按位置賦值, 對(duì)書(shū)寫(xiě)的簡(jiǎn)化

    • math.pi, math.sqrt, math.pow

  • 數(shù)據(jù)類(lèi)型檢查 isinstance(obj, class_or_tuple) 拋出異常

    raise TypeError('bad operand type')

  • 函數(shù)的參數(shù)

    • 位置參數(shù), 對(duì)參數(shù)提供默認(rèn)值, 則是默認(rèn)參數(shù)Ps: 默認(rèn)參數(shù)在必選參數(shù)后, 調(diào)用函數(shù)時(shí), 不按照位置, 需要提供參數(shù)名Ps2: 默認(rèn)參數(shù)必須是不可變對(duì)象, 否則默認(rèn)參數(shù)可能改變
    • 可變參數(shù)
      def sum(*num):
      sum(3,4,5,6), sum(*[2,3,4])
      
    • 關(guān)鍵字參數(shù) 傳入多個(gè), 內(nèi)部整合為dict
    • 命名關(guān)鍵詞參數(shù), 命名關(guān)鍵詞需要一個(gè)特殊的分隔符*, 有可變參數(shù), 后面為命名關(guān)鍵詞參數(shù)不再需要分隔符*
    • 參數(shù)組合順序, 必選參數(shù), 默認(rèn)參數(shù), 可變參數(shù), 命名關(guān)鍵詞參數(shù), 關(guān)鍵詞參數(shù)
    • 方法調(diào)用傳參可通過(guò)func(*args,**kw), *args是可變參數(shù),args接收的是一個(gè)tuple;**kw是關(guān)鍵字參數(shù),kw接收的是一個(gè)dict。以及調(diào)用函數(shù)時(shí)如何傳入可變參數(shù)和關(guān)鍵字參數(shù)的語(yǔ)法:可變參數(shù)既可以直接傳入:func(1, 2, 3),又可以先組裝list或tuple,再通過(guò)*args傳入:func(*(1, 2, 3));關(guān)鍵字參數(shù)既可以直接傳入:func(a=1, b=2),又可以先組裝dict,再通過(guò)**kw傳入:func(**{'a': 1, 'b': 2})。使用*args和**kw是Python的習(xí)慣寫(xiě)法,當(dāng)然也可以用其他參數(shù)名,但最好使用習(xí)慣用法。
  • 遞歸函數(shù)

    • 調(diào)用本身, 注意遞歸結(jié)束條件
    • 尾遞歸與循環(huán)等價(jià), 對(duì)尾遞歸優(yōu)化可以解決棧溢出問(wèn)題
  • 切片

    • 切片取前三個(gè)元素L[start:end:n],Ps: 第一個(gè)元素為0可省略,第二個(gè)元素默認(rèn)為最后一個(gè)元素,第三個(gè)元素指n元素取1含頭不含尾
    • tuple 切片操作返回tuple
    • string 切片返回string
    • -1為最后一個(gè)元素
  • 列表生成式

    • list(range(4,10))
    • [x*x for x in range(1,11)]
    • 可以循環(huán)嵌套, 生成全排列 [m + n for m in 'ABC' for n in 'XYZ']
    • 可以多變量生成列表生成器 [k + '=' + v for k,v in d.items()]
  • isinstance(obj, class_or_tuple) 判斷變量類(lèi)型

  • 生成器 generator

    • 定義 列表生成器 [] 換為()
    • 獲取 next(iterator[,default])
    • 遍歷 for n in g:
    • 多變量賦值 a,b = b, a+b 相當(dāng)于省略臨時(shí)變量
      t = (b,a+b)
      a = t[0]
      b = t[1]
    
    • 可以用函數(shù)作為generator, 如果函數(shù)包含yield關(guān)鍵詞, 那么函數(shù)將不再是普通函數(shù), 而是一個(gè)generator, generator在調(diào)用next()的時(shí)候執(zhí)行, 遇到y(tǒng)ield語(yǔ)句返回, 再次執(zhí)行從上次yield語(yǔ)句出繼續(xù)執(zhí)行
  • 迭代器 Iterable, from collections import Iterable

    • 可以用 isinstance函數(shù)判斷
    • 生成器為Iterator對(duì)象, 但list,dict,str 雖然是Iterable, 卻不是Iterator
    • Iterator 對(duì)象表示的是一個(gè)數(shù)據(jù)流, next()函數(shù)函數(shù)調(diào)用返回下一個(gè)數(shù)據(jù),Iterator計(jì)算是惰性的,
    • 凡是可作用于for 循環(huán)的對(duì)象都是Iterable類(lèi)型:
    • 凡是可作用于next()函數(shù)的對(duì)象都是Iterator類(lèi)型, 他們表示一個(gè)惰性計(jì)算序列;
    • 集合類(lèi)型, 可以通過(guò)iter()函數(shù)獲得一個(gè)Iterator對(duì)象
  • 函數(shù)式編程

    • 函數(shù)編程是一種抽象程度很高的編程范式, 純粹的函數(shù)式編程函數(shù)沒(méi)有變量, 因此, 只要輸入是確定的, 輸出就是確定的,
    • 函數(shù)式編程特點(diǎn), 可以允許把函數(shù)本身作為參數(shù)傳入另一個(gè)函數(shù), 還允許返回一個(gè)函數(shù)
    • python對(duì)函數(shù)式編程部分支持, 由于Python允許使用變量, 因此Python不是純函數(shù)式編程語(yǔ)言
  • 高階函數(shù): 變量可以指向函數(shù), 一個(gè)函數(shù)可以接收另一個(gè)函數(shù)作為參數(shù), 這樣的函數(shù)就稱(chēng)之為高階函數(shù), 函數(shù)式編程指這種高度抽象的編程范式

  • 遞歸是對(duì)問(wèn)題的描述, 循環(huán)是對(duì)問(wèn)題的求解, 相當(dāng)于方程組和計(jì)算式的關(guān)系

    • 線(xiàn)性遞歸, 樹(shù)形遞歸, 尾遞歸(可優(yōu)化為循環(huán))
  • map : map(func, *iterables) --> map object

  • reduce : map(fucntion, sequence[,initial]) --> value

  • filter : filter(function or None , iterable) --> filter object

    • 求素?cái)?shù), 先定義一個(gè)生成器, 埃氏篩法, 不斷嵌套filter, 篩選下一個(gè)素?cái)?shù)
  • sorted : sorted(iterable, key=None, reverse=False)

    • key 是提供一個(gè)映射關(guān)系, 對(duì)原值進(jìn)行映射, 返回結(jié)果, 以返回結(jié)果排序?qū)υ颠M(jìn)行排序
  • 返回函數(shù) 以函數(shù)作為返回值, lazy_sum 閉包結(jié)構(gòu)

    • 返回一個(gè)函數(shù)時(shí), 牢記該函數(shù)并未執(zhí)行 返回的函數(shù)中不要引入任何可能變化的變量
  • lambda x,y : x*10+y

    • 只能有一個(gè)表達(dá)式, 不用寫(xiě)return, 返回值就是該表達(dá)式的結(jié)果
    • 匿名函數(shù)也是函數(shù)對(duì)象, 可以復(fù)制給一個(gè)變量, 再用變量來(lái)調(diào)用該函數(shù)
    • 匿名函數(shù)也是函數(shù)對(duì)象, 也可以作為返回值
    • python支持有限, 只有一些簡(jiǎn)單情況可以使用
  • 10**3 = 1000, 代表冪計(jì)算

  • 裝飾器 : 在運(yùn)行期間動(dòng)態(tài)增加功能, 又不修改原函數(shù)的定義, 這種方式我們稱(chēng)之為裝飾器(Decorator)

    • 函數(shù)對(duì)象可以被賦值給其他變量, __name__可以拿到函數(shù)原名
    • @語(yǔ)法 log定義在now函數(shù)上,相當(dāng)于log(now),
    def log(func):
    def wrapper(*args, **kw):
        print('call %s():' % func.__name__)
        return func(*args, **kw)
    return wrapper
    
    • 多一層@log('eric'), 相當(dāng)于 log('eric')(now)
    def log(text):
    def decorator(func):
        def wrapper(*args, **kw):
            print('%s %s():' % (text, func.__name__))
            return func(*args, **kw)
        return wrapper
    return decorator
    
    • 解決__name__變?yōu)閣rapper, import functools 使用@functionls.wraps(func)
  • 偏函數(shù) 是引入已有方法, 創(chuàng)建一個(gè)新函數(shù)可以固定住原函數(shù)的部分參數(shù), 從而使調(diào)用時(shí)更簡(jiǎn)單

    • import functools
    • int2 = functools.partial(int, base=2)
    • help : partial(func, *args, **keywords) - new function with partial application of the given arguments and keywords.
  • 模塊

    • 按目錄組織模塊, 包Package
    • 包中有一個(gè)__init__.py文件, 這個(gè)文件必須存在, 否則Python就會(huì)把這個(gè)目錄當(dāng)成普通目錄, 而不是一個(gè)包, 這個(gè)文件可以是空文件, 也可以有Python代碼, 因?yàn)開(kāi)_init__本身就是一個(gè)模塊, 而模塊名就是包名
    • 可以有多級(jí)目錄, 組成多級(jí)層次包結(jié)構(gòu)
    • 注意不要和Python自帶模塊名沖突
  • 使用模塊

    • sys模塊, 內(nèi)部argv變量, 存儲(chǔ)命令行參數(shù), python hello.py 獲得的 sys.argv就是['hello.py'];, 運(yùn)行python hello.py Eric 獲得的sys.argv就是['hello.py','Eric']
    • if __name__ == '__main__':test(), 當(dāng)我們命令行運(yùn)行hello模塊式, Python解釋器將一個(gè)特殊變量__name__置為_(kāi)_main__,而其他地方導(dǎo)入hello模塊, if判斷將失敗, 因此, 這種if測(cè)試可以讓一個(gè)模塊通過(guò)命令行運(yùn)行時(shí)執(zhí)行一些額外代碼, 最常見(jiàn)就是用于運(yùn)行測(cè)試
    • 作用域
      • abc, x123, PI 為public
      • _xxx, __xxx為非公開(kāi)(private),
      • __name__等為特殊變量, 可以直接引用, 但是有特殊用途,__author__,文檔注釋可以用__doc__訪問(wèn)等
  • 第三庫(kù)

    • 通過(guò)pip來(lái)下載 , pip 軟件包管理系統(tǒng)
    • pip --version
    • pip install Pillow,pip install some-package-name
    • pip uninstall some-package-name
    • 加載模塊, Python在指定路徑下搜索對(duì)于.py文件, 找不到,就報(bào)錯(cuò)
      • 默認(rèn)搜索當(dāng)前目錄, 所有已安裝內(nèi)置模塊和第三方模塊, 搜索路徑存放于sys模塊path變量
        import sys
        sys.path
      
      • 可修改sys.path
        • sys.paht.append('/u...'), 運(yùn)行時(shí)生效, 運(yùn)行結(jié)束后失效
          - 修改環(huán)境變量PYTHONPATH, 永久修改

  • 面向?qū)ο缶幊?數(shù)據(jù)封裝, 繼承, 多態(tài)

    • __init__為特殊實(shí)例化方法, 可以在創(chuàng)建實(shí)例時(shí)將認(rèn)為必須綁定的數(shù)據(jù)強(qiáng)制寫(xiě)進(jìn)去
    • class Student(object) , 括號(hào)內(nèi)時(shí)父類(lèi)繼承類(lèi), 默認(rèn)object
    • class 內(nèi)方法, 第一個(gè)參數(shù)為對(duì)象本身
    • 與靜態(tài)語(yǔ)言不通, Python允許對(duì)實(shí)例對(duì)象綁定任何數(shù)據(jù), 也就是說(shuō), 對(duì)于兩個(gè)實(shí)例變量, 雖然他們都是一個(gè)類(lèi)的不同實(shí)例, 但擁有的變量名稱(chēng)可能不同
  • 訪問(wèn)限制

    • 雙下劃線(xiàn)前綴代表private變量, 而單下劃線(xiàn)前綴的實(shí)例變量外部時(shí)可以訪問(wèn)的, 但是, 按照約定俗稱(chēng)的規(guī)定, 當(dāng)你看到這樣的變量時(shí), 意思是, '雖然我可以被訪問(wèn), 但是, 請(qǐng)把我視為私有變量, 不要隨意訪問(wèn)'
    • 雙下劃線(xiàn)不能直接訪問(wèn), 是因?yàn)镻ython解釋器對(duì)外將Student類(lèi), 將__name變量改成了_Student__name, 所以仍然可以通過(guò)改變后的變量名訪問(wèn)到,但不要這樣做, 不同版本解釋器變量名可能不同
    • 表面上看,外部代碼“成功”地設(shè)置了__name變量,但實(shí)際上這個(gè)__name變量和class內(nèi)部的__name變量不是一個(gè)變量!內(nèi)部的__name變量已經(jīng)被Python解釋器自動(dòng)改成了_Student__name,而外部代碼給bart新增了一個(gè)__name變量
    • Python本身沒(méi)有有效高強(qiáng)制的訪問(wèn)限制, 需要自覺(jué)遵守規(guī)范
    • 私有變量, get set方法
  • 繼承 Animal(object) Cat(Animal) Dog(Animal)

    • 獲得父類(lèi)方法
    • 多態(tài) 對(duì)父類(lèi)方法改進(jìn)
    • 靜態(tài)語(yǔ)言和動(dòng)態(tài)語(yǔ)言,對(duì)于靜態(tài)語(yǔ)言(例如Java)來(lái)說(shuō),如果需要傳入Animal類(lèi)型,則傳入的對(duì)象必須是Animal類(lèi)型或者它的子類(lèi),否則,將無(wú)法調(diào)用run()方法。對(duì)于Python這樣的動(dòng)態(tài)語(yǔ)言來(lái)說(shuō),則不一定需要傳入Animal類(lèi)型。我們只需要保證傳入的對(duì)象有一個(gè)run()方法就可以了:
  • 獲取對(duì)象信息

    • type help : type(object) -> the object's type

    • isinstance help : isinstance(obj, class_or_tuple) -> return whether an object is an instance of a class or of a subclass thereof

    • dir help : dir([object]) -> list of strings, If called without an argument, return the names in the current scope. Else, return an alphabetized list of names comprising (some of) the attributes of the given object, and of attributes of the given object, and of attributes reachable from it.

    • 類(lèi)似xxx的屬性和方法在Python中都是有特殊用途的,比如len方法返回長(zhǎng)度。在Python中,如果你調(diào)用len()函數(shù)試圖獲取一個(gè)對(duì)象的長(zhǎng)度,實(shí)際上,在len()函數(shù)內(nèi)部,它自動(dòng)去調(diào)用該對(duì)象的len()方法,我們自己寫(xiě)的類(lèi),如果也想用len(myObj)的話(huà),就自己寫(xiě)一個(gè)len()方法:

    • 也可以把一個(gè)對(duì)象的方法賦予一個(gè)變量

    • 可以用getattr(), setattr()以及hasattr()直接對(duì)一個(gè)對(duì)象的狀態(tài)進(jìn)行操作

    • 通過(guò)內(nèi)置一系列函數(shù), 我們可以對(duì)任意一個(gè)Python對(duì)象進(jìn)行讀取, 拿到其內(nèi)部的數(shù)據(jù). 要注意的是, 只有不知道對(duì)象信息的時(shí)候, 我們才會(huì)去獲取對(duì)象的信息. 如果知道可以直接寫(xiě): 而不是下面第二種寫(xiě)法

        > sum = obj.x + obj.y
        > sum = getattr(obj, 'x') + getattr(obj,'y')
      

      對(duì)象未知時(shí)先判斷, 鴨子類(lèi)型

      def readImage(fp):
          if hasattr(fp, 'read')
              return readData(fp)
          return None
      
  • 實(shí)例屬性和類(lèi)屬性

    • self. 為實(shí)例屬性, 寫(xiě)在class中的為類(lèi)屬性
    • 相同名字的實(shí)例樹(shù)形將屏蔽類(lèi)屬性, 但是當(dāng)你刪除實(shí)例屬性后, 在使用相同的名稱(chēng), 訪問(wèn)到的將是類(lèi)屬性
    • 同名屬性實(shí)例屬性?xún)?yōu)先級(jí)高
    • 刪除 屬性

      del ss.name

  • 面向?qū)ο蟾呒?jí) 多重繼承, 定制類(lèi), 元類(lèi)

  • 可動(dòng)態(tài)綁定方法, 為實(shí)例綁定方法 instance

    from types import MethodType
    s.set_age = MethodType(set_age, s)
    
  • 為了給所有實(shí)例綁定的方法, 可以給class綁定方法

    Student.set_score = set_score
    
  • 限制實(shí)例屬性

    class Student(object):
        __slots__ = ('name','age')
    
    • slots 定義的屬性只對(duì)當(dāng)前class的instance 起作用, 對(duì)集成的子類(lèi)是不起作用的
    • 子類(lèi)也定義__slots__, 這樣子類(lèi)實(shí)例可以定義的屬性就是自身的__slots__加上父類(lèi)的__slots__.
  • @property 對(duì)對(duì)象屬性, 便捷性和控制的解決方案

    • 為檢查參數(shù), 設(shè)置get, set方法, 屬性設(shè)為私有
    • 但調(diào)用方法又略顯復(fù)雜,沒(méi)有直接用屬性這么直接簡(jiǎn)單
    class Student(object):
    
      @property
      def score(self):
          return self._score
    
      @score.setter
      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
    
    • @property的實(shí)現(xiàn)比較復(fù)雜,我們先考察如何使用。把一個(gè)getter方法變成屬性,只需要加上@property就可以了,此時(shí),@property本身又創(chuàng)建了另一個(gè)裝飾器@score.setter,負(fù)責(zé)把一個(gè)setter方法變成屬性賦值,于是,我們就擁有一個(gè)可控的屬性操作
    >>> 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!
    
  • 多重繼承 MixIn

    • class Dog(Mammal, Runnable):
    • 由于Python允許使用多重繼承,因此,MixIn就是一種常見(jiàn)的設(shè)計(jì)。只允許單一繼承的語(yǔ)言(如Java)不能使用MixIn的設(shè)計(jì)
    • 多繼承的好處在于不需要復(fù)雜而龐大的繼承鏈, 只要選擇組合不同的類(lèi)的功能, 就可以快速構(gòu)造出所需的子類(lèi)
    • 多繼承, 順序C3算法, MRO算法計(jì)算優(yōu)先級(jí)序列
    • 本地優(yōu)先級(jí): 指生命父類(lèi)的順序, 比如C(A,B), 如果訪問(wèn)C類(lèi)對(duì)象屬性時(shí), 應(yīng)該根據(jù)聲明順序, 優(yōu)先查找A類(lèi), 然后再查找B類(lèi).
    • 單調(diào)性: 如果在C的解析順序中, A排在B的前面, 那么在C的所有子類(lèi)里, 也必須滿(mǎn)足這個(gè)順序
    • 如果繼承至多個(gè)基類(lèi) class B(A1,A2,A3 ...), 這時(shí)B的mro序列 mro(B) = [B] + merge(mro(A1), mro(A2), mro(A3) ..., [A1,A2,A3])
    • merge操作就是C3算法的核心。遍歷執(zhí)行merge操作的序列,如果一個(gè)序列的第一個(gè)元素,在其他序列中也是第一個(gè)元素,或不在其他序列出現(xiàn),則從所有執(zhí)行merge操作序列中刪除這個(gè)元素,合并到當(dāng)前的mro中。merge操作后的序列,繼續(xù)執(zhí)行merge操作,直到merge操作的序列為空。如果merge操作的序列無(wú)法為空,則說(shuō)明不合法。
      -[E]+ merge([A,D,O],[B,O],[C,D,O],[D,O],[A,B,C,D]) = [E,A,B,C,D]
    • 定制類(lèi)
      • __str__ , 相當(dāng)于java, toString print時(shí) 打印自己定制的信息
      • __repr__ , 直接敲變量不用print,還是不好看, 這是因?yàn)橹苯语@示變量對(duì)用的不是__str__返回用戶(hù)看到的字符串, 而__repr__ 返回程序開(kāi)發(fā)者看到的字符串, 就是說(shuō), __repr__()是為調(diào)試服務(wù)的
      • __iter__ , __next__如果一個(gè)類(lèi)想被用于for ... in循環(huán),類(lèi)似list或tuple那樣,就必須實(shí)現(xiàn)一個(gè)iter()方法,該方法返回一個(gè)迭代對(duì)象,然后,Python的for循環(huán)就會(huì)不斷調(diào)用該迭代對(duì)象的next()方法拿到循環(huán)的下一個(gè)值,直到遇到StopIteration錯(cuò)誤時(shí)退出循環(huán)。
        class Fib(object):
              def __init__(self):
                  self.a, self.b = 0,1
        
              def __iter__(self):
                  return self # 實(shí)例對(duì)象本身就是迭代對(duì)象
        
              def __next__(self):
                  self.a, self.b = self.b, self.a +self.b
                  if self.a >100000:
                      raise StopIteration()
                  return self.a
        
      • __getitem__ 要表現(xiàn)的像list那樣下標(biāo)去除元素, 需要 實(shí)現(xiàn) __getitem__() def __getitem__方法 (self, n):
      • 切片功能list[1:4:2], 是指?jìng)魅雲(yún)?shù)可能為int值, 也可能為slice對(duì)象
      • __setitem__ 方法, 把對(duì)象視為list或dict來(lái)對(duì)集合賦值,
      • __delitem__方法, 用于刪除某個(gè)元素.
      • 通過(guò)上述定制方法, 我買(mǎi)的自己定義的類(lèi)表現(xiàn)的和Python自帶的list,tuple,dict沒(méi)什么分別, 這完全歸功與動(dòng)態(tài)語(yǔ)言的"鴨子類(lèi)型", 不需要強(qiáng)制集成那個(gè)接口
      • __getattr__ 當(dāng)調(diào)用不存在的屬性時(shí),比如score,Python解釋器會(huì)試圖調(diào)用getattr(self, 'score')來(lái)嘗試獲得屬性,這樣,我們就有機(jī)會(huì)返回score的值,返回函數(shù)也是完全可以的:注意,只有在沒(méi)有找到屬性的情況下,才調(diào)用getattr,已有的屬性,比如name,不會(huì)在getattr中查找。此外,注意到任意調(diào)用如s.abc都會(huì)返回None,這是因?yàn)槲覀兌x的getattr默認(rèn)返回就是None。要讓class只響應(yīng)特定的幾個(gè)屬性,我們就要按照約定,拋出AttributeError的錯(cuò)誤:
      • __call__() 任何類(lèi), 只需要定義一個(gè)__call__()方法, 就可以直接再實(shí)例本身調(diào)用, __call__()還可以定義函數(shù), 對(duì)實(shí)例進(jìn)行直接調(diào)用就好比對(duì)一個(gè)函數(shù)調(diào)用一樣, 所以你完全可以把對(duì)象堪稱(chēng)函數(shù), 把函數(shù)漢城對(duì)象, 因?yàn)閮烧咧g本沒(méi)有根本區(qū)別. 那么, 怎么判斷一個(gè)變量是對(duì)象還是函數(shù)? 其實(shí), 更多的時(shí)候, 我買(mǎi)的需要判斷一個(gè)對(duì)象是否能被調(diào)用, 能被調(diào)用的就是一個(gè)Callable對(duì)象, 比如函數(shù)和我買(mǎi)的上面定義的帶有__call__ 的類(lèi)實(shí)例
    • 枚舉類(lèi)
      • 定義 , value屬性則是自動(dòng)賦予成員變量的int常量, 默認(rèn)從1 開(kāi)始計(jì)數(shù)
        from enum import Enum
        Month = Enum('Month', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))
        
      • 這樣我們就獲得了Month類(lèi)型的枚舉類(lèi), 可以直接使用Month.Jan 來(lái)引用一個(gè)變量, 或者枚舉他的所有成員
          for name, member in Month.__members__.items():
              print(name, '=>' , member, ',', member.value)
        
      • 精確定義, 如果需要更精確的控制枚舉類(lèi)型, 可以從Enum派生自定義類(lèi)
      • py文件名不能有數(shù)字
  • 調(diào)試

    • 調(diào)試的方式:
      1. 用print()把可能有問(wèn)題的變量打印出來(lái)看看
      2. 使用assert(斷言)
      3. 使用logging(日志),logging不會(huì)拋出錯(cuò)誤,而且可以輸出到文件。
      4. pdb(Python的調(diào)試器),讓程序以單步的方式運(yùn)行
      5. pdb.set_trace()
      6. IDE打斷點(diǎn)
  • idea 開(kāi)發(fā)

    • 安裝python plugin
    • new project create virtual env
  • 文檔調(diào)試

    • 將運(yùn)行結(jié)果寫(xiě)在文檔注釋中, 更直接, 需要用doctest組件
        def abs(n):
            '''
            Function to get absolute value of number.
      
            Example:
      
            >>> abs(1)
            1         
            >>> abs(-1)
            1
            >>> abs(0)
            0
            '''
            return n if n >= 0 else (-n)
        if __name__=='__main__':
          import doctest
          doctest.testmod()
      
      • 文檔注釋的測(cè)試方式,無(wú)疑更明確地告訴函數(shù)的調(diào)用者該函數(shù)的期望輸入和輸出。并且,Python內(nèi)置的“文檔測(cè)試”(doctest)模塊可以直接提取注釋中的代碼并執(zhí)行測(cè)試。doctest嚴(yán)格按照Python交互式命令行的輸入和輸出來(lái)判斷測(cè)試結(jié)果是否正確。只有測(cè)試異常的時(shí)候,可以用...表示中間一大段煩人的輸出。
      • doctest非常有用,不但可以用來(lái)測(cè)試,還可以直接作為示例代碼。通過(guò)某些文檔生成工具,就可以自動(dòng)把包含doctest的注釋提取出來(lái)。用戶(hù)看文檔的時(shí)候,同時(shí)也看到了doctest。
  • IO編程

    • IO在計(jì)算機(jī)中指Input/Output,也就是輸入和輸出。由于程序和運(yùn)行時(shí)數(shù)據(jù)是在內(nèi)存中駐留,由CPU這個(gè)超快的計(jì)算核心來(lái)執(zhí)行,涉及到數(shù)據(jù)交換的地方,通常是磁盤(pán)、網(wǎng)絡(luò)等,就需要IO接口。
    • 很明顯,使用異步IO來(lái)編寫(xiě)程序性能會(huì)遠(yuǎn)遠(yuǎn)高于同步IO,但是異步IO的缺點(diǎn)是編程模型復(fù)雜。想想看,你得知道什么時(shí)候通知你“漢堡做好了”,而通知你的方法也各不相同。如果是服務(wù)員跑過(guò)來(lái)找到你,這是回調(diào)模式,如果服務(wù)員發(fā)短信通知你,你就得不停地檢查手機(jī),這是輪詢(xún)模式。總之,異步IO的復(fù)雜度遠(yuǎn)遠(yuǎn)高于同步IO。
    • 操作IO的能力都是由操作系統(tǒng)提供的,每一種編程語(yǔ)言都會(huì)把操作系統(tǒng)提供的低級(jí)C接口封裝起來(lái)方便使用,Python也不例外。我們后面會(huì)詳細(xì)討論P(yáng)ython的IO編程接口。
  • 文件讀寫(xiě)

    • 讀文件, 使用Python內(nèi)置open()函數(shù), 傳入文件名和標(biāo)示符:
        f = open('./test.txt','r')
        f.read()
      
    • 前邊講的默認(rèn)都是讀取文本文件, 并且是UTF-8編碼的文本文件, 要讀取二進(jìn)制文件,比如圖片, 視頻等等, 用'rb'模式打開(kāi)文件即可:
    • 要讀取非UTF-8編碼的文本文件, 需要給open()函數(shù)傳入enconding參數(shù), 例如讀取GBK編碼的文件:
          f = open('/Users/michael/test.txt','r', encoding='gbk', errors='ignore')
      
    • IO操作需要調(diào)用close()方法關(guān)閉文件, 文件使用完畢后必須關(guān)閉, 因?yàn)槲募?duì)象繪制用操作系統(tǒng)的資源, 并且操作系統(tǒng)同一時(shí)間能打開(kāi)的文件數(shù)量也是有限的, 文件讀寫(xiě)易產(chǎn)生IOError, 一旦出錯(cuò), 后面的f.close()就不會(huì)調(diào)用, 所以為保證無(wú)論是否錯(cuò)誤都能正確的關(guān)閉文件, 我們可以使用 try ... finally來(lái)實(shí)現(xiàn)
        try:
            f = open('/path/to/file', 'r')
            print(f.read())
        finally:
            if f:
                f.close()
      
    • 這樣寫(xiě)太繁瑣, 所以, Python引入了with語(yǔ)句來(lái)自動(dòng)幫我們調(diào)用close()方法:
          with open('/path/to/file','r') as f:
              print(f.read())
      
    • 調(diào)用read()會(huì)一次性讀取文件的全部?jī)?nèi)容,如果文件有10G,內(nèi)存就爆了,所以,要保險(xiǎn)起見(jià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()最方便:
    • file-like object: 像open()函數(shù)返回的這種有個(gè)read()方法的對(duì)象, 在Python中統(tǒng)稱(chēng)為file-like Object. 出了file外, 還可以是內(nèi)存的字節(jié)流, 網(wǎng)絡(luò)流, 自定義流等等. file-like Object不要求從特定類(lèi)繼承, 只要寫(xiě)個(gè)read()方法就行.
      • StringIO就是在內(nèi)存中創(chuàng)建的file-like Object, 常用作臨時(shí)緩沖.
    • 寫(xiě)文件: 寫(xiě)文件和讀文件是一樣的, 唯一區(qū)別是調(diào)用open()函數(shù)時(shí), 傳入標(biāo)識(shí)符'w'或者'wb'表示寫(xiě)文本文件或?qū)懚M(jìn)制文件:
        f = open('/Users/michael/test.txt','w')
        f.write('Hello, world')
        f.close()
      
  • StringIO和BytesIO: StringIO和BytesIO是在內(nèi)存中操作str和bytes的方法,使得和讀寫(xiě)文件具有一致的接口。

        from io import BytesIO
        fff = BytesIO()
        fff.write('中文ss'.encode('utf-8'))
        print(fff.getvalue())
    
      from io import StringIO
      f = StringIO('   Hello!   \nHi!\nGoodbye!')
      while True:
          s = f.readline()
          if s == '':
              break
          print(s.strip())
    
  • 操作文件和目錄

    import os

    • os.name # 操作系統(tǒng)類(lèi)型 posix ,說(shuō)明為L(zhǎng)inux, Unit 或 Mac OS X, 如果是 nt, 就是windows系統(tǒng), 詳細(xì)信息用os.uname函數(shù), window函數(shù)Windows上不提供, os模塊的某些函數(shù)是跟操作系統(tǒng)相關(guān)的.
    • 環(huán)境變量: os.environ, 過(guò)去某個(gè)環(huán)境變量的值, 可以調(diào)用os.envirsion.get('key')
          os.path.abspath('.') # 查看當(dāng)前目錄的絕對(duì)路徑
          os.path.join(os.path.abspath('.'),'testdir') # 把兩個(gè)路徑拼接,不直接拼字符串, 而是通過(guò) os.path.join()函數(shù), 這樣可以正確處理不同操作系統(tǒng)的路徑分隔符Linux/Unix/Mac '/' windows '\'
          os.path.split(os.path.abspath('.')) # 同樣的道理,要拆分路徑時(shí),也不要直接去拆字符串,而要通過(guò)os.path.split()函數(shù),這樣可以把一個(gè)路徑拆分為兩部分,后一部分總是最后級(jí)別的目錄或文件名:
          os.makedir(os.path.join(os.path.abspath('.'),'testdir')) # 創(chuàng)建目錄
          os.rmdir(os.path.join(os.path.abspath('.'),'testdir')) #刪除一個(gè)目錄
          os.path.splitext() # 可以直接讓你得到文件擴(kuò)展名, 很多時(shí)候非常方便
          os.rename('test.txt','test.py') # 對(duì)文件重命名
          os.remove('test.py') # 刪掉文件
      
      • 文件賦值可以通過(guò)shutil模塊的copyfile()函數(shù), shutil中海油很多使用函數(shù), 可以叫做os模塊的補(bǔ)充
      • 列出當(dāng)前目錄下的所有目錄
          [x for x in os.listdir('.') if os.path.isdir(x)]
        
      • 列出當(dāng)前目錄下的所有.py文件
          [x for x in os.listdir('.') if os.path.isfile(x) and os.path.splitext(x)[1] == '.py']
        
      • Python的os模塊封裝了操作系統(tǒng)的目錄和文件操作,要注意這些函數(shù)有的在os模塊中,有的在os.path模塊中。
  • 序列化: 將數(shù)據(jù)從內(nèi)存變成可存儲(chǔ)或傳輸?shù)倪^(guò)程稱(chēng)為序列化, 在Python中成為pickling, 在其他語(yǔ)言中稱(chēng)為serialization, marshalling, flattening, 都是一個(gè)意思.

    • 獲取序列化數(shù)據(jù):
        import pickle
        d = dict(name='Bob', age=20, score=88)
        pickle.dumps(d)
      
    • 將序列化數(shù)據(jù)寫(xiě)入文件:
        f = open('dump.txt','rb')
        d = pickle.dump(d,f)
        f.close()
      
    • 將對(duì)象從磁盤(pán)讀到內(nèi)存時(shí), 可以先將內(nèi)容讀到一個(gè)bytes, 然后用pickle.loads()方法反序列化出對(duì)象, 也可以直接pickle.load()方法從一個(gè)file-like Object中直接反序列化出對(duì)象
          f = open('dump.txt','rb')
          d = pickle.load(f)
          f.close()
          d
      
    • Pickle的問(wèn)題和其他編程語(yǔ)言的反序列化問(wèn)題一樣, 就是他只能用于Python, 并且可能不同版本的Python彼此都不兼容, 因此, 只能用Pickle保存那些不重要的數(shù)據(jù), 不能充公的反序列化也沒(méi)關(guān)系
    • 為傳遞對(duì)象, 可以用JSON作為標(biāo)準(zhǔn)存儲(chǔ)格式
        import json
        fff = open('dump.txt','w')
        d = dict(name='Bob', age=20, score=88)
        json.dumps(d) # '{"age": 20, "score": 88, "name": "Bob"}'
        json.dump(d,fff) # 類(lèi)似的,dump()方法可以直接把JSON寫(xiě)入一個(gè)file-like Object。
        json_str = '{"age": 20, "score": 88, "name": "Bob"}'
        json.loads(json_str)
        json.load(open('dump.txt','r').read())
      
    • 對(duì)象的序列化和反序列化通過(guò)dict進(jìn)行轉(zhuǎn)換
          def student2dict(std):
              return{
                'name': std.name,
                'age': std.age,
                'score': std.score
              }
        json.dumps(s, default=student2dict) # 對(duì)象的序列化
        json.dumps(s, default=lambda obj: obj.__dict__)
      
          def dict2student(d):
              return Student(d['name'], d['age'], d['score'])
          print(json.loads(json_str, object_hook=dict2student)) #<__main__.Student object at 0x10cd3c190> 打印出反序列化的Student實(shí)例對(duì)象
      
    • Python語(yǔ)言特定的序列化模塊是pickle,但如果要把序列化搞得更通用、更符合Web標(biāo)準(zhǔn),就可以使用json模塊。json模塊的dumps()和loads()函數(shù)是定義得非常好的接口的典范。當(dāng)我們使用時(shí),只需要傳入一個(gè)必須的參數(shù)。但是,當(dāng)默認(rèn)的序列化或反序列機(jī)制不滿(mǎn)足我們的要求時(shí),我們又可以傳入更多的參數(shù)來(lái)定制序列化或反序列化的規(guī)則,既做到了接口簡(jiǎn)單易用,又做到了充分的擴(kuò)展性和靈活性。
  • 進(jìn)程和線(xiàn)程:線(xiàn)程是最小的執(zhí)行單元,而進(jìn)程由至少一個(gè)線(xiàn)程組成。如何調(diào)度進(jìn)程和線(xiàn)程,完全由操作系統(tǒng)決定,程序自己不能決定什么時(shí)候執(zhí)行,執(zhí)行多長(zhǎng)時(shí)間。多進(jìn)程和多線(xiàn)程的程序涉及到同步、數(shù)據(jù)共享的問(wèn)題,編寫(xiě)起來(lái)更復(fù)雜。

  • process: 在Unix/Linux下,可以使用fork()調(diào)用實(shí)現(xiàn)多進(jìn)程。要實(shí)現(xiàn)跨平臺(tái)的多進(jìn)程,可以使用multiprocessing模塊。進(jìn)程間通信是通過(guò)Queue、Pipes等實(shí)現(xiàn)的。

  • Thread, 多線(xiàn)程編程, 模型復(fù)雜, 容易發(fā)生沖突, 必須用鎖加以隔離, 同時(shí), 又要小心死鎖的發(fā)生, Python解釋器由于設(shè)計(jì)時(shí)有GIL全局鎖, 導(dǎo)致了多線(xiàn)程無(wú)法利用多核, 多線(xiàn)程的并發(fā)在Python 就是一個(gè)美麗的夢(mèng).

  • ThreadLocal對(duì)象:一個(gè)ThreadLocal變量雖然是全局變量,但每個(gè)線(xiàn)程都只能讀寫(xiě)自己線(xiàn)程的獨(dú)立副本,互不干擾。ThreadLocal解決了參數(shù)在一個(gè)線(xiàn)程中各個(gè)函數(shù)之間互相傳遞的問(wèn)題。

    • 全局變量local_school就是一個(gè)ThreadLocal對(duì)象,每個(gè)Thread對(duì)它都可以讀寫(xiě)student屬性,但互不影響。你可以把local_school看成全局變量,但每個(gè)屬性如local_school.student都是線(xiàn)程的局部變量,可以任意讀寫(xiě)而互不干擾,也不用管理鎖的問(wèn)題,ThreadLocal內(nèi)部會(huì)處理。可以理解為全局變量local_school是一個(gè)dict,不但可以用local_school.student,還可以綁定其他變量,如local_school.teacher等等。ThreadLocal最常用的地方就是為每個(gè)線(xiàn)程綁定一個(gè)數(shù)據(jù)庫(kù)連接,HTTP請(qǐng)求,用戶(hù)身份信息等,這樣一個(gè)線(xiàn)程的所有調(diào)用到的處理函數(shù)都可以非常方便地訪問(wèn)這些資源。
  • 多進(jìn)程vs多線(xiàn)程

    • 多進(jìn)程穩(wěn)定性高, 多線(xiàn)程易崩潰
    • 計(jì)算密集型任務(wù)適合單任務(wù), 代碼運(yùn)行效率高, c語(yǔ)言; IO密集型適合多任務(wù), CPU等待IO操作
    • 異步IO:考慮到CPU和IO之間巨大的速度差異,一個(gè)任務(wù)在執(zhí)行的過(guò)程中大部分時(shí)間都在等待IO操作,單進(jìn)程單線(xiàn)程模型會(huì)導(dǎo)致別的任務(wù)無(wú)法并行執(zhí)行,因此,我們才需要多進(jìn)程模型或者多線(xiàn)程模型來(lái)支持多任務(wù)并發(fā)執(zhí)行。現(xiàn)代操作系統(tǒng)對(duì)IO操作已經(jīng)做了巨大的改進(jìn),最大的特點(diǎn)就是支持異步IO。如果充分利用操作系統(tǒng)提供的異步IO支持,就可以用單進(jìn)程單線(xiàn)程模型來(lái)執(zhí)行多任務(wù),這種全新的模型稱(chēng)為事件驅(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編程模型來(lái)實(shí)現(xiàn)多任務(wù)是一個(gè)主要的趨勢(shì)。對(duì)應(yīng)到Python語(yǔ)言,單線(xiàn)程的異步編程模型稱(chēng)為協(xié)程,有了協(xié)程的支持,就可以基于事件驅(qū)動(dòng)編寫(xiě)高效的多任務(wù)程序。我們會(huì)在后面討論如何編寫(xiě)協(xié)程。
  • 正則模塊

    • 使用
        import re
        re.match(r'^\d{3}\-\d{3,8}$', '010-12345') # 匹配成功返回Match對(duì)象, 否則返回None
      
        test = '用戶(hù)輸入的字符串'
        if re.match(r'正則表達(dá)式', test):
            print('ok')
        else:
            print('failed')
      
    • 可用來(lái)切割字符串
        re.split(r'\s+', 'a b   c')
        # ['a','b','c']
        re.split(r'[\s\,]+', 'a,b,  c, d')
        #['a','b','c','d'], 可以用正則表達(dá)式來(lái)把不貴但的輸入轉(zhuǎn)化為正確的數(shù)組.
      
    • 分組: 除了簡(jiǎn)單地判斷是否匹配之外,正則表達(dá)式還有提取子串的強(qiáng)大功能。用()表示的就是要提取的分組(Group)
        m = re.match(r'^(\d{3})-(\d{3,8})$', '010-12345')
        # <_sre.SRE_Match object; span=(0, 9), match='010-12345'>
        # 如果正則表達(dá)式定義了組, 就可以再M(fèi)atch對(duì)象上用group()方法提取出字串來(lái).
        m.group(0)
        # '010-12345'
        m.group(1)
        # '010'
        m.group(2)
        # '12345'
      
    • 當(dāng)時(shí)在Python中使用正則表達(dá)式, re模塊內(nèi)部會(huì)干兩件事:
      • 編譯正則表達(dá)式, 如果正則表達(dá)式字符串本身不合法, 后報(bào)錯(cuò);
      • 用編譯后的正則表達(dá)式去匹配字符串.
      • 如果一個(gè)正則要重復(fù)使用幾千次, 出于效率考慮, 我們可以預(yù)編譯該正則表達(dá)式, 接下來(lái)就不需要編譯這個(gè)步驟了, 直接匹配:
          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')
        
  • datetime

    • 當(dāng)前時(shí)間的獲取: now= datetime.now()
    • 獲取指定日期和時(shí)間, 我們可以直接用參數(shù)構(gòu)建一個(gè)datetime: dt = datetime(2017,11,29,17,27)
    • timestamp對(duì)象
      • 在計(jì)算機(jī)中,時(shí)間實(shí)際上是用數(shù)字表示的。我們把1970年1月1日 00:00:00 UTC+00:00時(shí)區(qū)的時(shí)刻稱(chēng)為epoch time,記為0(1970年以前的時(shí)間timestamp為負(fù)數(shù)),當(dāng)前時(shí)間就是相對(duì)于epoch time的秒數(shù),稱(chēng)為timestamp。
        • timestamp = 0 = 1970-1-1 00:00:00 UTC+0:00
        • 北京 timestamp = 0 = 1970-1-1 08:00:00 UTC+8:00
      • 可見(jiàn)timestamp的值與時(shí)區(qū)毫無(wú)關(guān)系,因?yàn)閠imestamp一旦確定,其UTC時(shí)間就確定了,轉(zhuǎn)換到任意時(shí)區(qū)的時(shí)間也是完全確定的,這就是為什么計(jì)算機(jī)存儲(chǔ)的當(dāng)前時(shí)間是以timestamp表示的,因?yàn)槿蚋鞯氐挠?jì)算機(jī)在任意時(shí)刻的timestamp都是完全相同的(假定時(shí)間已校準(zhǔn)).
      • 轉(zhuǎn)換
          from datetime import datetime
          dt = datetime(2017,11,29,20)
          dt.timestamp()
        
  • collections: collections是Python內(nèi)建的一個(gè)集合模塊,提供了許多有用的集合類(lèi)

    • namedtuple: namedtuple是一個(gè)函數(shù),它用來(lái)創(chuàng)建一個(gè)自定義的tuple對(duì)象,并且規(guī)定了tuple元素的個(gè)數(shù),并可以用屬性而不是索引來(lái)引用tuple的某個(gè)元素
    • deque:deque 是為了高效實(shí)現(xiàn)插入和刪除操作的雙向列表,適合用于隊(duì)列和棧。可以再首或者尾進(jìn)行刪除和插入
    • defaultdict: 使用dict時(shí),如果引用的Key不存在,就會(huì)拋出KeyError。如果希望key不存在時(shí),返回一個(gè)默認(rèn)值,就可以用defaultdict
    • OrderedDict: 可以保證key的順序
  • base64: Base64是一種任意二進(jìn)制到文本字符串的編碼方法,常用于在URL、Cookie、網(wǎng)頁(yè)中傳輸少量二進(jìn)制數(shù)據(jù)。

    import base64
    
    print(base64.b64encode(b'binary\x00string'))
    # 如果要編碼的二進(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)去掉。
    print(base64.b64decode(b'YmluYXJ5AHN0cmluZw=='))
    
    # 由于標(biāo)準(zhǔn)的Base64編碼后可能出現(xiàn)字符+和/,在URL中就不能直接作為參數(shù),所以又有一種"url safe"的base64編碼,其實(shí)就是把字符+和/分別變成-和_:
    print(base64.urlsafe_b64decode(b'i\xb7\x1d\xef\xff'))
    
    # 由于=字符也可能出現(xiàn)在Base64編碼中,但=用在URL、Cookie里面會(huì)造成歧義,所以,很多Base64編碼后會(huì)把=去掉
    # 去掉=后怎么解碼呢?因?yàn)锽ase64是把3個(gè)字節(jié)變?yōu)?個(gè)字節(jié),所以,Base64編碼的長(zhǎng)度永遠(yuǎn)是4的倍數(shù),因此,需要加上=把Base64字符串的長(zhǎng)度變?yōu)?的倍數(shù),就可以正常解碼了。
    
  • hashlib: 摘要算法在很多地方都有廣泛的應(yīng)用。要注意摘要算法不是加密算法,不能用于加密(因?yàn)闊o(wú)法通過(guò)摘要反推明文),只能用于防篡改,但是它的單向計(jì)算特性決定了可以在不存儲(chǔ)明文口令的情況下驗(yàn)證用戶(hù)口令。

    import hashlib
    md5 = hashlib.md5()
    md5.update('how to use md5 in python hashlib?'.encode('utf-8'))
    print(md5.hexdigest())
    
    # 如果數(shù)據(jù)量很大, 可以分塊多次調(diào)用update(), 最后計(jì)算結(jié)果一樣
    md5_2 = hashlib.md5()
    md5_2.update('how to use md5 in '.encode('utf-8'))
    md5_2.update('python hashlib?'.encode('utf-8'))
    print(md5_2.hexdigest())
    
    
  • hmac:Python內(nèi)置的hmac模塊實(shí)現(xiàn)了標(biāo)準(zhǔn)的Hmac算法,它利用一個(gè)key對(duì)message計(jì)算“雜湊”后的hash,使用hmac算法比標(biāo)準(zhǔn)hash算法更安全,因?yàn)獒槍?duì)相同的message,不同的key會(huì)產(chǎn)生不同的hash。(加鹽)

  • itertools: itertools模塊提供的全部是處理迭代功能的函數(shù),它們的返回值不是list,而是Iterator,只有用for循環(huán)迭代的時(shí)候才真正計(jì)算。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,797評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,179評(píng)論 3 414
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 175,628評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 62,642評(píng)論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,444評(píng)論 6 405
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 54,948評(píng)論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,040評(píng)論 3 440
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,185評(píng)論 0 287
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,717評(píng)論 1 333
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,602評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,794評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,316評(píng)論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,045評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,418評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 35,671評(píng)論 1 281
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,414評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,750評(píng)論 2 370