寫給自己的python基礎

poqweur發表於2020-11-30

建議剛開始學習直接使用ANACONDA

++https://www.anaconda.com/download/++

配置python環境變數
https://docs.python.org/3.6/using/cmdline.html#envvar-PYTHONMALLOC

++Python PEP8導包順序++

  1. Python標準庫
  2. Python第三方模組
  3. 應用程式自定義模組
    然後使用一個空行分割這三類模組的匯入語句,這將確保模組使用固定的習慣匯入, 有助於減少每個模組需要的 import 語句數目。
  4. python中0,"",None都等於False

生成隨機字元,可用於加密key 金鑰

import os,base64
base64.b64encode(os.urandom(20))
# python的包命令
pip install xxx
pip uninstall xxx
pip install upgrade xxx
# anaconda提供包命令
conda install xxx
conda uninstall xxx
conda update xxx
Python頭資訊
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author: YourName
python2設定編碼格式
# 設定直譯器編碼格式
import sys
reload(sys)
sys.setdefaultencoding('utf8')


# python對接oracle時設定系統變數
os.environ["NLS_LANG"]="SIMPLIFIED CHINESE_CHINA.UTF8"

安裝python的虛擬環境

安裝virtualenvwrapper

使得virtualenv變得更好用,所以我們一起安裝了

# 安裝:
(sudo) pip install virtualenv virtualenvwrapper
# 修改~/.bash_profile或其它環境變數相關檔案(如 .bashrc 或用 ZSH 之後的 .zshrc),新增以下語句

export WORKON_HOME=$HOME/.virtualenvs
export PROJECT_HOME=$HOME/workspace
source /usr/local/bin/virtualenvwrapper.sh
# 修改後使之立即生效(也可以重啟終端使之生效):

source ~/.bash_profile

andexecnot
assertfinallyor
breakforpass
classfromprint
continueglobalraise
defifreturn
delimporttry
elifinwhile
elseiswith
exceptlambdayield

pip常用命令

  1. pip freeze or pip list 列出已安裝的包
  2. pip freeze > <目錄>/requirements.txt 匯出requirements.txt
  3. pip install <包名> 或 pip install -r requirements.txt 線上安裝
  4. pip install --no-index -f=<目錄>/ <包名> 安裝本地安裝包
  5. pip uninstall <包名> 或 pip uninstall -r requirements.txt 解除安裝包
  6. pip install -U <包名> 或:pip install <包名> --upgrade 升級包
  7. pip install -U pip 升級pip
  8. pip show -f <包名> 顯示包所在的目錄
  9. pip search <搜尋關鍵字> 搜尋包
  10. pip list -o 查詢可升級的包
  11. pip install <包名> -d <目錄> 或 pip install -d <目錄> -r requirements.txt 下載包而不安裝
  12. pip wheel <包名> 打包
更換國內pypi映象
國內pypi映象

    阿里:https://mirrors.aliyun.com/pypi/simple
    豆瓣:http://pypi.douban.com/simple
    中國科學技術大學:http://pypi.mirrors.ustc.edu.cn/simple/

指定單次安裝源

pip install <包名> -i http://pypi.v2ex.com/simple
指定全域性安裝源

在unix和macos,配置檔案為:$HOME/.pip/pip.conf
在windows上,配置檔案為:%HOME%\pip\pip.ini

[global]
timeout = 6000
  index-url = http://pypi.douban.com/simple


Python核心

python中的資料型別有:

  • Number(數字)

    • int(有符號的整形)
    • float(浮點型)
    • complex(複數)
  • Bool(布林)

    • True
    • Flase
  • String(字串)

  • List(列表)

  • Tuple(元組)

  • Dictionary(字典)

    小整數池範圍-5~256

知道駝峰命名法和關鍵字命名範圍
檢視關鍵字可以使用:

import keyword
keyword.kwlist

格式化輸出有:

佔位符輸出值
%c字元
%s通過str() 字串轉換來格式化
%i有符號十進位制整數
%d有符號十進位制整數
%u無符號十進位制整數
%o八進位制整數
%x十六進位制整數(小寫字母)
%X十六進位制整數(大寫字母)
%e科學計數法(小寫’e’)
%E科學計數法(大寫“E”)
%f浮點數
%g%f和%e 的簡寫
%G%f和%E的簡寫

常用的有%s、%f、%d

還有一種自動格式化填充format()

print('{}'.format('我們'))

"numbers: {:b},{:o},{:d},{:x},{:X}, {:%}".format(15, 15, 15, 15, 15, 15.87623, 2)

在Python3中輸出是print(),Python2中是print

在Python3中輸入使用input(),Python2中使用raw_input()

算數運算子描述例項
+兩個物件相加 a + b 輸出結果 30
-得到負數或是一個數減去另一個數 a - b 輸出結果 -10
*兩個數相乘或是返回一個被重複若干次的字串 a * b 輸出結果 200
/b / a 輸出結果 2
//取整除返回商的整數部分 9//2 輸出結果 4 , 9.0//2.0 輸出結果 4.0
%取餘返回除法的餘數 b % a 輸出結果 0
**指數a**b 為10的20次方, 輸出結果 100000000000000000000

賦值運算子描述例項
=賦值運算子把=號右邊的結果給左邊的變數 num = 1 + 2 * 3,結果num的值為7

複合賦值運算子描述例項
+=加法賦值運算子c += a 等效於 c = c + a
-=減法賦值運算子c -= a 等效於 c = c - a
*=乘法賦值運算子c *= a 等效於 c = c * a
/=除法賦值運算子c /= a 等效於 c = c / a
%=取模賦值運算子c %= a 等效於 c = c % a
**=冪賦值運算子c **= a 等效於 c = c ** a
//=取整除賦值運算子c //= a 等效於 c = c // a

常用的資料型別轉換
函式說明
int(x [,base ])將x轉換為一個整數
float(x )將x轉換為一個浮點數
complex(real [,imag ])建立一個複數,real為實部,imag為虛部
str(x )將物件 x 轉換為字串
repr(x )將物件 x 轉換為表示式字串
eval(str )用來計算在字串中的有效Python表示式,並返回一個物件
tuple(s )將序列 s 轉換為一個元組
list(s )將序列 s 轉換為一個列表
chr(x )將一個整數轉換為一個Unicode字元
ord(x )將一個字元轉換為它的整數值
hex(x )將一個整數轉換為一個十六進位制字串
oct(x )將一個整數轉換為一個八進位制字串
bin(x )將一個整數轉換為一個二進位制字串

判斷語句

if 條件:
    todo
elif 條件:
    todo
else:
    todo

迴圈語句

while 條件:
    todoing
    
for i in 可迭代物件:
    i

break在迴圈中滿足條件退出迴圈
continue滿足條件跳過這一次迴圈,繼續後面的迴圈
如果什麼都不做可以使用pass來佔位


字串、元組、列表都可以做切片;
字串、元組、列表、字典都是可迭代物件

字串常見操作

string = ' hello world hello everybody '
# find,如果查詢的字串存在返回索引,否則返回-1
string.find(str,start=0,end=len(string)

# index,跟find方法一樣如果沒找到字串則會丟擲一個異常
string.index(str,start=0,end=len(string)

# count,在start與end之間,str出現的次數
string.count(str,start=0,end=len(string)

# replace,把str1替換成str2,如果指定count,則替換不會超過count次
string.replace(str1,str2,count)

# split,指定分割的符號,如果指定最大分割值,則僅分割最大值個數的字串(0是不分割,無引數則全分割)
string.split(str='',maxsplit)

# capitalize首字母大寫
string.capitalize()

# title,把字串的每個單詞首字母大寫
string.title()

# startswith,檢查字串是否是以指定字串開頭, 是則返回 True,否則返回 False
string.startswith(hello)

# endswith,檢查字串是否以指定字串結束,如果是返回True,否則返回 False
string.endswith(obj)

# lower,轉換 mystr 中所有大寫字元為小寫
string.lower()

# upper,轉換 mystr 中的小寫字母為大寫
string.upper() 

# ljust,返回一個原字串左對齊,並使用空格填充至長度 width 的新字串
string.ljust(width) 

# rjust,返回一個原字串右對齊,並使用空格填充至長度 width 的新字串
string.rjust(width)    

# center,返回一個原字串居中,並使用空格填充至長度 width 的新字串
string..center(width)

# lstrip,刪除 mystr 左邊的空白字元
string.lstrip()

# rstrip,刪除 mystr 字串末尾的空白字元
string.rstrip()    

# strip,刪除mystr字串兩端的空白字元
string.strip()

# rfind,類似於 find()函式,不過是從右邊開始查詢
string.rfind(str, start=0,end=len(mystr))

# rindex,類似於 index(),不過是從右邊開始.
string.rindex( str, start=0,end=len(mystr))

# partition,把mystr以str分割成三部分,str前,str和str後
string.partition(str)

# rpartition,類似於 partition()函式,不過是從右邊開始
string.rpartition(str)

# splitlines,按照行分隔,返回一個包含各行作為元素的列表
string.splitlines()  

# isalpha,如果 mystr 所有字元都是字母 則返回 True,否則返回 False
string.isaplha()

# isdigit,如果 mystr 只包含數字則返回 True 否則返回 False
string.isdigit()

# isalnum,如果 mystr 所有字元都是字母或數字則返回 True,否則返回 False
string.isalnum()  

# isspace,如果 mystr 中只包含空格,則返回 True,否則返回 False
string.isspace()  

# join,mystr 中每個元素後面插入str,構造出一個新的字串
string.join(str)

列表

list1 = [1,2,3]
list2 = [7,8,9]
# append,向列表追加元素
list1.append(4)

# extend,將另一個集合中的元素逐一新增到列表中
list1.extend(list2)

# insert,(index, object) 在指定位置index前插入元素object
list1.insert(0,1)

# 修改元素可以通過指定下標重新賦值
list1[0]=5

# in, not in:
## in(存在),如果存在那麼結果為true,否則為false
## not in(不存在),如果不存在那麼結果為true,否則false
2 in list1
1 not in list1

# index, count:用法與字串相同
list1.index(2)
list1.count(1)

# del, pop, remove:刪除元素
## del:根據下標進行刪除
## pop:預設彈出最後一個元素,也可以指定下標
## remove:根據元素的值進行刪除
del list1[0]
list1.pop()
list1.remove(2)

# sort,排序,可以新增reverse=True引數設定倒序
list1.sort()

# reverse只逆置順序,不排序
list1.reverse()

# 列表推導式
[i for i in range(30) if i % 3 is 0]
# 生成器
(i for i in range(30) if i % 3 is 0)

元組

# Python的元組與列表類似,不同之處在於元組的元素不能修改。元組使用小括號,列表使用方括號。
# 訪問元素,可以拆包或者取下標
tuple = (1,2,3)
tuple[1]
x,y,z = tuple

# 元組的內建函式count, index
# index和count與字串和列表中的用法相同
tuple.count(1)
tuple.index(1)

字典

dict = {'id':1,'name':'張三'}
# 修改元素:字典的每個元素中的資料是可以修改的,只要通過key找到,即可修改
dict['name']='李四'

# 新增元素:**訪問不存在的元素會丟擲異常,如果在使用 變數名['鍵'] = 資料 時,這個“鍵”在字典中,不存在,那麼就會新增這個元素**
dict['age']=18

# update,新增多個元素
dict.update({'addr':'beijing','sex':'nan'})

# fromkeys,根據傳入的列表和值生成多個元素,所有元素的值都一樣
b=[1,2,3,4]
a={}
a=a.fromkeys(b,'666')

# setdefault(key,value),如果key存在獲取元素,如果不存在則新增元素
dict.setdefault('id')
dict.setdefault('addr','東北')

# get,獲取指定key的value,如果key不存在返回None
dict.get('學籍')

# 刪除元素:
## del:指定key刪除元素
## clear():刪除所有元素
del dict['age']
dict.clear()

# 彈出元素:
## pop:指定key彈出元素
## popitem:彈出最後一個元素
dict.pop('id')
dict.popitem()

# len,測量字典中,鍵值對的個數
len(dict)

# keys,返回一個包含字典所有KEY的列表
dict.keys()

# values,返回一個包含字典所有value的列表
dict.values()

# items,返回一個包含所有(鍵,值)元祖的列表
dict.items()

# enumerate()列舉,傳入字典返回(key,value),傳入字典返回(index,value)
# python2:has_key,dict.has_key(key)如果key在字典中,返回True,否則返回False

集合

set={1,2,3}
# add,新增元素
set.add(4)

# update,新增多個元素
set.update({4,5,6})

# pop,彈出第一個元素
set.pop()

# remove,刪除指定元素,如果元素不存在丟擲異常
set.remove(2)

# discard,刪除指定元素,元素不存在返回None
set.discard

---

set1={1,2,3}
set2={2,3,4}
# &,交集
set1 & set2

# |,並集
set1 | set2

# ^,對稱差集
set1 ^ set2

# -,差集
set1 - set2

公共方法

運算子Python 表示式結果描述支援的資料型別
+[1, 2] + [3, 4][1, 2, 3, 4]合併字串、列表、元組
*[‘Hi!’] * 4[‘Hi!’, ‘Hi!’, ‘Hi!’, ‘Hi!’]複製字串、列表、元組
in3 in (1, 2, 3)True元素是否存在字串、列表、元組、字典
not in4 not in (1, 2, 3)True元素是否不存在字串、列表、元組、字典

python內建函式

方法描述
cmp(item1, item2)python2 中cmp(item1, item2)比較值個大小 item1大返回1,item1小返回-1,相等返回0
len(item)計算容器中元素個數
max(item)返回容器中元素最大值
min(item)返回容器中元素最小值
del(item)刪除變數
type(item)返回物件型別
isinstance(item,type)傳入物件和型別返回True或False
reversed(item)返回倒置的物件需要轉換list或其他
enumerate(item)返回一個元組
zip(list,list)返回新的列表,需要傳入的列表每個元素一一對應
hash(obj)返回雜湊值
dict(item)建立字典或轉換成字典
list(item)建立列表或轉換成列表
tuple(tiem)轉換成元組
dir(obj)檢視函式有哪些方法
divmod(datasize, limte)全部資料,每頁幾條資料。返回元組(總頁數, 剩餘條數)
# python3中代替cmp的函式
import operator
operator.eq(a,b) # 是否相等
operator.lt(a,b) # a 小於 b
operator.gt(a,b) # a 大於 b
operator.le(a,b) # a 小等於 b
operator.ge(a,b) # a 大等於 b

函式內部定義的變數屬於區域性變數,在函式外定義的變數屬於全域性變數,在函式內優先呼叫區域性變數,如果想從函式內部修改全域性變數需要使用global關鍵字宣告

# 遞迴函式
def func(num):
    if num == 1:
        return num
    return func(num-1) + num

# 匿名函式
(lambda x:x+1)(2)
list1 = [{'a':1},{'a':2},{'a':3}]
list1.sort(key=lamdba x:x['a'])

抽象基類

ABC,Abstract Base Class(抽象基類),主要定義了基本類和最基本的抽象方法,可以為子類定義共有的API,不需要具體實現。相當於是Java中的介面或者是抽象類。
抽象基類可以不實現具體的方法(當然也可以實現,只不過子類如果想呼叫抽象基類中定義的方法需要使用super())而是將其留給派生類實現。

抽象基類提供了邏輯和實現解耦的能力,即在不同的模組中通過抽象基類來呼叫,可以用最精簡的方式展示出程式碼之間的邏輯關係,讓模組之間的依賴清晰簡單。同時,一個抽象類可以有多個實現,讓系統的運轉更加靈活。而針對抽象類的程式設計,讓每個人可以關注當前抽象類,只關注其方法和描述,而不需要考慮過多的其他邏輯,這對協同開發有很大意義。極簡版的抽象類實現,也讓程式碼可讀性更高。

抽象基類的使用:
1:直接繼承
    直接繼承抽象基類的子類就沒有這麼靈活,抽象基類中可以宣告”抽象方法“和“抽象屬性”,只有完全覆寫(實現)了抽象基類中的“抽象”內容後,才能被例項化,而虛擬子類則不受此影響。
2:虛擬子類
將其他的類”註冊“到抽象基類下當虛擬子類(呼叫register方法),虛擬子類的好處是你實現的第三方子類不需要直接繼承自基類,可以實現抽象基類中的部分API介面,也可以根本不實現,但是issubclass(), issubinstance()進行判斷時仍然返回真值。

Python 對於ABC的支援模組是abc模組,定義了一個特殊的metaclass:ABCMeta 還有一些裝飾器:@abstractmethod 和 @abstarctproperty 。abc.ABCMeta 用於在Python程式中建立抽象基類。而抽象基類如果想要宣告“抽象方法”,可以使用 @abstractmethod ,如果想宣告“抽象屬性”,可以使用 @abstractproperty 。

為了解決Python2&3的相容問題,需要引入six模組,該模組中有一個針對類的裝飾器 @six.add_metaclass(MetaClass) 可以為兩個版本的Python類方便地新增metaclass

通用做法。

@six.add_metaclass(MetaClass) >的作用是在不同版本的Python之間提供一個優雅的宣告類的metaclass的手段,事實上不用它也可以,只是使用了它程式碼更為整潔明瞭。

import six

@six.add_metaclass(Meta)
class MyClass(object):
    pass

在Python 3 等價於

import six

class MyClass(object, metaclass = Meta):
    pass

在Python 2.x (x >= 6)中等價於

import six

class MyClass(object):
    __metaclass__ = Meta
    pass

或者直接呼叫裝飾器,
這裡也能看出來裝飾器就是個方法包裝而已。

import six

class MyClass(object):
    pass
MyClass  = six.add_metaclass(Meta)(MyClass)
import abc
import six


@six.add_metaclass(abc.ABCMeta)
class BaseClass(object):
    @abc.abstractmethod
    def func_a(self, data):
        """
        an abstract method need to be implemented
        """

    @abc.abstractmethod
    def func_b(self, data):
        """
        another abstract method need to be implemented
        """

class SubclassImpl(BaseClass):
    def func_a(self, data):
        print("Overriding func_a, " + str(data))

    @staticmethod
    def func_d(self, data):
        print(type(self) + str(data))

class RegisteredImpl(object):
    @staticmethod
    def func_c(data):
        print("Method in third-party class, " + str(data))
BaseClass.register(RegisteredImpl)


if __name__ == '__main__':
    for subclass in BaseClass.__subclasses__():
        print("subclass of BaseClass: " + subclass.__name__)
    print("subclass do not contains RegisteredImpl")
    print("-----------------------------------------------")

    print("RegisteredImpl is subclass: " + str(issubclass(RegisteredImpl, BaseClass)))
    print("RegisteredImpl object  is instance: " + str(isinstance(RegisteredImpl(), BaseClass)))
    print("SubclassImpl is subclass: " + str(issubclass(SubclassImpl, BaseClass)))

    print("-----------------------------------------------")
    obj1 = RegisteredImpl()
    obj1.func_c("RegisteredImpl new object OK!")
    print("-----------------------------------------------")
    obj2 = SubclassImpl()  #由於沒有例項化所有的方法,所以這裡會報錯 Can't instantiate abstract class SubclassImpl with abstract methods func_b
    obj2.func_a("It's right!")
結果如下:
subclass of BaseClass: SubclassImpl
subclass do not contains RegisteredImpl
-----------------------------------------------
RegisteredImpl is subclass: True
RegisteredImpl object  is instance: True
SubclassImpl is subclass: True
-----------------------------------------------
Method in third-party class, RegisteredImpl new object OK!
-----------------------------------------------
Traceback (most recent call last):
  File "/Users/wangqi/Git/Python/scrapy_crawler_learn/test/ABCTest.py", line 51, in <module>
    obj2 = SubclassImpl()  #由於沒有例項化所有的方法,所以這裡會報錯 Can't instantiate abstract class SubclassImpl with abstract methods func_b
TypeError: Can't instantiate abstract class SubclassImpl with abstract methods func_b

三元操作符

x if x < y else y 

位運算

  • 按位與( bitwise and of x and y )

    • & 舉例: 5&3 = 1 解釋: 101 11 相同位僅為個位1 ,故結果為 1
  • 按位或( bitwise or of x and y )

    • | 舉例: 5|3 = 7 解釋: 101 11 出現1的位是 1 1 1,故結果為 111
  • 按位異或 ( bitwise exclusive or of x and y )

    • ^ 舉例: 5^3 = 6 解釋: 101 11 對位相加(不進位)是 1 1 0,故結果為 110
  • 按位反轉 (the bits of x inverted )

    • ~ 舉例: ~5 = -6 解釋: 將二進位制數+1之後乘以-1,即~x = -(x+1),-(101 + 1) = -110
  • 按位反轉 (the bits of x inverted )

    • ~ 舉例: ~5 = -6 解釋: 將二進位制數+1之後乘以-1,即~x = -(x+1),-(101 + 1) = -110
  • 按位左移 ( x shifted left by n bits )

    • << 舉例: 5<<2 = 20 解釋:101 向左移動2位得到 10100 ,即右面多出2位用0補
  • 按位右移 ( x shifted right by n bits )

    • 舉例: 5>>2 = 1 解釋:101 向右移動2位得到 1,即去掉右面的2位


檔案操作

# 建立檔案物件open
file = open(name,'w')

# 檔案讀操作
file.read(num) # 讀取所有位元組,引數是位元組

file.readline(num) # 只讀取一行,引數可以指定位元組
with open("filename") as fh:
    line = fh.readline()
    while line:
        print(line.strip())
        line = fh.readline()
        
file.readlines() # 讀取所有行,返回列表

# 檔案寫操作
file.write(str) # 傳入字串寫入檔案
file.writelines(iter) # 傳入可迭代物件寫入檔案

# 關閉檔案操作
file.close()

# 檔案其他操作
file.fileno() # 檔案描述符
file.flush() # 重新整理檔案的內部緩衝區
file.seek(offset,from) 
# 第一個引數,代表需要移動偏移的位元組數。
# 第二個引數,表示要從哪個位置開始偏移;0代表從檔案開頭開始算起,1代表從當前位置開始算起,2代表從檔案末尾算起。
file.tell() # 檢視當前位置
file.closed # 檢視檔案是否關閉,沒關閉返回False
file.encoding # 檢視檔案編碼格式
file.mode # 檢視檔案操作模式
file.name # 檢視檔名

自定義上下文管理器

class Query(object):

    def __init__(self, name):
        self.name = name

    def __enter__(self):
        print('Begin')
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        if exc_type:
            print('Error')
        else:
            print('End')

    def query(self):
        print('Query info about %s...' % self.name)

with Query('Bob') as q:
    q.query()

# 還有另一種更簡便的方法
from contextlib import contextmanager

class Query(object):

    def __init__(self, name):
        self.name = name

    def query(self):
        print('Query info about %s...' % self.name)

@contextmanager
def create_query(name):
    print('Begin')
    q = Query(name)
    yield q
    print('End')
    
    
    
@closing
# 如果一個物件沒有實現上下文,我們就不能把它用於with語句。這個時候,可以用closing()來把該物件變為上下文物件。例如,用with語句使用urlopen():

from contextlib import closing
from urllib.request import urlopen

with closing(urlopen('https://www.python.org')) as page:
    for line in page:
        print(line)
# 它的作用就是把任意物件變為上下文物件,並支援with語句。
訪問模式說明
r以只讀方式開啟檔案。檔案的指標將會放在檔案的開頭。這是預設模式。
w開啟一個檔案只用於寫入。如果該檔案已存在則將其覆蓋。如果該檔案不存在,建立新檔案。
a開啟一個檔案用於追加。如果該檔案已存在,檔案指標將會放在檔案的結尾。也就是說,新的內容將會被寫入到已有內容之後。如果該檔案不存在,建立新檔案進行寫入。
rb以二進位制格式開啟一個檔案用於只讀。檔案指標將會放在檔案的開頭。這是預設模式。
wb以二進位制格式開啟一個檔案只用於寫入。如果該檔案已存在則將其覆蓋。如果該檔案不存在,建立新檔案。
ab以二進位制格式開啟一個檔案用於追加。如果該檔案已存在,檔案指標將會放在檔案的結尾。也就是說,新的內容將會被寫入到已有內容之後。如果該檔案不存在,建立新檔案進行寫入。
r+開啟一個檔案用於讀寫。檔案指標將會放在檔案的開頭。
w+開啟一個檔案用於讀寫。如果該檔案已存在則將其覆蓋。如果該檔案不存在,建立新檔案。
a+開啟一個檔案用於讀寫。如果該檔案已存在,檔案指標將會放在檔案的結尾。檔案開啟時會是追加模式。如果該檔案不存在,建立新檔案用於讀寫。
rb+以二進位制格式開啟一個檔案用於讀寫。檔案指標將會放在檔案的開頭。
wb+以二進位制格式開啟一個檔案用於讀寫。如果該檔案已存在則將其覆蓋。如果該檔案不存在,建立新檔案。
ab+以二進位制格式開啟一個檔案用於追加。如果該檔案已存在,檔案指標將會放在檔案的結尾。如果該檔案不存在,建立新檔案用於讀寫。
import os 
# os模組提供的一些分隔符
os.linesep
'\r\n'    
          
os.sep    
'\\'      
          
os.pathsep
';'       
          
os.curdir 
'.'       
          
os.pardir 
'..'      

常用os模組函式

函式描述
name獲取系統型別(如果是posix,說明系統是Linux、Unix或Mac OS X,如果是nt,就是Windows系統。)
environ檢視作業系統中定義的環境變數
environ.get(‘key’)獲取某個環境變數的值
rename(file,newname)檔案重新命名
remove(file)刪除檔案
mkdir(dir)建立資料夾
makedirs()建立多層目錄
getcwd()獲取當前目錄
chdir("…/")改變預設目錄
listdir("./")獲取目錄列表
rmdir(dir)刪除資料夾
removedir()刪除多層目錄
chmod()改變許可權
access()檢視許可權
open()開啟檔案
read()
write()

常用os.path模組函式

函式描述
abspath(’.’)檢視當前目錄的絕對路徑
basename()去掉目錄路徑,返回檔名
dirname()去掉檔名,返回路徑
join()將分離的各部分組合成一個路徑名
split()將完整的路徑名分割成路徑和檔名
getatime()返回最新的訪問時間
getctime()返回檔案建立時間
getmtime()返回檔案修改時間
getsize()返回檔案位元組大小
exists()判斷檔案或目錄是否存在
isabs()判斷是否是絕對路徑
isdir()判斷是否是目錄
isfile()判斷是否是檔案
splitext()(返回檔名,檔案字尾)

當無法匯入包時使用
os.path.abspath(os.path.join(os.getcwd(),"…"))

python提供了pickle(pickle.dumps(obj)序列化物件成bytes資料、pickle.loads(strobj)將序列化物件轉換成python物件)、cpickle和shelve模組可以將python物件以二進位制直接儲存到檔案裡,而不需要轉換成字串


sys常用方法

函式描述
sys.argv命令列引數List,第一個元素是程式本身路徑
sys.modules.keys()返回所有已經匯入的模組列表
sys.exc_info()獲取當前正在處理的異常類,exc_type、exc_value、exc_traceback當前處理的異常詳細資訊
sys.exit(n)退出程式,正常退出時exit(0),有錯誤退出exit(1)
sys.hexversion獲取Python解釋程式的版本值,16進位制格式如:0x020403F0
sys.version獲取Python解釋程式的版本資訊
sys.maxint最大的Int值
sys.maxunicode最大的Unicode值
sys.modules返回系統匯入的模組欄位,key是模組名,value是模組
sys.path返回模組的搜尋路徑,初始化時使用PYTHONPATH環境變數的值
sys.platform返回作業系統平臺名稱
sys.stdout標準輸出
sys.stdin標準輸入
sys.stderr錯誤輸出
sys.exc_clear()用來清除當前執行緒所出現的當前的或最近的錯誤資訊
sys.exec_prefix返回平臺獨立的python檔案安裝的位置
sys.byteorder本地位元組規則的指示器,big-endian平臺的值是’big’,little-endian平臺的值是’little’
sys.copyright記錄python版權相關的東西
sys.api_version直譯器的C的API版本

Python讀寫ini檔案的方法

[ZIP]
EngineVersion=0
DATVersion=5127
FileName=dat-5127.zip
FilePath=/pub/antivirus/datfiles/4.x/
FileSize=13481555
Checksum=6037,021E
MD5=aaeb519d3f276b810d46642d782d8921

獲取MD5的值

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import ConfigParser
config = ConfigParser.ConfigParser()
config.readfp(open('update.ini'))
a = config.get("ZIP","MD5")
print a

設定值

import ConfigParser
config = ConfigParser.ConfigParser()
# set a number of parameters
config.add_section("book")
config.set("book", "title", "the python standard library")
config.set("book", "author", "fredrik lundh")
config.add_section("ematter")
config.set("ematter", "pages", 250)
# write to file
config.write(open('1.ini', "w"))

修改(新增)

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import ConfigParser
config = ConfigParser.ConfigParser()
config.read('1.ini')
a = config.add_section("md5")
config.set("md5", "value", "1234")
config.write(open('1.ini', "r+")) #可以把r+改成其他方式,看看結果:)

修改

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import ConfigParser
config = ConfigParser.ConfigParser()
config.read('1.ini')
config.set("md5", "value", "kingsoft") #這樣md5就從1234變成kingsoft了
config.write(open('1.ini', "r+"))

shutil標準庫

函式名作用
move(src,dst)移動檔案,重新命名等
copytree('src, dst, symlinks=False, ignore=None)遞迴複製
rmtree(path, ignore_errors=False, οnerrοr=None)遞迴刪除目錄樹
get_archive_formats()返回支援的 壓縮格式列表, 如 [(name,desc),(‘tar’,‘uncompressed tar file’)]
make_archive(base_name, format, root_dir=None, base_dir=None, verbose=0, dry_run=0, owner=None, group=None, logger=None)建立壓縮檔案(base_name : 壓縮包的檔名, 也可以使壓縮包的路徑. format : 壓縮種類,root_dir : 要壓縮的資料夾路徑, 預設當前目錄,owner : 使用者, 預設當前使用者,group : 組, 默然當前組)
copy(src, dst)複製檔案及許可權
shutil.copyfileobj(fsrc, fdst, length=16384)將檔案內容拷貝到另一個檔案, copy data from file-like object fsrc to file-like object fdst
copyfile(src, dst)拷貝檔案, Copy data from src to dst
copymode(src, dst)僅拷貝許可權,內容,使用者,組不變, Copy mode bits from src to dst
copystat(src, dst)僅拷貝狀態資訊, Copy all stat info (mode bits, atime, mtime, flags) from src to dst
copy2(‘f1.log’, ‘f2.log’)拷貝檔案和狀態資訊, Copy data and all stat info

簡單檢視系統型別platform

import platform

platform.system()

訊號處理模組signal

在signal模組中,主要是使用signal.signal()函式來預設訊號處理函式

singnal.signal(signalnum, handler)

其中第一個引數是訊號量,第二個引數訊號處理函式。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import signal
import time

def signal_handler(signum, frame):
    print('Received signal: ', signum)

while True:
    signal.signal(signal.SIGHUP, signal_handler) # 1
    signal.signal(signal.SIGINT, signal_handler) # 2
    signal.signal(signal.SIGQUIT, signal_handler) # 3
    signal.signal(signal.SIGALRM, signal_handler) # 14
    signal.signal(signal.SIGTERM, signal_handler) # 15
    signal.signal(signal.SIGCONT, signal_handler) # 18
    while True:
        print('waiting')
        time.sleep(1)

執行上面的程式

python test.py

然後另外開一個終端,找到對應的程式,並執行下面的kill操作

kill -1 <pid>
kill -2 <pid>
kill -3 <pid>
kill -14 <pid>
kill -15 <pid>
kill -18 <pid>
kill -9 <pid> # 最後殺死程式

此時可以看到test.py的輸出,列印的就是具體接收到的訊號。

這裡注意一點就是程式中註冊了SIGINT訊號,所以在執行程式後使用CTRL+C並不能結束程式,而是仍然列印程式接收到的訊號。

signal.alarm()

另外,signal模組提供了一個很有用的函式signal.alarm(),它用於在一定時間後向程式自身傳送SIGALRM訊號,比如下面的例子設定5秒後向自己傳送一個SIGALRM訊號。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import signal
import time

def signal_handler(signum, frame):
    print('Received signal: ', signum)

while True:
    signal.signal(signal.SIGALRM, signal_handler) # 14
    signal.alarm(5)
    while True:
        print('waiting')
        time.sleep(1)

關於引用、深淺拷貝

import copy

a = [1, 2, 3, [4, 5]]
b = a
c = copy.copy(a)
d = copy.deepcopy(a)
a.append(7)
a[3].append(6)
print(a)
print(b)
print(c)
print(d)

[1, 2, 3, [4, 5, 6], 7]
[1, 2, 3, [4, 5, 6], 7]
[1, 2, 3, [4, 5, 6]]
[1, 2, 3, [4, 5]]

argparse模組

  • python標準庫模組argparse用於解析命令列引數,編寫使用者友好的命令列介面,該模組還會自動生成幫助資訊,並在所給引數無效時報錯。
  • https://docs.python.org/3/library/argparse.html
  • https://blog.csdn.net/guoyajie1990/article/details/76739977
# 例子
#arg_parse.py
#coding:utf-8
import argparse

parser = argparse.ArgumentParser(description='Process some integers.')
parser.add_argument('integers', metavar='N', type=int, nargs='+',help='an integer for the accumulator')
parser.add_argument('--sum', dest='accumulate', action='store_const',const=sum, default=max,
                      help='sum the integers (default: find the max)')
args = parser.parse_args()
print(args.accumulate(args.integers))

將上述程式碼儲存為arg_parse.py,在命令列執行該指令碼。使用-h選項可以檢視幫助資訊

$ python prog.py -h
usage: prog.py [-h] [--sum] N [N ...]
Process some integers.
positional arguments:
 N           an integer for the accumulator
optional arguments:
 -h, --help  show this help message and exit
 --sum       sum the integers (default: find the max)

如果不指定–sum選項,則找出輸入引數中的最大值,否則求和。

$ python prog.py 1 2 3 4
4
$ python prog.py 1 2 3 4 --sum
10

logging日誌的基本使用

  1. 日誌級別
import logging
logger = logging.getLogger()
ch = logging.StreamHandler()
logger.addHandler(ch)
logging.debug('debug')
logging.info('info')
logging.warning('warning')
logging.error('error')
logging.critical('critical')

級別排序:CRITICAL > ERROR > WARNING > INFO > DEBUG
預設級別WARNING
2. 部分名詞解釋

  • Logging.Formatter:這個類配置了日誌的格式,在裡面自定義設定日期和時間,輸出日誌的時候將會按照設定的格式顯示內容。
  • Logging.Logger:Logger是Logging模組的主體,進行以下三項工作:
    1. 為程式提供記錄日誌的介面
    1. 判斷日誌所處級別,並判斷是否要過濾
    1. 根據其日誌級別將該條日誌分發給不同handler
  • 常用函式有:
  • Logger.setLevel() 設定日誌級別
  • Logger.addHandler() 和 Logger.removeHandler() 新增和刪除一個Handler
  • Logger.addFilter() 新增一個Filter,過濾作用
  • Logging.Handler:Handler基於日誌級別對日誌進行分發,如設定為WARNING級別的Handler只會處理WARNING及以上級別的日誌。
  • 常用函式有:
  • setLevel() 設定級別
  • setFormatter() 設定Formatter
  1. 日誌輸出-控制檯
import logging  # 引入logging模組
logging.basicConfig(level=logging.DEBUG,
                    format='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s')  # logging.basicConfig函式對日誌的輸出格式及方式做相關配置
# 由於日誌基本配置中級別設定為DEBUG,所以一下列印資訊將會全部顯示在控制檯上
logging.info('this is a loggging info message')
logging.debug('this is a loggging debug message')
logging.warning('this is loggging a warning message')
logging.error('this is an loggging error message')
logging.critical('this is a loggging critical message')
  1. 日誌輸出-檔案
import logging  # 引入logging模組
import os.path
import time
# 第一步,建立一個logger
logger = logging.getLogger()
logger.setLevel(logging.INFO)  # Log等級總開關
# 第二步,建立一個handler,用於寫入日誌檔案
rq = time.strftime('%Y%m%d%H%M', time.localtime(time.time()))
log_path = os.path.dirname(os.getcwd()) + '/Logs/'
log_name = log_path + rq + '.log'
logfile = log_name
fh = logging.FileHandler(logfile, mode='w')
fh.setLevel(logging.DEBUG)  # 輸出到file的log等級的開關
# 第三步,定義handler的輸出格式
formatter = logging.Formatter("%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s")
fh.setFormatter(formatter)
# 第四步,將logger新增到handler裡面
logger.addHandler(fh)
# 日誌
logger.debug('this is a logger debug message')
logger.info('this is a logger info message')
logger.warning('this is a logger warning message')
logger.error('this is a logger error message')
logger.critical('this is a logger critical message')
  1. 日誌輸出-控制檯和檔案

只要在輸入到日誌中的第二步和第三步插入一個handler輸出到控制檯:
建立一個handler,用於輸出到控制檯
ch = logging.StreamHandler()
ch.setLevel(logging.WARNING) # 輸出到console的log等級的開關
第四步和第五步分別加入以下程式碼即可
ch.setFormatter(formatter)
logger.addHandler(ch)

  1. format常用格式說明
  • %(levelno)s: 列印日誌級別的數值
  • %(levelname)s: 列印日誌級別名稱
  • %(pathname)s: 列印當前執行程式的路徑,其實就是sys.argv[0]
  • %(filename)s: 列印當前執行程式名
  • %(funcName)s: 列印日誌的當前函式
  • %(lineno)d: 列印日誌的當前行號
  • %(asctime)s: 列印日誌的時間
  • %(thread)d: 列印執行緒ID
  • %(threadName)s: 列印執行緒名稱
  • %(process)d: 列印程式ID
  • %(message)s: 列印日誌資訊
import logging.config

conf = {'version': 1,
        'disable_existing_loggers': True,
        'incremental': False,
        'formatters': {'myformat1': {'class': 'logging.Formatter',
                                     'format': '|%(asctime)s|%(name)s|%(filename)s|%(lineno)d|%(levelname)s|%(message)s',
                                     'datefmt': '%Y-%m-%d %H:%M:%S'}
                      },
        'filters': {'filter_by_name': {'class': 'logging.Filter',
                                       'name': 'logger_for_filter_name'},

                    'filter_single_level_pass':{'()': 'mylogger.SingleLevelFilter',
                                                'pass_level': logging.WARN}
                    },
        'handlers': {'console': {'class': 'logging.StreamHandler',
                                  'level': 'INFO',
                                  'formatter': 'myformat1',
                                  'filters': ['filter_single_level_pass', ]},

                     'screen': {'()': 'mylogger.ScreenHandler',
                                'level': logging.INFO,
                                'formatter': 'myformat1',
                                'filters': ['filter_by_name', ]}
                    },
        'loggers': {'logger_for_filter_name': {'handlers': ['console', 'screen'],
                                               'filters': ['filter_by_name', ],
                                               'level': 'INFO'},
                    'logger_for_all': {'handlers': ['console', ],
                                       'filters': ['filter_single_level_pass',],
                                       'level': 'INFO',
                                       'propagate': False}
                   }
        }
logging.config.dictConfig(conf)

logging.getLogger('logger_for_all')
import logging.config
import os
import platform

__PREFIX = 'D:\\tyxb_tiantong_logs' if platform.system() == 'Windows' else '%s/%s/%s' % (
        log_path.rstrip('/'), app_name.strip('/'), os.getpid())

# 根據系統修改檔案生成路徑
__LOG_PATH_DEBUG = r'%s\debug.log' % __PREFIX if platform.system() == 'Windows' else '%s/debug.log' % __PREFIX
__LOG_PATH_INFO = r'%s\info.log' % __PREFIX if platform.system() == 'Windows' else '%s/info.log' % __PREFIX
__LOG_PATH_WARN = r'%s\warn.log' % __PREFIX if platform.system() == 'Windows' else '%s/warn.log' % __PREFIX
__LOG_PATH_ERROR = r'%s\error.log' % __PREFIX if platform.system() == 'Windows' else '%s/error.log' % __PREFIX

# 判斷目錄是否存在
if not os.path.exists(__PREFIX):
    os.makedirs(__PREFIX)

# 鏃ュ織閰嶇疆
__LOGGING_CONFIG = {
    'version': 1,
    'disable_existing_loggers': True,
    'formatters': {
        'standard': {
            'format': '[%(asctime)s] %(levelname)s::(%(process)d %(thread)d)::%(module)s(%(funcName)s:%(lineno)d): %(message)s'
        },
    },
    'handlers': {
        'error': {
            'class': 'logging.handlers.TimedRotatingFileHandler',
            'level': 'ERROR',
            'formatter': 'standard',
            'filename': __LOG_PATH_ERROR + '_file',
            'when': 'H',
            'interval': 1
        },
        'warn': {
            'class': 'logging.handlers.TimedRotatingFileHandler',
            'level': 'WARN',
            'formatter': 'standard',
            'filename': __LOG_PATH_WARN + '_file',
            'when': 'H',
            'interval': 1
        },
        'info': {
            'class': 'logging.handlers.TimedRotatingFileHandler',
            'level': 'INFO',
            'formatter': 'standard',
            'filename': __LOG_PATH_INFO + '_file',
            'when': 'H',
            'interval': 1
        },
        'debug': {
            'class': 'logging.handlers.TimedRotatingFileHandler',
            'level': 'DEBUG',
            'formatter': 'standard',
            'filename': __LOG_PATH_DEBUG + '_file',
            'when': 'H',
            'interval': 1
        }
    },
    'loggers': {
        'default': {
            'handlers': ['debug', 'info', 'warn', 'error'],
            'level': 'INFO',
            'propagate': True
        },
        'enable_debug': {
            'handlers': ['debug', 'info', 'warn', 'error'],
            'level': 'DEBUG',
            'propagate': True
        }
    }
}

logging.config.dictConfig(__LOGGING_CONFIG)
if debug:
    return logging.getLogger('enable_debug')
else:
    return logging.getLogger('default')

重寫日誌物件

import logging
import getpass
import sys

class L(logging.Logger):

    def debug(self, msg, *args, **kwargs):
        if self.isEnabledFor(logging.DEBUG):
            self._log(logging.DEBUG, msg, args, extra={"真的": "可以"}, **kwargs)



logger = L("new") # logging.getLogger("new")
logger.setLevel(logging.DEBUG)
formatter = logging.Formatter("[%(asctime)s] %(levelname)s::(%(process)d %(thread)d)::%(module)s(%(funcName)s:%(lineno)d): %(message)s")
ll = logging.StreamHandler()
ll.setFormatter(formatter)
logger.addHandler(ll)
logger.debug("ok")

其他相關資料 https://www.cnblogs.com/CJOKER/p/8295272.html


相關模組

模組內容
base64提供二進位制字串和文字字串的編碼/解碼
binascli提供二進位制和ASCII編碼的二進位制字串間的編碼/解碼
bz2訪問BZ2格式的壓縮檔案
csv訪問csv檔案
json訪問json檔案
filecmp用於比較目錄和檔案
fileinput提供多個文字檔案的行迭代器
gzip/zlib讀寫GNU zip(gzip)檔案/壓縮檔案
c/String()對字串物件提供檔案介面
zipfile用於讀取zip歸檔檔案工具
tarfile讀取tar歸檔檔案

常用第三方庫

chardet檢測編碼格式

>>> chardet.detect(b'Hello, world!')
{'encoding': 'ascii', 'confidence': 1.0, 'language': ''}

>>> data = '離離原上草,一歲一枯榮'.encode('utf-8')
>>> chardet.detect(data)
{'encoding': 'utf-8', 'confidence': 0.99, 'language': ''}

IPy

校驗ip是否合法

https://pypi.org/project/IPy/
from IPy import IP
>>> print(IP(0x7f000001))
127.0.0.1 
>>> print(IP('0x7f000001'))
127.0.0.1 
>>> print(IP(' 127.0.0.1'))
127.0.0.1 
>>> print(IP('10'))
10.0.0.0 

# 如果不合法丟擲異常

pillow影像處理庫

from PIL import Image

# 開啟一個jpg影像檔案,注意是當前路徑:
im = Image.open('test.jpg')
# 獲得影像尺寸:
w, h = im.size
print('Original image size: %sx%s' % (w, h))
# 縮放到50%:
im.thumbnail((w//2, h//2))
print('Resize image to: %sx%s' % (w//2, h//2))
# 把縮放後的影像用jpeg格式儲存:
im.save('thumbnail.jpg', 'jpeg')


from PIL import Image, ImageFilter

# 開啟一個jpg影像檔案,注意是當前路徑:
im = Image.open('test.jpg')
# 應用模糊濾鏡:
im2 = im.filter(ImageFilter.BLUR)
im2.save('blur.jpg', 'jpeg')

tqdm(iterator)進度條

from tqdm import tqdm

for i in tqdm(range(10)):
    pass

psutil監控系統執行狀態

https://github.com/giampaolo/psutil
https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/001511052957192bb91a56a2339485c8a8c79812b400d49000

# 獲取CPU的資訊:
>>> import psutil
>>> psutil.cpu_count() # CPU邏輯數量
4
>>> psutil.cpu_count(logical=False) # CPU物理核心
2

# 統計CPU的使用者/系統/空閒時間:
>>> psutil.cpu_times()
scputimes(user=10963.31, nice=0.0, system=5138.67, idle=356102.45)

six一種版本相容模組

https://pythonhosted.org/six/

import six
# 判斷是否是python2
six.PY2
# 判斷是否是python3
six.PY3

# 相容py2和py3的佇列
from six.moves.queue import Queue

w3lib對url、html、http做處理

http://w3lib.readthedocs.io/en/latest/w3lib.html

import w3lib.url
# 對url進行排序
w3lib.url.canonicalize_url(url, keep_blank_values=True, keep_fragments=False, encoding=None)

suds呼叫webservice介面

引用初始化
>>> from suds.client import Client
>>> url = 'http://www.gpsso.com/webservice/kuaidi/kuaidi.asmx?wsdl'
>>> client = Client(url)
>>> print client

Suds ( https://fedorahosted.org/suds/ ) version: 0.4 GA build: R699-20100913

Service ( Kuaidi ) tns="http://gpsso.com/"
Prefixes (1)
ns0 = "http://gpsso.com/"
Ports (2):
(KuaidiSoap)
Methods (1):
KuaidiQuery(xs:string Compay, xs:string OrderNo, )
Types (1):
ApiSoapHeader
(KuaidiSoap12)
Methods (1):
KuaidiQuery(xs:string Compay, xs:string OrderNo, )
Types (1):
ApiSoapHeader
>>>
對url做一下說明,一般要確認給的wsdl地址是正常模式,地址開啟一般為xml格式而有些服務是做成了html模式,這個會導致例項化或者呼叫方法的時候出現xml解析異常。
方法呼叫
2中的client列印出來就可以知道,該webserviece服務定義了什麼方法,方法需要什麼引數,宣告瞭什麼資訊等(如頭資訊,ApiSoapHeader),方法可以通過client.serviece直接呼叫
>>> client.service.KuaidiQuery(Company='EMS', OrderNo='1111')
(KuaidiQueryResult){
   API =
      (API){
         RESULTS = "0"
         MESSAGE = "介面查詢成功"
      }
 }
>>>
而宣告的頭資訊,則可以用factory的方式去例項化
>>> header = client.factory.create('ApiSoapHeader')
>>> print header
(ApiSoapHeader){
   APICode = None
   APIKey = None
 }
>>> header.APICode = '123'
>>> header.APIKey = 'key123'
>>> print header
(ApiSoapHeader){
   APICode = "123"
   APIKey = "key123"
 }
>>>
頭資訊需要用set_options方法設定
>>>
>>> client.set_options(soapheaders=[header,])
>>>

內建模組

collections集合模組

# namedtuple是一個函式,它用來建立一個自定義的tuple物件,並且規定了tuple元素的個數,並可以用屬性而不是索引來引用tuple的某個元素。
>>> from collections import namedtuple
>>> Point = namedtuple('Point', ['x', 'y'])
>>> p = Point(1, 2)
>>> p.x
1
>>> p.y
2

# deque除了實現list的append()和pop()外,還支援appendleft()和popleft(),這樣就可以非常高效地往頭部新增或刪除元素。
>>> from collections import deque
>>> q = deque(['a', 'b', 'c'])
>>> q.append('x')
>>> q.appendleft('y')
>>> q
deque(['y', 'a', 'b', 'c', 'x'])

# defaultdict
# 使用dict時,如果引用的Key不存在,就會丟擲KeyError。如果希望key不存在時,返回一個預設值,就可以用defaultdict:
>>> from collections import defaultdict
>>> dd = defaultdict(lambda: 'N/A')
>>> dd['key1'] = 'abc'
>>> dd['key1'] # key1存在
'abc'
>>> dd['key2'] # key2不存在,返回預設值
'N/A'
# 注意預設值是呼叫函式返回的,而函式在建立defaultdict物件時傳入。
# 除了在Key不存在時返回預設值,defaultdict的其他行為跟dict是完全一樣的。

# OrderedDict
# 使用dict時,Key是無序的。在對dict做迭代時,我們無法確定Key的順序。
# 果要保持Key的順序,可以用OrderedDict:
>>> from collections import OrderedDict
>>> d = dict([('a', 1), ('b', 2), ('c', 3)])
>>> d # dict的Key是無序的
{'a': 1, 'c': 3, 'b': 2}
>>> od = OrderedDict([('a', 1), ('b', 2), ('c', 3)])
>>> od # OrderedDict的Key是有序的
OrderedDict([('a', 1), ('b', 2), ('c', 3)])
# 注意,OrderedDict的Key會按照插入的順序排列,不是Key本身排序

# Counter是一個簡單的計數器,例如,統計字元出現的個數:
>>> 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實際上也是dict的一個子類,上面的結果可以看出,字元'g'、'm'、'r'各出現了兩次,其他字元各出現了一次。
常見做法:
sum(c.values())                 # 繼承自字典的.values()方法返回values的列表,再求和
c.clear()                       # 繼承自字典的.clear()方法,清空counter
list(c)                         # 返回key組成的list
set(c)                          # 返回key組成的set
dict(c)                         # 轉化成字典
c.items()                       # 轉化成(元素,計數值)組成的列表
Counter(dict(list_of_pairs))    # 從(元素,計數值)組成的列表轉化成Counter
c.most_common()[:-n-1:-1]       # 最小n個計數的(元素,計數值)組成的列表
c += Counter()                  # 利用counter的相加來去除負值和0的值


from collections import ChainMap
# 連線操作,如果有相同鍵只會取第一個元素
dict1={"a":"bobby1", "b":"bobby2"}
dict2={"c":"bobby2", "d":"bobby3"}
new_dict=ChainMap(user_dict1, user_dict2)
for key, value in new_dict.items():
    print(key, value)
print(new_dict.maps)

from collections import Iterator, Iterable # 判斷型別

時間日期處理

董小旭提供 http://www.wklken.me/posts/2015/03/03/python-base-datetime.html

1. datetime
>>> import datetime
>>> now = datetime.datetime.now()
>>> now
datetime.datetime(2015, 1, 12, 23, 9, 12, 946118)
>>> type(now)
<type 'datetime.datetime'>

2. timestamp
>>> import time
>>> time.time()
1421075455.568243

3. time tuple
>>> import time
>>> time.localtime()
time.struct_time(tm_year=2015, tm_mon=1, tm_mday=12, tm_hour=23, tm_min=10, tm_sec=30, tm_wday=0, tm_yday=12, tm_isdst=0)

4. string
>>> import datetime
>>> datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
'2015-01-12 23:13:08'

5. date
>>> import datetime
>>> datetime.datetime.now().date()
datetime.date(2015, 1, 12)

datetime基本操作
1. 獲取當前datetime
>>> import datetime
>>> datetime.datetime.now()
datetime.datetime(2015, 1, 12, 23, 26, 24, 475680)

2. 獲取當天date
>>> datetime.date.today()
datetime.date(2015, 1, 12)

3. 獲取明天/前N天
明天
>>> datetime.date.today() + datetime.timedelta(days=1)
datetime.date(2015, 1, 13)

三天前
>>> datetime.datetime.now()
datetime.datetime(2015, 1, 12, 23, 38, 55, 492226)
>>> datetime.datetime.now() - datetime.timedelta(days=3)
datetime.datetime(2015, 1, 9, 23, 38, 57, 59363)

4. 獲取當天開始和結束時間(00:00:00 23:59:59)
>>> datetime.datetime.combine(datetime.date.today(), datetime.time.min)
datetime.datetime(2015, 1, 12, 0, 0)
>>> datetime.datetime.combine(datetime.date.today(), datetime.time.max)
datetime.datetime(2015, 1, 12, 23, 59, 59, 999999)

5. 獲取兩個datetime的時間差

>>> (datetime.datetime(2015,1,13,12,0,0) - datetime.datetime.now()).total_seconds()
44747.768075

6. 獲取本週/本月/上月最後一天

本週
>>> today = datetime.date.today()
>>> today
datetime.date(2015, 1, 12)
>>> sunday = today + datetime.timedelta(6 - today.weekday())
>>> sunday
datetime.date(2015, 1, 18)

本月
>>> import calendar
>>> today = datetime.date.today()
>>> _, last_day_num = calendar.monthrange(today.year, today.month)
>>> last_day = datetime.date(today.year, today.month, last_day_num)
>>> last_day
datetime.date(2015, 1, 31)

獲取上個月的最後一天(可能跨年)
>>> import datetime
>>> today = datetime.date.today()
>>> first = datetime.date(day=1, month=today.month, year=today.year)
>>> lastMonth = first - datetime.timedelta(days=1)

關係轉換

幾個關係之間的轉化

Datetime Object / String / timestamp / time tuple
關係轉換例子
datetime <=> string

datetime -> string
>>> import datetime
>>> datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
'2015-01-12 23:13:08'

string -> datetime
>>> import datetime
>>> datetime.datetime.strptime("2014-12-31 18:20:10", "%Y-%m-%d %H:%M:%S")
datetime.datetime(2014, 12, 31, 18, 20, 10)

datetime -> timetuple
>>> import datetime
>>> datetime.datetime.now().timetuple()
time.struct_time(tm_year=2015, tm_mon=1, tm_mday=12, tm_hour=23, tm_min=17, tm_sec=59, tm_wday=0, tm_yday=12, tm_isdst=-1)

timetuple -> datetime
timetuple => timestamp => datetime [看後面datetime<=>timestamp]

datetime <=> date

datetime -> date
>>> import datetime
>>> datetime.datetime.now().date()
datetime.date(2015, 1, 12)

date -> datetime
>>> datetime.date.today()
datetime.date(2015, 1, 12)
>>> today = datetime.date.today()
>>> datetime.datetime.combine(today, datetime.time())
datetime.datetime(2015, 1, 12, 0, 0)
>>> datetime.datetime.combine(today, datetime.time.min)
datetime.datetime(2015, 1, 12, 0, 0)

datetime <=> timestamp

datetime -> timestamp
>>> now = datetime.datetime.now()
>>> timestamp = time.mktime(now.timetuple())
>>> timestamp
1421077403.0

timestamp -> datetime
>>> datetime.datetime.fromtimestamp(1421077403.0)
datetime.datetime(2015, 1, 12, 23, 43, 23)

加鎖——fcntl模組

import fcntl

開啟一個檔案

f = open('./test') ##當前目錄下test檔案要先存在,如果不存在會報錯。

對該檔案加密:

fcntl.flock(f,fcntl.LOCK_EX)

這樣就對檔案test加鎖了,如果有其他程式對test檔案加鎖,則不能成功,會被阻塞,但不會退出程式。

解鎖:fcntl.flock(f,fcntl.LOCK_UN)

cntl模組:

flock() : flock(f, operation)

  operation : 包括:

    fcntl.LOCK_UN 解鎖

    fcntl.LOCK_EX  排他鎖

fcntl.LOCK_SH  共享鎖

fcntl.LOCK_NB  非阻塞鎖

LOCK_SH 共享鎖:所有程式沒有寫訪問許可權,即使是加鎖程式也沒有。所有程式有讀訪問許可權。

LOCK_EX 排他鎖:除加鎖程式外其他程式沒有對已加鎖檔案讀寫訪問許可權。

LOCK_NB 非阻塞鎖:

    如果指定此引數,函式不能獲得檔案鎖就立即返回,否則,函式會等待獲得檔案鎖。LOCK_NB可以同LOCK_SH或LOCK_NB進行按位或(|)運算操作。 fcnt.flock(f,fcntl.LOCK_EX|fcntl.LOCK_NB)

例子:
import os
import sys
import time
import fcntl #匯入模組
 
class FLOCK(ojbect):
    def __init__(self,name):
        """
        :param name: 檔名
        """
 
        self.fobj = open(name,'w')
        self.fd = self.fobj.fileno()
 
    def lock(self):
        try:
            fcntl.lockf(sefl.fd,fcntl.LOCK_EX|fcntl.LOCK_NB) #給檔案加鎖,使用了fcntl.LOCK_NB
            print '給檔案加鎖,稍等 ... ...'
            time.sleep(20)
            return True
        except:
            print '檔案加鎖,無法執行,請稍後執行。'
            retrun False
 
    def unlock(self):
        self.fobj.close()
        print '已解鎖'
 
if __name__ == "__main__":
    print sys.argv[1]
    locker = FLOCK(sys.argv[1])
    a = locker.lock()
    if a:
        print '檔案已加鎖'
    else:
        print '無法執行,程式已鎖定,請稍等'


decimal快速入門

https://docs.python.org/2/library/decimal.html#quick-start-tutorial

十進位制模組具有使用者可更改的精度(預設為28個位置),對於給定的問題,該精度可以與需要的一樣大:

>>> from decimal import *
>>> getcontext().prec = 6
>>> Decimal(1) / Decimal(7)
Decimal('0.142857')
>>> getcontext().prec = 28
>>> Decimal(1) / Decimal(7)
Decimal('0.1428571428571428571428571429')

通常開始使用小數將匯入模組,檢視當前上下文,getcontext()並在必要時為精度,舍入或啟用的陷阱設定新值:

>>> from decimal import *
>>> getcontext()
Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999999, Emax=999999999,
        capitals=1, flags=[], traps=[Overflow, DivisionByZero,
        InvalidOperation])

>>> getcontext().prec = 7       # Set a new precision

十進位制例項可以用整數,字串,浮點數或元組構造。從整數或浮點構造執行該整數或浮點的值的精確轉換。十進位制數字包括特殊值,例如 NaN,表示“不是數字”,正數和負數 Infinity,以及-0。

>>> getcontext().prec = 28
>>> Decimal(10)
Decimal('10')
>>> Decimal('3.14')
Decimal('3.14')
>>> Decimal(3.14)
Decimal('3.140000000000000124344978758017532527446746826171875')
>>> Decimal((0, (3, 1, 4), -2))
Decimal('3.14')
>>> Decimal(str(2.0 ** 0.5))
Decimal('1.41421356237')
>>> Decimal(2) ** Decimal('0.5')
Decimal('1.414213562373095048801688724')
>>> Decimal('NaN')
Decimal('NaN')
>>> Decimal('-Infinity')
Decimal('-Infinity')

新Decimal的意義僅由輸入的位數決定。上下文精度和舍入僅在算術運算中發揮作用。

>>> getcontext().prec = 6
>>> Decimal('3.0')
Decimal('3.0')
>>> Decimal('3.1415926535')
Decimal('3.1415926535')
>>> Decimal('3.1415926535') + Decimal('2.7182818285')
Decimal('5.85987')
>>> getcontext().rounding = ROUND_UP
>>> Decimal('3.1415926535') + Decimal('2.7182818285')

小數與Python的其餘部分很好地互動。這裡有一個小小數浮點飛行馬戲團:

>>> data = map(Decimal, '1.34 1.87 3.45 2.35 1.00 0.03 9.25'.split())
>>> max(data)
Decimal('9.25')
>>> min(data)
Decimal('0.03')
>>> sorted(data)
[Decimal('0.03'), Decimal('1.00'), Decimal('1.34'), Decimal('1.87'),
 Decimal('2.35'), Decimal('3.45'), Decimal('9.25')]
>>> sum(data)
Decimal('19.29')
>>> a,b,c = data[:3]
>>> str(a)
'1.34'
>>> float(a)
1.34
>>> round(a, 1)     # round() first converts to binary floating point
1.3
>>> int(a)
1
>>> a * 5
Decimal('6.70')
>>> a * b
Decimal('2.5058')
>>> c % a
Decimal('0.77')

還有一些數學函式也可用於Decimal:

>>> getcontext().prec = 28
>>> Decimal(2).sqrt()
Decimal('1.414213562373095048801688724')
>>> Decimal(1).exp()
Decimal('2.718281828459045235360287471')
>>> Decimal('10').ln()
Decimal('2.302585092994045684017991455')
>>> Decimal('10').log10()
Decimal('1')

該quantize()方法將數字四捨五入為固定的指數。這種方法對於貨幣應用程式非常有用,這些應用程式通常會將結果轉換為固定數量的地方

>>> Decimal('7.325').quantize(Decimal('.01'), rounding=ROUND_DOWN)
Decimal('7.32')
>>> Decimal('7.325').quantize(Decimal('1.'), rounding=ROUND_UP)
Decimal('8')

如上所示,該getcontext()功能訪問當前上下文並允許更改設定。這種方法可以滿足大多數應用的需求。

對於更高階的工作,使用Context()建構函式建立備用上下文可能很有用。要使備用啟用,請使用該setcontext() 功能。

根據該標準,該decimal模組提供了兩個準備使用的標準上下文,BasicContext並且ExtendedContext。前者對於除錯特別有用,因為許多陷阱都已啟用:

>>> myothercontext = Context(prec=60, rounding=ROUND_HALF_DOWN)
>>> setcontext(myothercontext)
>>> Decimal(1) / Decimal(7)
Decimal('0.142857142857142857142857142857142857142857142857142857142857')

>>> ExtendedContext
Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999999, Emax=999999999,
        capitals=1, flags=[], traps=[])
>>> setcontext(ExtendedContext)
>>> Decimal(1) / Decimal(7)
Decimal('0.142857143')
>>> Decimal(42) / Decimal(0)
Decimal('Infinity')

>>> setcontext(BasicContext)
>>> Decimal(42) / Decimal(0)
Traceback (most recent call last):
  File "<pyshell#143>", line 1, in -toplevel-
    Decimal(42) / Decimal(0)

上下文還有訊號標誌用於監控計算過程中遇到的異常情況。這些標誌保持設定直到明確清除,所以最好在每一組監控計算之前使用該clear_flags()方法清除標誌。

>>> setcontext(ExtendedContext)
>>> getcontext().clear_flags()
>>> Decimal(355) / Decimal(113)
Decimal('3.14159292')
>>> getcontext()
Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999999, Emax=999999999,
        capitals=1, flags=[Rounded, Inexact], traps=[])

該標誌條目顯示合理的近似Pi四捨五入(數字超出範圍內精度被扔掉了),而且結果不準確(有些丟棄數字為非零)。

單個陷阱是使用traps上下文欄位中的字典設定的:

>>> setcontext(ExtendedContext)
>>> Decimal(1) / Decimal(0)
Decimal('Infinity')
>>> getcontext().traps[DivisionByZero] = 1
>>> Decimal(1) / Decimal(0)
Traceback (most recent call last):
  File "<pyshell#112>", line 1, in -toplevel-
    Decimal(1) / Decimal(0)

大多數程式只在程式開始時調整當前上下文一次。而且,在許多應用程式中,資料會Decimal在迴圈內轉換為單個資料。通過建立上下文集和小數點,程式的大部分運算元據的方式與其他Python數字型別無異。

class decimal.Decimal([ value [,context ] ] )
Decimal基於價值構建一個新的物件。

值可以是整數,字串,元組float或其他Decimal 物件。如果沒有給出價值,則返回Decimal(‘0’)。如果value是一個字串,則在刪除前導和尾隨空白字元後,它應該符合十進位制數字字串語法:

sign           ::=  '+' | '-'
digit          ::=  '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
indicator      ::=  'e' | 'E'
digits         ::=  digit [digit]...
decimal-part   ::=  digits '.' [digits] | ['.'] digits
exponent-part  ::=  indicator [sign] digits
infinity       ::=  'Infinity' | 'Inf'
nan            ::=  'NaN' [digits] | 'sNaN' [digits]
numeric-value  ::=  decimal-part [exponent-part] | infinity
numeric-string ::=  [sign] numeric-value | [sign] nan

操作說明

adjusted()
移出係數最右邊的數字後,返回撥整後的指數,直到只剩下前導數字: Decimal('321e+5').adjusted()返回7。用於確定最重要數字相對於小數點的位置。

as_tuple()
返回數字的命名元組表示形式: 。DecimalTuple(sign, digits, exponent)

在版本2.6中更改:使用命名的元組。

canonical()
返回引數的規範編碼。目前,一個Decimal例項的編碼總是規範的,所以這個操作返回它的引數不變。

2.6版本中的新功能。

compare(其他[,上下文] )
比較兩個Decimal例項的值。此操作的行為與通常的比較方法相同__cmp__(),只是 compare()返回Decimal例項而不是整數,並且如果任一運算元是NaN,則結果是NaN:

a or b is a NaN ==> Decimal('NaN')
a < b           ==> Decimal('-1')
a == b          ==> Decimal('0')
a > b           ==> Decimal('1')
compare_signal(其他[,上下文] )
compare()除了所有的NaNs訊號之外,該操作與該方法相同。也就是說,如果兩個運算元都不是一個NaN訊號,那麼任何安靜的NaN運算元都被視為一個訊號NaN。

compare_total(其他)
使用它們的抽象表示比較兩個運算元,而不是它們的數值。與該compare()方法類似,但結果給出了Decimal例項的總排序。Decimal具有相同數值但不同表示的兩個 例項在此順序中比較不等:

>>> Decimal('12.0').compare_total(Decimal('12'))
Decimal('-1')
安全和信令NaNs也包括在總的順序中。這個函式的結果是,Decimal('0')如果兩個運算元具有相同的表示形式,Decimal('-1')如果第一個運算元在總順序中低於第二個,並且Decimal('1')第一個運算元在總順序中高於第二個運算元。有關總訂單的詳細資訊,請參閱規格。

2.6版本中的新功能。

compare_total_mag(其他)
比較兩個運算元使用它們的抽象表示而不是它們的值compare_total(),但忽略每個運算元的符號。 x.compare_total_mag(y)相當於 x.copy_abs().compare_total(y.copy_abs())。

2.6版本中的新功能。

conjugate()
只是返回自我,這種方法只符合十進位制規範。

2.6版本中的新功能。

copy_abs()
返回引數的絕對值。此操作不受上下文影響,並且很安靜:沒有標誌被更改,也沒有執行舍入。

2.6版本中的新功能。

copy_negate()
返回引數的否定。此操作不受上下文影響,並且很安靜:沒有標誌被更改,也沒有執行舍入。

2.6版本中的新功能。

copy_sign(其他)
返回第一個運算元的副本,並將符號設定為與第二個運算元的符號相同。例如:

>>> Decimal('2.3').copy_sign(Decimal('-1.5'))
Decimal('-2.3')
此操作不受上下文影響,並且很安靜:沒有標誌被更改,也沒有執行舍入。

2.6版本中的新功能。

exp([ context ] )
返回e**x給定數字處的(自然)指數函式的值。結果使用ROUND_HALF_EVEN舍入模式正確舍 入。

>>> Decimal(1).exp()
Decimal('2.718281828459045235360287471')
>>> Decimal(321).exp()
Decimal('2.561702493119680037517373933E+139')
2.6版本中的新功能。

from_float(f )
精確地將float轉換為十進位制數的Classmethod。

注意Decimal.from_float(0.1)與Decimal('0.1')不同。由於0.1在二進位制浮點中不能完全表示,因此該值儲存為最接近的可表示值,即 0x1.999999999999ap-4。該十進位制等效值是 0.1000000000000000055511151231257827021181583404541015625。

注意 從Python 2.7開始,一個Decimal例項也可以直接從a構建float。
>>> Decimal.from_float(0.1)
Decimal('0.1000000000000000055511151231257827021181583404541015625')
>>> Decimal.from_float(float('nan'))
Decimal('NaN')
>>> Decimal.from_float(float('inf'))
Decimal('Infinity')
>>> Decimal.from_float(float('-inf'))
Decimal('-Infinity')
2.7版本的新功能。

fma(other,third [,context ] )
融合乘加。返回自己*其他+第三沒有捨去中間產品自己*其他。

>>> Decimal(2).fma(3, 5)
Decimal('11')
2.6版本中的新功能。

is_canonical()
True如果引數是規範的,False 否則返回。目前,一個Decimal例項總是規範的,所以這個操作總是返回True。

2.6版本中的新功能。

is_finite()
返回True如果引數是一個有限數量,以及 False如果引數為無窮大或為NaN。

2.6版本中的新功能。

is_infinite()
返回True如果引數為正或負無窮大,False否則。

2.6版本中的新功能。

is_nan()
返回True如果引數是(安靜或信令)的NaN和 False其它。

2.6版本中的新功能。

is_normal()
True如果引數是一個調整指數大於或等於Emin的正常有限非零數字,則返回。返回如果引數為0,低於正常,無窮大或NaN的。請注意,術語“ 法線”在此處與用於建立典型值的方法在不同的意義上使用。Falsenormalize()

2.6版本中的新功能。

is_qnan()
True如果引數是安靜的NaN,則返回, False否則返回。

2.6版本中的新功能。

is_signed()
True如果引數有負號False則返回, 否則返回。請注意,零和NaN都可以攜帶符號。

2.6版本中的新功能。

is_snan()
返回True如果引數信令楠False 否則。

2.6版本中的新功能。

is_subnormal()
True如果引數是低於正常的,則返回,False 否則返回。如果數字非零,有限且調整指數小於Emin,則數字為低於正常值。

2.6版本中的新功能。

is_zero()
返回True如果引數為一(正或負)和零 False否則。

2.6版本中的新功能。

ln([ context ] )
返回運算元的自然對數(基數e)。結果使用ROUND_HALF_EVEN舍入模式正確舍入。

2.6版本中的新功能。

log10([ context ] )
返回運算元的十進位制對數。結果使用ROUND_HALF_EVEN舍入模式正確舍入。

2.6版本中的新功能。

logb([ context ] )
對於非零數字,返回其運算元的調整指數作為 Decimal例項。如果運算元為零,則 Decimal('-Infinity')返回該DivisionByZero標誌並引發該標誌。如果運算元是無窮大,則Decimal('Infinity')返回。

2.6版本中的新功能。

logical_and(其他[,上下文] )
logical_and()是一個邏輯操作,它需要兩個邏輯運算元(請參閱邏輯運算元)。結果是and兩個運算元的數字方式。

2.6版本中的新功能。

logical_invert([ context ] )
logical_invert()是一種邏輯運算。結果是運算元的數字反轉。

2.6版本中的新功能。

logical_or(其他[,上下文] )
logical_or()是一個邏輯操作,它需要兩個邏輯運算元(請參閱邏輯運算元)。結果是or兩個運算元的數字方式。

2.6版本中的新功能。

logical_xor(其他[,上下文] )
logical_xor()是一個邏輯操作,它需要兩個邏輯運算元(請參閱邏輯運算元)。結果是數字獨佔或兩個運算元。

2.6版本中的新功能。

max(其他[,上下文] )
像不同的是在返回之前和施加的上下文舍入規則值用訊號通知或忽略(取決於上下文以及它們是否信令或安靜)。max(self, other)NaN

max_mag(其他[,上下文] )
與該max()方法類似,但使用運算元的絕對值進行比較。

2.6版本中的新功能。

min(其他[,上下文] )
像不同的是在返回之前和施加的上下文舍入規則值用訊號通知或忽略(取決於上下文以及它們是否信令或安靜)。min(self, other)NaN

min_mag(其他[,上下文] )
與該min()方法類似,但使用運算元的絕對值進行比較。

2.6版本中的新功能。

next_minus([ context ] )
返回給定上下文中的最大數字(或者在當前執行緒的上下文中,如果沒有給出上下文),該數字小於給定的運算元。

2.6版本中的新功能。

next_plus([ context ] )
返回大於給定運算元的給定上下文(或者在當前執行緒的上下文中,如果沒有給出上下文)中可表示的最小數字。

2.6版本中的新功能。

next_toward(其他[,上下文] )
如果兩個運算元不相等,則在第二個運算元的方向上返回最接近第一個運算元的數字。如果兩個運算元在數值上相等,則返回第一個運算元的副本,並將符號設定為與第二個運算元的符號相同。

2.6版本中的新功能。

normalize([ context ] )
通過汽提最右邊的尾隨零和轉換等於任何結果歸一化數Decimal('0')到 Decimal('0e0')。用於為等價類的屬性生成規範值。例如,Decimal('32.100')與 Decimal('0.321000e+2')兩個正常化為等效值 Decimal('32.1')。

number_class([ context ] )
返回描述運算元類的字串。返回的值是以下十個字串之一。

"-Infinity",表明運算元是負無窮大。
"-Normal",表明該運算元是一個負的正常數。
"-Subnormal"表明運算元是負數和低於正常的。
"-Zero",表明運算元是負零。
"+Zero",表明運算元是一個正的零。
"+Subnormal",表明運算元是正的和低於正常的。
"+Normal",表示運算元是正數。
"+Infinity",表明運算元是正無窮。
"NaN",表明運算元是一個安靜的NaN(不是數字)。
"sNaN",表明運算元是一個訊號NaN。
2.6版本中的新功能。

quantize(exp [,rounding [,context [,watchexp ] ] ] )
在舍入後返回一個等於第一個運算元並具有第二個運算元的指數的值。

>>> Decimal('1.41421356').quantize(Decimal('1.000'))
Decimal('1.414')
與其他操作不同,如果量化操作之後的係數長度大於精度,則會InvalidOperation發出an 訊號。這保證了,除非有錯誤條件,否則量化指數總是等於右側運算元的指數。

與其他操作不同,即使結果是次正常且不精確,量化也不會發出下溢訊號。

如果第二個運算元的指數大於第一個運算元的指數,則可能需要舍入。在這種情況下,舍入模式由rounding引數確定,如果給出,則由給定 context引數確定; 如果沒有給出引數,則使用當前執行緒上下文的舍入模式。

如果watchexp被設定(預設),那麼只要結果指數大於Emax或小於, 就會返回一個錯誤Etiny。

radix()
返回Decimal(10),Decimal 類中所有算術的基數(基數)。包括與規範的相容性。

2.6版本中的新功能。

remainder_near(其他[,上下文] )
從分返回,其餘自通過其他。這不同於 其餘部分的符號被選擇為使其絕對值最小化。更確切地說,返回值是 其中最接近的精確值的整數,如果兩個整數都同樣接近,則即使一個選擇。self % otherself - n * othernself / other

如果結果為零,那麼它的符號將是自我的標誌。

>>> Decimal(18).remainder_near(Decimal(10))
Decimal('-2')
>>> Decimal(25).remainder_near(Decimal(10))
Decimal('5')
>>> Decimal(35).remainder_near(Decimal(10))
Decimal('-5')
rotate(其他[,上下文] )
將第一個運算元的數字旋轉一個由第二個運算元指定的量的結果。第二個運算元必須是精度範圍-precision中的整數。第二個運算元的絕對值給出了要旋轉的地方的數量。如果第二個運算元是正的,那麼旋轉是在左邊; 否則旋轉是正確的。如有必要,第一個運算元的係數在左側填充為零以達到長度精度。第一個運算元的符號和指數保持不變。

2.6版本中的新功能。

same_quantum(其他[,上下文] )
測試自我和其他人是否有相同的指數或兩者是否都是 NaN。

scaleb(其他[,上下文] )
返回第一個運算元,指數由第二個調整。等價地,返回第一個運算元乘以10**other。第二個運算元必須是整數。

2.6版本中的新功能。

shift(其他[,上下文] )
返回將第一個運算元的數位移位第二個運算元指定的數值的結果。第二個運算元必須是精度範圍-precision中的整數。第二個運算元的絕對值給出了要移位的位數。如果第二個運算元是正的,那麼這個移位是在左邊; 否則這個轉變是在右邊。移入係數的數字是零。第一個運算元的符號和指數保持不變。

2.6版本中的新功能。

sqrt([ context ] )
將引數的平方根返回到完全精度。

to_eng_string([ context ] )
如果需要指數,則轉換為字串,使用工程符號。

工程符號的指數是3的倍數。這可以在小數點左邊留下最多3位數字,並且可能需要新增一個或兩個尾隨零。

例如,這轉換Decimal('123E+1')為Decimal('1.23E+3')。

to_integral([ rounding [,context ] ] )
與該to_integral_value()方法相同。該to_integral 名稱一直保持與舊版本的相容性。

to_integral_exact([ rounding [,context ] ] )
四捨五入到最接近的整數,發訊號Inexact或 Rounded酌情發生舍入。舍入模式由rounding給定的引數確定,否則由給定的引數 確定context。如果沒有給出引數,則使用當前上下文的舍入模式。

2.6版本中的新功能。

to_integral_value([ rounding [,context ] ] )
四捨五入到最接近的整數,無需訊號Inexact或 Rounded。如果給出,則適用四捨五入 ; 否則,在提供的上下文或當前上下文中使用舍入方法。

在版本2.6中更改:從重新命名to_integral為to_integral_value。舊名稱對於相容性仍然有效。

subprocess模組

https://docs.python.org/2/library/subprocess.html

subprocess.call(args, *, stdin=None, stdout=None, stderr=None, shell=False)

執行args描述的命令。等待命令完成,然後返回returncode屬性。

上面顯示的引數僅僅是最常用的引數,在下面的常用引數中進行了描述(因此縮寫簽名中的略帶奇數的記號)。完整的函式簽名與Popen建構函式的簽名相同- 該函式將所有提供的引數直接傳遞到該介面。
例子:

>>> subprocess.call(["ls", "-l"])
0

>>> subprocess.call("exit 1", shell=True)
1

警告:使用shell=True可能是安全隱患。執行包含來自不可信源的未經處理的輸入的shell命令會使程式容易受到shell注入的攻擊,這是一個嚴重的安全漏洞,可導致任意命令執行。在使用時shell=True,pipes.quote()可用於正確地轉義要用於構造shell命令的字串中的空白和shell元字元。

注意:不要使用stdout=PIPE或stderr=PIPE使用此功能,因為它可能會基於子程式輸出量導致死鎖。在需要管道時使用Popen該communicate()方法。

subprocess.check_call(args, *, stdin=None, stdout=None, stderr=None, shell=False)

帶引數執行命令。等待命令完成。如果返回碼為零,則返回,否則提升CalledProcessError。該 CalledProcessError物件將在returncode屬性中具有返回碼 。

例子:

>>> subprocess.check_call(["ls", "-l"])
0

>>> subprocess.check_call("exit 1", shell=True)
Traceback (most recent call last):
   ...
subprocess.CalledProcessError: Command 'exit 1' returned non-zero exit status 1
subprocess.check_output(args, *, stdin=None, stderr=None, shell=False, universal_newlines=False)

使用引數執行命令並將其輸出作為位元組字串返回。

如果返回程式碼不為零,則會引發一次CalledProcessError。該 CalledProcessError物件將在returncode屬性中具有返回碼,並在 屬性中包含任何輸出 output。

例子:

>>> subprocess.check_output(["echo", "Hello World!"])
'Hello World!\n'

>>> subprocess.check_output("exit 1", shell=True)
Traceback (most recent call last):
   ...
subprocess.CalledProcessError: Command 'exit 1' returned non-zero exit status 1

要在結果中捕獲標準錯誤,請使用 stderr=subprocess.STDOUT:

>>> subprocess.check_output(
...     "ls non_existent_file; exit 0",
...     stderr=subprocess.STDOUT,
...     shell=True)
'ls: non_existent_file: No such file or directory\n'

subprocess.PIPE
特殊值,可用作標準輸入,標準輸出或標準錯誤引數,Popen並指示應開啟標準流的管道。

subprocess.STDOUT
可以用作stderr引數的特殊值,Popen並指示標準錯誤應該與標準輸出進入相同的控制程式碼。

exception subprocess.CalledProcessError
當程式執行check_call()或 check_output()返回非零退出狀態時引發異常。

returncode
退出子程式的狀態。

cmd
用於產生子程式的命令。

output
子程式的輸出,如果這個異常被引發 check_output()。否則,None。

commands的使用

# 如果需求返回結果該模組提供了很好的方法
>>> import commands
>>> commands.getstatusoutput('ls /bin/ls')
(0, '/bin/ls')
>>> commands.getstatusoutput('cat /bin/junk')
(256, 'cat: /bin/junk: No such file or directory')
>>> commands.getstatusoutput('/bin/junk')
(256, 'sh: /bin/junk: not found')
>>> commands.getoutput('ls /bin/ls')
'/bin/ls'
>>> commands.getstatus('/bin/ls')
'-rwxr-xr-x 1 root 13352 Oct 14 1994 /bin/ls'

traceback模組

import traceback
try:
    1/0
except Exception,e:
    traceback.print_exc()
    

輸出結果是
Traceback (most recent call last):

    File "test_traceback.py", line 3, in <module>

        1/0

ZeroDivisionError: integer division or modulo by zero
這樣非常直觀有利於除錯。

traceback.print_exc()跟traceback.format_exc()有什麼區別呢?
format_exc()返回字串,print_exc()則直接給列印出來。
即traceback.print_exc()與print traceback.format_exc()效果是一樣的。
print_exc()還可以接受file引數直接寫入到一個檔案。比如
traceback.print_exc(file=open('tb.txt','w+'))
寫入到tb.txt檔案去。

hashlib提供常見的摘要演算法

import hashlib

md5 = hashlib.md5()
md5.update('how to use md5 in python hashlib?'.encode('utf-8'))
print(md5.hexdigest())

import hashlib

sha1 = hashlib.sha1()
sha1.update('how to use sha1 in '.encode('utf-8'))
sha1.update('python hashlib?'.encode('utf-8'))
print(sha1.hexdigest())


# 物件 = hashlib.加密演算法('字串')也可以這樣用

types判斷python物件型別

import types
In [3]: types.GeneratorType
Out[3]: generator

ctype的使用

官方網址 https://docs.python.org/2/library/ctypes.html

其他 https://www.cnblogs.com/rainduck/archive/2011/09/02/2163230.html

以下是Windows的一些示例。請注意,msvcrtMS標準C庫包含大多數標準C函式,並使用cdecl呼叫約定:

>>> from ctypes import *
>>> print windll.kernel32  
<WinDLL 'kernel32', handle ... at ...>
>>> print cdll.msvcrt      
<CDLL 'msvcrt', handle ... at ...>
>>> libc = cdll.msvcrt     
>>>
Windows會.dll自動附加通常的檔案字尾。

在Linux上,需要指定包含載入庫的副檔名的檔名,因此不能使用屬性訪問來載入庫。要麼使用LoadLibrary()dll載入器的方法,要麼 通過呼叫建構函式建立CDLL例項來載入庫:

>>> cdll.LoadLibrary("libc.so.6")  
<CDLL 'libc.so.6', handle ... at ...>
>>> libc = CDLL("libc.so.6")       
>>> libc                           
<CDLL 'libc.so.6', handle ... at ...>
>>>
ctypes型別c型別python型別
c_bool_Boolbool (1)
c_charchar1-character string
c_wcharwchar_t1-character unicode string
c_bytecharint/long
c_ubyteunsigned charint/long
c_shortshortint/long
c_ushortunsigned shortint/long
c_intintint/long
c_uintunsigned intint/long
c_longlong int/long
c_ulongunsigned longint/long
c_longlong__int64 or long longint/long
c_ulonglongunsigned __int64 or unsigned long longint/long
c_floatfloatfloat
c_doubledoublefloat
c_longdoublelong doublefloat
c_char_pchar * (NUL terminated)string or None
c_wchar_pwchar_t * (NUL terminated)unicode or None
c_void_pvoid *int/long or None
from ctypes import *

a=c_int * 10
print(a(1,2,3,4,5,6,7,8,9,10))
for i in a(1,2,3,4,5,6,7,8,9,10):
    print(i)

<__main__.c_long_Array_10 object at 0x0000000004AF5148>
1
2
3
4
5
6
7
8
9
10

struct模組中的函式及用法

函式returnexplain
pack(fmt,v1,v2…)string按照給定的格式(fmt),把資料轉換成字串(位元組流),並將該字串返回.
pack_into(fmt,buffer,offset,v1,v2…)None按照給定的格式(fmt),將資料轉換成字串(位元組流),並將位元組流寫入以offset開始的buffer中.(buffer為可寫的緩衝區,可用array模組)
unpack(fmt,v1,v2……)tuple按照給定的格式(fmt)解析位元組流,並返回解析結果
pack_from(fmt,buffer,offset)tuple按照給定的格式(fmt)解析以offset開始的緩衝區,並返回解析結果
calcsize(fmt)size of fmt計算給定的格式(fmt)佔用多少位元組的記憶體,注意對齊方式
struct對齊方式

為了同c中的結構體交換資料,還要考慮c或c++編譯器使用了位元組對齊,通常是以4個位元組為單位的32位系統,故而struct根據本地機器位元組順序轉換.可以用格式中的第一個字元來改變對齊方式.定義如下

CharacterByte orderSizeAlignment
@(預設)本機本機本機,湊夠4位元組
=本機標準none,按原位元組數
<小端標準none,按原位元組數
>大端標準none,按原位元組數
!network(大端)標準none,按原位元組數
struct格式符
格式符C語言型別Python型別Standard size
xpad byte(填充位元組) no value
ccharstring of length 11
bsigned charinteger1
Bunsigned charinteger1
?_Boolbool1
hshortinteger2
Hunsigned shortinteger2
iintinteger4
I(大寫的i)unsigned intinteger4
l(小寫的L)longinteger4
Lunsigned longlong4
qlong longlong8
Qunsigned long longlong8
ffloatfloat4
ddoublefloat8
schar[]string
pchar[]string
Pvoid *long
簡單使用
import struct
  
a = 20
b = 400
  
str = struct.pack("ii", a, b) 
#轉換後的str雖然是字串型別,但相當於其他語言中的位元組流(位元組陣列),可以在網路上傳輸
print 'length:', len(str)
print str
print repr(str)
  
#---- result
#length: 8
#  ----這裡是亂碼
#'/x14/x00/x00/x00/x90/x01/x00/x00'


str = struct.pack("ii", 20, 400)
a1, a2 = struct.unpack("ii", str)
print 'a1:', a1
print 'a2:', a2
  
#---- result:
#a1: 20
#a2: 400
struct.calcsize


import struct
from ctypes import create_string_buffer
  
buf = create_string_buffer(12)
print repr(buf.raw)
  
struct.pack_into("iii", buf, 0, 1, 2, -1)
print repr(buf.raw)
  
print struct.unpack_from('iii', buf, 0)
  
#---- result
#'/x00/x00/x00/x00/x00/x00/x00/x00/x00/x00/x00/x00'
#'/x01/x00/x00/x00/x02/x00/x00/x00/xff/xff/xff/xff'
#(1, 2, -1)


# 有符號轉無符號
e=-641881654
a=struct.pack('i',e)
struct.unpack('I',a)

迭代器

  1. 通過可迭代物件的__iter__() 返回的
  2. 有__next__() next
  3. StopIteration
class Iterable:
    def __iter__(self):
        return self
    def __init__(self):
        self.start=-1
    def __next__(self):
        self.start +=2
        if self.start >10:
            raise StopIteration
        return self.start
        
# py3
[1,2,3,4].__iter__().__next__()
# py2
[1,2,3,4].__iter__().next()

生成器

  1. 生成器(generator)是特殊的迭代器,函式中有yield關鍵字就是生成器
  2. 建立方法:函式、生成器表示式
  3. 原生的資料結構:列表、字串、元組、字典,range、xrange
    (py3的range=py2的xrange)
def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        yield b
        a, b = b, a + b
        n = n + 1

異常描述
BaseException所有異常的基類
SystemExit直譯器請求退出
KeyboardInterrupt使用者中斷執行(通常是輸入^C)
Exception常規錯誤的基類
StopIteration迭代器沒有更多的值
GeneratorExit生成器(generator)發生異常來通知退出
StandardError所有的內建標準異常的基類
ArithmeticError所有數值計算錯誤的基類
FloatingPointError浮點計算錯誤
OverflowError數值運算超出最大限制
ZeroDivisionError除(或取模)零 (所有資料型別)
AssertionError斷言語句失敗
AttributeError物件沒有這個屬性
EOFError沒有內建輸入,到達EOF 標記
EnvironmentError作業系統錯誤的基類
IOError輸入/輸出操作失敗
OSError作業系統錯誤
WindowsError系統呼叫失敗
ImportError匯入模組/物件失敗
LookupError無效資料查詢的基類
IndexError序列中沒有此索引(index)
KeyError對映中沒有這個鍵
MemoryError記憶體溢位錯誤(對於Python 直譯器不是致命的)
NameError未宣告/初始化物件 (沒有屬性)
UnboundLocalError訪問未初始化的本地變數
ReferenceError弱引用(Weak reference)試圖訪問已經垃圾回收了的物件
RuntimeError一般的執行時錯誤
NotImplementedError尚未實現的方法
SyntaxError Python語法錯誤
IndentationError縮排錯誤
TabError Tab和空格混用
SystemError一般的直譯器系統錯誤
TypeError對型別無效的操作
ValueError傳入無效的引數
UnicodeError Unicode相關的錯誤
UnicodeDecodeError Unicode解碼時的錯誤
UnicodeEncodeError Unicode編碼時錯誤
UnicodeTranslateError Unicode轉換時錯誤
Warning警告的基類
DeprecationWarning關於被棄用的特徵的警告
FutureWarning關於構造將來語義會有改變的警告
OverflowWarning舊的關於自動提升為長整型(long)的警告
PendingDeprecationWarning關於特性將會被廢棄的警告
RuntimeWarning可疑的執行時行為(runtime behavior)的警告
SyntaxWarning可疑的語法的警告
UserWarning使用者程式碼生成的警告

檢測和處理異常

# 在python中使用try捕獲異常,except處理異常.
# 捕獲異常和處理異常通常同時使用
try:
    需要監控的程式碼塊
except Exception as e:
    print(e)

# 也可以多個except,處理指定異常
try:
    需要監控的程式碼塊
except ValueError:
    pass
except TypeError:
    pass

# 當條件不滿足時可以執行else,無論之前的條件滿不滿足都會執行finally
try:
    需要監控的程式碼塊
except:
    pass
else:
    pass
finally:
    pass

自定義異常

class 自定義異常(Exception):
    '''只需要重寫父類的init方法就可以'''
    def __init__(self,err='erro'):
        Exception.__init__(self,err)
        
def test():
    '''手動丟擲異常'''
    raise 自定義異常

try:
    test()
except 自定義異常 as e:
    print(e)

斷言

  1. assert語句用來宣告某個條件是真的。
  2. 如果你非常確信某個你使用的列表中至少有一個元素,而你想要檢驗這一點,並且在它非真的時候引發一個錯誤,那麼assert語句是應用在這種情形下的理想語句。
  3. 當assert語句失敗的時候,會引發AssertionError異常。
assert 表示式 [, 引數]

def foo(s):
    n = int(s)
    assert n != 0, 'n is zero!'
    return 10 / n

def main():
    foo('0')
    
$ python err.py
Traceback (most recent call last):
  ...
AssertionError: n is zero!

打斷點

啟動Python的偵錯程式pdb,讓程式以單步方式執行,可以隨時檢視執行狀態。我們先準備好程式:

# err.py
s = '0'
n = int(s)
print(10 / n)

然後啟動:

$ python -m pdb err.py
> /Users/michael/Github/learn-python3/samples/debug/err.py(2)<module>()
-> s = '0'
# 這種通過pdb在命令列除錯的方法理論上是萬能的,但實在是太麻煩了,如果有一千行程式碼,要執行到第999行得敲多少命令啊。還好,我們還有另一種除錯方法。

pdb.set_trace()

這個方法也是用pdb,但是不需要單步執行,我們只需要import pdb,然後,在可能出錯的地方放一個pdb.set_trace(),就可以設定一個斷點:

# err.py
import pdb

s = '0'
n = int(s)
pdb.set_trace() # 執行到這裡會自動暫停
print(10 / n)

單元測試

import unittest

class TestDict(unittest.TestCase):

    def setUp(self):
        '''建構函式'''
        print('setUp...')
        
    def test_func(self):
        pass

    def tearDown(self):
        '''解構函式'''
        print('tearDown...')
        
        
if __name__ == '__main__':
    unittest.main()
    
# 編寫單元測試時,我們需要編寫一個測試類,從unittest.TestCase繼承。

# 以test開頭的方法就是測試方法,不以test開頭的方法不被認為是測試方法,測試的時候不會被執行。

# 對每一類測試都需要編寫一個test_xxx()方法。由於unittest.TestCase提供了很多內建的條件判斷,我們只需要呼叫這些方法就可以斷言輸出是否是我們所期望的。最常用的斷言就是assertEqual():

self.assertEqual(abs(-1), 1) # 斷言函式返回的結果與1相等

# 另一種重要的斷言就是期待丟擲指定型別的Error,比如通過d['empty']訪問不存在的key時,斷言會丟擲KeyError:

with self.assertRaises(KeyError):
    value = d['empty']

#而通過d.empty訪問不存在的key時,我們期待丟擲AttributeError:

with self.assertRaises(AttributeError):
    value = d.empty

函式

  • 函數語言程式設計
  • 位置引數、關鍵字引數、預設引數、非關鍵字可變長引數(元組)*args、關鍵字變數引數(字典)**kwargs、全域性變數global關鍵字、內嵌函式
  • 閉包,訪問閉包外層的變數使用nonlocal關鍵字
    • 內層函式引用外層函式的變數(引數也算變數),然後返回內層函式的情況稱為閉包
def func():
    def func2():
        return
    return func
  • 裝飾器,訪問外層的變數使用nonlocal關鍵字
# import functools
def wapper(func):
    # @functools.wraps(func)#修飾內層函式,以防止當前裝飾器去修改被裝飾函式的__name__屬性
    def inner():
        return func(*args,**kwargs)
    return inner

@wapper
def func():
    return

高階函式

廖雪峰的網站

map():函式接收兩個引數,一個是函式,一個是Iterable,map將傳入的函式依次作用到序列的每個元素,並把結果作為新的Iterator返回。

def f(x):
    return x * x

r = map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])
list(r)
[1, 4, 9, 16, 25, 36, 49, 64, 81]

reduce:把一個函式作用在一個序列[x1, x2, x3, …]上,這個函式必須接收兩個引數,reduce把結果繼續和序列的下一個元素做累積計算

from functools import reduce
def add(x, y):
    return x + y

reduce(add, [1, 3, 5, 7, 9])
25

filter():也接收一個函式和一個序列。和map()不同的是,filter()把傳入的函式依次作用於每個元素,然後根據返回值是True還是False決定保留還是丟棄該元素。

def is_odd(n):
    return n % 2 == 1

list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15]))
# 結果: [1, 5, 9, 15]

sorted():函式也是一個高階函式,它還可以接收一個key函式來實現自定義的排序

sorted([36, 5, -12, 9, -21], key=abs)
[5, 9, -12, -21, 36]

偏函式

# 簡單總結functools.partial的作用就是,把一個函式的某些引數給固定住(也就是設定預設值),返回一個新的函式,呼叫這個新函式會更簡單。
>>> import functools
>>> int2 = functools.partial(int, base=2)
>>> int2('1000000')
64
>>> int2('1010101')
85
# 自己寫一個偏函式
class partial:
    def __new__(cls, func, *args, **kwargs):
        if not callable(func):
            raise TypeError("the first argument must be callable")
        self = super().__new__(cls)

        self.func = func
        self.args = args
        self.kwargs = kwargs
        return self

   def __call__(self, *args, **kwargs):
        newkeywords = self.kwargs.copy()
        newkeywords.update(kwargs)
        return self.func(*self.args, *args, **newkeywords)
        
        
# 使用:
def add(x, y):
    return x + y

inc = partial(add, y=1)
print(inc(41))  # 42

StringIO與BytesIO

>>> from io import StringIO
>>> f = StringIO()
>>> f.write('hello')
5
>>> f.write(' ')
1
>>> f.write('world!')
6
>>> print(f.getvalue())
hello world!
# getvalue()方法用於獲得寫入後的str。


# 要讀取StringIO,可以用一個str初始化StringIO,然後,像讀檔案一樣讀取:

>>> from io import StringIO
>>> f = StringIO('Hello!\nHi!\nGoodbye!')
>>> while True:
...     s = f.readline()
...     if s == '':
...         break
...     print(s.strip())
...
Hello!
Hi!
Goodbye!

# StringIO操作的只能是str,如果要操作二進位制資料,就需要使用BytesIO。

# BytesIO實現了在記憶體中讀寫bytes,我們建立一個BytesIO,然後寫入一些bytes:

>>> from io import BytesIO
>>> f = BytesIO()
>>> f.write('中文'.encode('utf-8'))
6
>>> print(f.getvalue())
b'\xe4\xb8\xad\xe6\x96\x87'

# 請注意,寫入的不是str,而是經過UTF-8編碼的bytes。

# 和StringIO類似,可以用一個bytes初始化BytesIO,然後,像讀檔案一樣讀取:

>>> from io import BytesIO
>>> f = BytesIO(b'\xe4\xb8\xad\xe6\x96\x87')
>>> f.read()
b'\xe4\xb8\xad\xe6\x96\x87'


import和__import__(str)呼叫模組不同

globals()和locals()檢視全域性和區域性名稱空間
reload(model)重新匯入已經匯入的模組

物件導向程式設計

在python中類是用來建立物件的

  • 私有的屬性,不能通過物件直接訪問,但是可以通過方法訪問
  • 私有的方法,不能通過物件直接訪問
  • 私有的屬性、方法,不會被子類繼承,也不能被訪問
  • 一般情況下,私有的屬性、方法都是不對外公佈的,往往用來做內部的事情,起到安全的作用
  • 父類中的 私有方法、屬性,不會被子類繼承
  • 可以通過呼叫繼承的父類的共有方法,間接的訪問父類的私有方法、屬性
class Myobj(object):
    '''定義類,所有私有屬性和方法都不會被繼承,私有屬性不能直接被例項物件呼叫'''
    __私有類屬性 = None
    類屬性 = None
    country = 'china'
    def __init__(self,*args,**kwargs):
        '''定義構造方法,初始化例項屬性'''
        self.name = None
        self._受保護的屬性= None
        self.__私有屬性= None
        
    def __str__(self):
        """返回一個物件的描述資訊"""
        return '輸出%s'%self.name
    
    def method(self):
        print('我的方法')
        
    def __私有方法(self):
        return
        
    def __del__(self):
        '''析構方法,當物件被刪除時自動呼叫'''
        print('end')
        
    @classmethod
    def getCountry(cls):
        '''類方法'''
        return cls.country
        
    @staticmethod
    def getCountry():
        '''靜態方法'''
        return People.country
        
class 子類(Myobj):
    '''子類可以繼承一個或多個父類,相同屬性會優先呼叫第一個父類,如果子類建立了和父類一樣方法和屬性會重寫父類的該方法或屬性'''
    pass

# 類訪問類方法
Myobj().getCountry
# 類訪問例項方法
Myobj().method()
# 例項化物件
obj=Myobj()
# 例項物件訪問例項屬性
obj.method()

# 寫入屬性
obj.__setattr__('mv',2)
# 獲取屬性
print(obj.__getattribute__('mv'))


# python還提供了一種為了達到限制的目的,允許在定義class的時候,定義一個特殊的__slots__變數,來限制該class例項能新增的屬性:

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

>>> s = Student() # 建立新的例項
>>> s.name = 'Michael' # 繫結屬性'name'
>>> s.age = 25 # 繫結屬性'age'
>>> s.score = 99 # 繫結屬性'score'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute 'score'


# 定製類
# __len__()方法我們也知道是為了能讓class作用於len()函式。
# 兩者的區別是__str__()返回使用者看到的字串,而__repr__()返回程式開發者看到的字串,也就是說,__repr__()是為除錯服務的。
# 通常__str__()和__repr__()程式碼都是一樣的,所以,有個偷懶的寫法:
class Student(object):
    def __init__(self, name):
        self.name = name
    def __str__(self):
        return 'Student object (name=%s)' % self.name
    __repr__ = __str__
    
    
# 要表現得像list那樣按照下標取出元素,需要實現__getitem__()方法:  
class Fib(object):
    def __getitem__(self, n):
        if isinstance(n, int): # n是索引
            a, b = 1, 1
            for x in range(n):
                a, b = b, a + b
            return a
        if isinstance(n, slice): # n是切片
            start = n.start
            stop = n.stop
            if start is None:
                start = 0
            a, b = 1, 1
            L = []
            for x in range(stop):
                if x >= start:
                    L.append(a)
                a, b = b, a + b
            return L
            
>>> f = Fib()
>>> f[0:5]
[1, 1, 2, 3, 5]
>>> f[:10]
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]


# 列舉類
from enum import Enum

Month = Enum('Month', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))


from enum import Enum, unique

@unique
class Weekday(Enum):
    Sun = 0 # Sun的value被設定為0
    Mon = 1
    Tue = 2
    Wed = 3
    Thu = 4
    Fri = 5
    Sat = 6
# @unique裝飾器可以幫助我們檢查保證沒有重複值。

工廠模式

class Person:
    # 工廠模式父類只定義屬性和基本方法
    def __init__(self):
        self.name = None
        self.gender = None

    def getName(self):
        return self.name

    def getGender(self):
        return self.gender

class Male(Person):
    def __init__(self, name):
        print "Hello Mr." + name

class Female(Person):
    def __init__(self, name):
        print "Hello Miss." + name

class Factory:
    # 實際最後執行的都是子類
    def getPerson(self, name, gender):
        if gender == ‘M':
            return Male(name)
        if gender == 'F':
            return Female(name)

if __name__ == '__main__':
    factory = Factory()
    person = factory.getPerson("Chetan", "M")

單例模式

class Singleton(object):
    def __init__(self,*args,**kwargs):
        pass
    @classmethod
    def get_instance(cls, *args, **kwargs):
        # 利用反射,看看這個類有沒有_instance屬性
        if not hasattr(Singleton, '_instance'):
            Singleton._instance = Singleton(*args, **kwargs)
        return Singleton._instance
        
# 使用裝飾器建立單例
def singleton(cls):
    instance = {}
    def _singleton(*args, **kwargs):
        if cls not in instance:
            instance[cls] = cls(*args, **kwargs)
        return instance[cls]
    return _singleton

如果一個檔案中有__all__變數,那麼也就意味著這個變數中的元素,不會被from xxx import *時匯入

__all__ = ['類名','函式名']

元類

# 我們說class的定義是執行時動態建立的,而建立class的方法就是使用type()函式。
Hello = type('Hello', (object,), dict(hello=fn)) # 建立Hello class

# metaclass是建立類,所以必須從`type`型別派生:
class ListMetaclass(type):
    def __new__(cls, name, bases, attrs):
        attrs['add'] = lambda self, value: self.append(value)
        return type.__new__(cls, name, bases, attrs)

class MyList(list):
    __metaclass__ = ListMetaclass # 指示使用ListMetaclass來定製類

網路程式設計

udp協議

from socket import socket
# 建立套接字
udp_socket=socket(AF_INET,SOCK_DGRAM)
# 繫結埠
udp_socket.bind(('',port))
# 設定廣播
udp_socket.setsockopt(SOL_SOCKET,SO_BROADCAST,1)
# 傳送訊息
udp_socket.sendto('訊息'.encode('gbk'),('目標ip',))
# 接收訊息
接收的資料,地址=udp_socket.recvfrom(位元組數)
接收的資料.decode('gbk')

tcp協議

# tcp客戶端
from socket import socket
# 建立套接字
tcp_client=socket(AF_INET,SOCK_STREAM)
# 連線伺服器
tcp_client.connect(('伺服器ip',伺服器port))
# 傳送資料
tcp_client.send('訊息'.encode('gbk'))
# 關閉連線
tcp_client.close()
# tcp服務端
from socket import socket
# 建立套接字
tcp_server=socket(AF_INET,SOCK_STREAM)
# 地址重用
tcp_server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
# 繫結地址
tcp_server.bind(('',7788))
# 使用socket建立的套接字預設的屬性是主動的,使用listen將其變為被動的,這樣就可以接收別人的連結了
tcp_server.listen(128)
# 接收連線
客戶連線,客戶地址=tcp_server.accept()
# 接收資料
資料=客戶連線,recv(位元組)
# 傳送資料
客戶連線.send('資料'.encode('gbk'))
# 關閉連線
客戶連線.close()

Socket內建方法

函式描述
s.bind()繫結地址(host,port)到套接字, 在AF_INET下,以元組(host,port)的形式表示地址。
s.listen()開始TCP監聽。backlog指定在拒絕連線之前,作業系統可以掛起的最大連線數量。該值至少為1,大部分應用程式設為5就可以了。
s.accept()被動接受TCP客戶端連線,(阻塞式)等待連線的到來
s.connect()主動初始化TCP伺服器連線,。一般address的格式為元組(hostname,port),如果連線出錯,返回socket.error錯誤。
s.connect_ex()connect()函式的擴充套件版本,出錯時返回出錯碼,而不是丟擲異常
s.recv()接收TCP資料,資料以字串形式返回,bufsize指定要接收的最大資料量。flag提供有關訊息的其他資訊,通常可以忽略。
s.send()傳送TCP資料,將string中的資料傳送到連線的套接字。返回值是要傳送的位元組數量,該數量可能小於string的位元組大小。
s.sendall()完整傳送TCP資料,完整傳送TCP資料。將string中的資料傳送到連線的套接字,但在返回之前會嘗試傳送所有資料。成功返回None,失敗則丟擲異常。
s.recvfrom()接收UDP資料,與recv()類似,但返回值是(data,address)。其中data是包含接收資料的字串,address是傳送資料的套接字地址。
s.sendto()傳送UDP資料,將資料傳送到套接字,address是形式為(ipaddr,port)的元組,指定遠端地址。返回值是傳送的位元組數。
s.close()關閉套接字
s.getpeername()返回連線套接字的遠端地址。返回值通常是元組(ipaddr,port)。
s.getsockname()返回套接字自己的地址。通常是一個元組(ipaddr,port)
s.setsockopt(level,optname,value)設定給定套接字選項的值。
s.getsockopt(level,optname[.buflen])返回套接字選項的值。
s.settimeout(timeout)設定套接字操作的超時期,timeout是一個浮點數,單位是秒。值為None表示沒有超時期。一般,超時期應該在剛建立套接字時設定,因為它們可能用於連線的操作(如connect())
s.gettimeout()返回當前超時期的值,單位是秒,如果沒有設定超時期,則返回None。
s.fileno()返回套接字的檔案描述符。
s.setblocking(flag)如果flag為0,則將套接字設為非阻塞模式,否則將套接字設為阻塞模式(預設值)。非阻塞模式下,如果呼叫recv()沒有發現任何資料,或send()呼叫無法立即傳送資料,那麼將引起socket.error異常。
s.makefile()建立一個與該套接字相關連的檔案

setsockopt(level,optname,value)

選項意義期望值
SO_BINDTODEVICE可以使socket只在某個特殊的網路介面(網路卡)有效。也許不能是移動便攜裝置一個字串給出裝置的名稱或者一個空字串返回預設值
SO_BROADCAST允許廣播地址傳送和接收資訊包。只對UDP有效。如何傳送和接收廣播資訊包布林型整數
SO_DONTROUTE禁止通過路由器和閘道器往外傳送資訊包。這主要是為了安全而用在乙太網上UDP通訊的一種方法。不管目的地址使用什麼IP地址,都可以防止資料離開本地網路布林型整數
SO_KEEPALIVE可以使TCP通訊的資訊包保持連續性。這些資訊包可以在沒有資訊傳輸的時候,使通訊的雙方確定連線是保持的布林型整數
SO_OOBINLINE可以把收到的不正常資料看成是正常的資料,也就是說會通過一個標準的對recv()的呼叫來接收這些資料布林型整數
SO_REUSEADDR當socket關閉後,本地端用於該socket的埠號立刻就可以被重用。通常來說,只有經過系統定義一段時間後,才能被重用。布林型整數

三次握手

  • 第一次握手:建立連線時,客戶端傳送syn包(syn=j)到伺服器,並進入SYN_SENT狀態,等待伺服器確認;SYN:同步序列編號(Synchronize Sequence Numbers)。
  • 第二次握手:伺服器收到syn包,必須確認客戶的SYN(ack=j+1),同時自己也傳送一個SYN包(syn=k),即SYN+ACK包,此時伺服器進入SYN_RECV狀態;
  • 第三次握手:客戶端收到伺服器的SYN+ACK包,向伺服器傳送確認包ACK(ack=k+1),此包傳送完畢,客戶端和伺服器進入ESTABLISHED(TCP連線成功)狀態,完成三次握手。

四次揮手

  • 第一步,當主機A的應用程式通知TCP資料已經傳送完畢時,TCP向主機B傳送一個帶有FIN附加標記的報文段(FIN表示英文finish)。
  • 第二步,主機B收到這個FIN報文段之後,並不立即用FIN報文段回覆主機A,而是先向主機A傳送一個確認序號ACK,同時通知自己相應的應用程式:對方要求關閉連線(先傳送ACK的目的是為了防止在這段時間內,對方重傳FIN報文段)。
    -第三步,主機B的應用程式告訴TCP:我要徹底的關閉連線,TCP向主機A送一個FIN報文段。
    -第四步,主機A收到這個FIN報文段後,向主機B傳送一個ACK表示連線徹底釋放。
標誌中文名描述
URG緊急標誌緊急(The urgent pointer) 標誌有效。緊急標誌置位
ACK確認標誌確認編號(Acknowledgement Number)欄有效。大多數情況下該標誌位是置位的.
TCP報頭內的確認編號欄內包含的確認編號(w+1,Figure:1)為下一個預期的序列編號,同時提示遠端系統已經成功接收所有資料。
PSH推標誌該標誌置位時,接收端不將該資料進行佇列處理,而是儘可能快將資料轉由應用處理。在處理 telnet 或 rlogin 等互動模式的連線時,該標誌總是置位的。
RST復位標誌復位標誌有效。用於復位相應的TCP連線。
SYN同步標誌同步序列編號(Synchronize Sequence Numbers)欄有效。該標誌僅在三次握手建立TCP連線時有效。它提示TCP連線的服務端檢查序列編號,該序列編號為TCP連線初始端(一般是客戶端)的初始序列編號。在這裡,可以把TCP序列編號看作是一個範圍從0到4,294,967,295的32位計數器。通過TCP連線交換的資料中每一個位元組都經過序列編號。在TCP報頭中的序列編號欄包括了TCP分段中第一個位元組的序列編號。
FIN結束標誌帶有該標誌置位的資料包用來結束一個TCP回話,但對應埠仍處於開放狀態,準備接收後續資料。
服務端處於監聽狀態,客戶端用於建立連線請求的資料包(IP packet)按照TCP/IP協議堆疊組合成為TCP處理的分段(segment)。

高階I / O複用selectors

https://docs.python.org/3/library/selectors.html

import selectors
import socket

sel = selectors.DefaultSelector()

def accept(sock, mask):
    conn, addr = sock.accept()  # Should be ready
    print('accepted', conn, 'from', addr)
    conn.setblocking(False)
    sel.register(conn, selectors.EVENT_READ, read)

def read(conn, mask):
    data = conn.recv(1000)  # Should be ready
    if data:
        print('echoing', repr(data), 'to', conn)
        conn.send(data)  # Hope it won't block
    else:
        print('closing', conn)
        sel.unregister(conn)
        conn.close()

sock = socket.socket()
sock.bind(('localhost', 1234))
sock.listen(100)
sock.setblocking(False)
sel.register(sock, selectors.EVENT_READ, accept)

while True:
    events = sel.select()
    for key, mask in events:
        callback = key.data
        callback(key.fileobj, mask)

多工

threading模組

threading模組物件描述
Thread表示一個執行緒的執行的物件
Lock鎖原語物件(跟thread模組裡的鎖物件相同)
RLock可重入鎖物件。使單執行緒可以再次獲得已經獲得了的鎖(遞迴鎖定)
Condition條件變數物件能讓一個執行緒停下來,等待其他執行緒滿足了某個“條件”。如狀態的改變或值的改變
Event通用的條件變數。多個執行緒可以等待某個時間的發生,在事件發生後,所有的執行緒都被啟用
Semaphore為等待鎖的執行緒提供一個類似“等候室”的結構
BoundedSemaphore與Semaphore類似,只是它不允許超過初始值
Timer與thread類似,只是它要等待一段時間後才開始執行
start()開始執行緒的執行
run()定義執行緒的功能的函式(一般會被子類重寫)
join(timeout=None)程式掛起,直到執行緒結束;如果給了timeout,則最多阻塞timeout秒
getName()返回執行緒的名字
setName(name)設定執行緒的名字
isAlive()布林標誌,表示這個執行緒是否還在執行中
isDaemon()返回執行緒的daemon標誌
setDaemon(daemonic)把執行緒的daemon標誌設為daemonic(一定要在呼叫start()函式前呼叫)
currentThread()返回當前的執行緒變數
enumerate()返回一個包含正在執行的執行緒的list。正在執行指執行緒啟動後、結束前,不包括啟動前和終止後的執行緒
activeCount()返回正在執行的執行緒數量,與len(threading.enumerate())有相同的結果

執行緒

# 執行緒是程式中執行的最小單位
import threading
import time

def saySorry():
    print("親愛的,我錯了,我能吃飯了嗎?")
    time.sleep(1)

if __name__ == "__main__":
    for i in range(5):
        t = threading.Thread(target=saySorry)
        t.start() #啟動執行緒,即讓執行緒開始執行

重寫run方法和執行緒鎖

import threading
import time
 
class myThread (threading.Thread):
    def __init__(self, threadID, name, counter):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.name = name
        self.counter = counter
    def run(self):
        print "Starting " + self.name
       # 獲得鎖,成功獲得鎖定後返回True
       # 可選的timeout引數不填時將一直阻塞直到獲得鎖定
       # 否則超時後將返回False
        threadLock.acquire()
        print_time(self.name, self.counter, 3)
        # 釋放鎖
        threadLock.release()
 
def print_time(threadName, delay, counter):
    while counter:
        time.sleep(delay)
        print "%s: %s" % (threadName, time.ctime(time.time()))
        counter -= 1
 
threadLock = threading.Lock()
threads = []
 
# 建立新執行緒
thread1 = myThread(1, "Thread-1", 1)
thread2 = myThread(2, "Thread-2", 2)
 
# 開啟新執行緒
thread1.start()
thread2.start()
 
# 新增執行緒到執行緒列表
threads.append(thread1)
threads.append(thread2)
 
# 等待所有執行緒完成
for t in threads:
    t.join()
print "Exiting Main Thread"

多程式

# 程式是系統分配資源的最小單位
from multiprocessing import Process
import os

# 子程式要執行的程式碼
def run_proc(name):
    print 'Run child process %s (%s)...' % (name, os.getpid())

if __name__=='__main__':
    print 'Parent process %s.' % os.getpid()
    p = Process(target=run_proc, args=('test',))
    print 'Process will start.'
    p.start()
    # 主程式等待子程式
    p.join()
    # 守護程式
    # p.daemon=True
    print 'Process end.'
程式池
from multiprocessing import Pool
import os, time, random

def 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.'

各種池

程式
import logging
from multiprocessing import Pool
from multiprocessing import Process,Manager


class Test():

    def __init__(self):
        self.pool = Pool()

    def task(self):
        print('func')

    def _err(self, ex):
        try:
            raise ex
        except:
            logging.exception(ex)

    def main(self):
        self.pool.apply_async(self.task, error_callback=self._err)
        # self.pool.apply_async(self.task)
        # self.pool.apply_async(self.task)
        # self.pool.apply_async(self.task)
        self.pool.close()
        self.pool.join()


t = Test()
t.main()
執行緒
import logging
import time
import threading
from multiprocessing.dummy import Pool  # 執行緒池
# from multiprocessing import Pool  # 程式池


def func():
    print(threading.current_thread().name)
    time.sleep(0.5)
    print('func')
    # raise Exception('123')
    return 'ok'

def func2():
    time.sleep(0.3)
    print('func2')

def func3():
    time.sleep(0.1)
    print('func3')

def func4():
    time.sleep(0)
    print('func4')

p = Pool(5)
# 同步執行
# p.apply(func)
# p.apply(func2)
# p.apply(func3)
# p.apply(func4)
# p.close()
# p.join()

def callback(temp):
    print(threading.current_thread().name)
    print(temp)

def error_callback(temp):
    print(threading.current_thread().name)
    try:
        raise temp
    except:
        logging.exception(temp)


print(threading.current_thread().name)
# 非同步執行
p.apply_async(func, callback=callback, error_callback=error_callback)
p.apply_async(func, callback=callback, error_callback=error_callback)
p.apply_async(func, callback=callback, error_callback=error_callback)
p.apply_async(func, callback=callback, error_callback=error_callback)

# p.apply_async(func2)
# p.apply_async(func3)
# p.apply_async(func4)
while True:
    time.sleep(0.0001)

p.close()
p.join()
協程
from gevent.pool import  Pool


def func():
    print('func')
    raise Exception('ok')


class Gpool(Pool):

    def apply_async(self, func, args=None, kwds=None, callback=None, error_callback=None):
        super().apply_async(func, args=None, kwds=None, callback=None)

    def cloase(self):
        pass


p = Gpool()
p.apply_async(func, error_callback='asdasd')
p.apply_async(func)
p.apply_async(func)
p.apply_async(func)
p.apply_async(func)
p.join()
程式間通訊
from multiprocessing import Process, Queue
import os, time, random

# 寫資料程式執行的程式碼:
def write(q):
    for value in ['A', 'B', 'C']:
        print 'Put %s to queue...' % value
        q.put(value)
        time.sleep(random.random())

# 讀資料程式執行的程式碼:
def read(q):
    while True:
        value = q.get(True)
        print 'Get %s from queue.' % value

if __name__=='__main__':
    # 父程式建立Queue,並傳給各個子程式:
    q = Queue()
    pw = Process(target=write, args=(q,))
    pr = Process(target=read, args=(q,))
    # 啟動子程式pw,寫入:
    pw.start()
    # 啟動子程式pr,讀取:
    pr.start()
    # 等待pw結束:
    pw.join()
    # pr程式裡是死迴圈,無法等待其結束,只能強行終止:
    pr.terminate()

程式池通訊

from multiprocessing import Manager,Pool
import os,time,random

def reader(q):
    print("reader啟動(%s),父程式為(%s)" % (os.getpid(), os.getppid()))
    for i in range(q.qsize()):
        print("reader從Queue獲取到訊息:%s" % q.get(True))

def writer(q):
    print("writer啟動(%s),父程式為(%s)" % (os.getpid(), os.getppid()))
    for i in "itcast":
        q.put(i)

if __name__=="__main__":
    print("(%s) start" % os.getpid())
    q = Manager().Queue()  # 使用Manager中的Queue
    po = Pool()
    po.apply_async(writer, (q,))

    time.sleep(1)  # 先讓上面的任務向Queue存入資料,然後再讓下面的任務開始從中取資料

    po.apply_async(reader, (q,))
    po.close()
    po.join()
    print("(%s) End" % os.getpid())

或者from queue import Queue建立佇列

另一種多執行緒
from multiprocessing.dummy import Pool as ThreadPool #執行緒池
# 開4個 worker,沒有引數時預設是 cpu 的核心數  
pool = ThreadPool(4)  
# 線上程中執行 urllib2.urlopen(url) 並返回執行結果
results2 = pool.map(urllib2.urlopen, urls)
# 列印執行緒名
print(threading.current_thread().name)
pool.close()  
pool.join()  


from multiprocessing.dummy import Pool
p=Pool()
# 同步執行
p.apply(func)
# 非同步執行
p.apply_async(func,callback=callback ,error_callback=callback_func) # 回撥函式不能有耗時操作否則會阻塞
p.close()
p.join()
安全的多執行緒
import threading

# 建立全域性ThreadLocal物件:
local_school = threading.local()

def process_student():
    # 獲取當前執行緒關聯的student:
    std = local_school.student
    print('Hello, %s (in %s)' % (std, threading.current_thread().name))

def process_thread(name):
    # 繫結ThreadLocal的student:
    local_school.student = name
    process_student()

t1 = threading.Thread(target= process_thread, args=('Alice',), name='Thread-A')
t2 = threading.Thread(target= process_thread, args=('Bob',), name='Thread-B')
t1.start()
t2.start()
t1.join()
t2.join()
# 一個ThreadLocal變數雖然是全域性變數,但每個執行緒都只能讀寫自己執行緒的獨立副本,互不干擾。ThreadLocal解決了引數在一個執行緒中各個函式之間互相傳遞的問題。
# ThreadLocal最常用的地方就是為每個執行緒繫結一個資料庫連線,HTTP請求,使用者身份資訊等,這樣一個執行緒的所有呼叫到的處理函式都可以非常方便地訪問這些資源。
協程

協程又稱微執行緒,是手動控制的執行緒

  • 協程yield
import time

def work1():
    while True:
        print("----work1---")
        yield
        time.sleep(0.5)

def work2():
    while True:
        print("----work2---")
        yield
        time.sleep(0.5)

def main():
    w1 = work1()
    w2 = work2()
    while True:
        next(w1)
        next(w2)

if __name__ == "__main__":
    main()
  • 協程greenlet
from greenlet import greenlet
import time

def test1():
    while True:
        print "---A--"
        gr2.switch()
        time.sleep(0.5)

def test2():
    while True:
        print "---B--"
        gr1.switch()
        time.sleep(0.5)

gr1 = greenlet(test1)
gr2 = greenlet(test2)

#切換到gr1中執行
gr1.switch()
  • 協程gevent
from gevent import monkey
import gevent
import random
import time

# 有耗時操作時需要
monkey.patch_all()  # 將程式中用到的耗時操作的程式碼,換為gevent中自己實現的模組

def coroutine_work(coroutine_name):
    for i in range(10):
        print(coroutine_name, i)
        time.sleep(random.random())

gevent.joinall([
        gevent.spawn(coroutine_work, "work1"),
        gevent.spawn(coroutine_work, "work2")
])
  • 協程池
import gevent
from gevent import monkey
monkey.patch_all()

from gevent.pool import Pool as BasePool


class Pool(BasePool):

    def apply_async(self, func, args=None, kwds=None, callback=None, error_callback=None):
        super().apply_async(func, args=args, kwds=kwds, callback=callback)

    def close(self):
        pass

    def sleep(self, n):
        gevent.sleep(n)

正則

匹配單個功能
.匹配任意1個字元(除了\n)
[ ]匹配[ ]中列舉的字元
\d匹配數字,即0-9
\D匹配非數字,即不是數字
\s匹配空白,即 空格,tab鍵
\S匹配非空白
\w匹配單詞字元,即a-z、A-Z、0-9、_
\W匹配非單詞字元
匹配多個功能
*匹配前一個字元出現0次或者無限次,即可有可無
+匹配前一個字元出現1次或者無限次,即至少有1次
?匹配前一個字元出現1次或者0次,即要麼有1次,要麼沒有
{m}匹配前一個字元出現m次
{m,n}匹配前一個字元出現從m到n次
開頭結尾功能
^匹配字串開頭
$匹配字串結尾
分組功能
|匹配左右任意一個表示式
(ab)將括號中字元作為一個分組
\num引用分組num匹配到的字串
(?P)分組起別名
(?P=name)引用別名為name分組匹配到的字串
標誌位描述
re.I使匹配對大小寫不敏感
re.L做本地化識別(locale-aware)匹配
re.M多行匹配,影響 ^ 和 $
re.S使 . 匹配包括換行在內的所有字元
re.U根據Unicode字符集解析字元。這個標誌影響 \w, \W, \b, \B.
re.X該標誌通過給予你更靈活的格式以便你將正規表示式寫得更易於理解。
正則函式
函式名描述
re.match(pattern, string, flags=0)嘗試從字串的起始位置匹配一個模式,如果不是起始位置匹配成功的話,match()就返回none。
re.search(pattern, string, flags=0)掃描整個字串並返回第一個成功的匹配。
re.sub(pattern, repl, string, count=0, flags=0)用於替換字串中的匹配項。
re.findall(pattern,string[, pos[, endpos]])在字串中找到正規表示式所匹配的所有子串,並返回一個列表,如果沒有找到匹配的,則返回空列表。
re.finditer(pattern, string, flags=0)和 findall 類似,在字串中找到正規表示式所匹配的所有子串,並把它們作為一個迭代器返回。
re.split(pattern, string[, maxsplit=0, flags=0])split 方法按照能夠匹配的子串將字串分割後返回列表
group(num=0)/groups匹配的整個表示式的字串,group() 可以一次輸入多個組號,在這種情況下它將返回一個包含那些組所對應值的元組。/返回一個包含所有小組字串的元組,從 1 到 所含的小組號。
re.compile(pattern[, flags])函式用於編譯正規表示式,生成一個正規表示式( Pattern )物件。

引數說明

引數描述
pattern匹配的正規表示式
string要匹配的字串。
flags標誌位,用於控制正規表示式的匹配方式,如:是否區分大小寫,多行匹配等等。參見:正規表示式修飾符 - 可選標誌
repl替換的字串,也可為一個函式。
count模式匹配後替換的最大次數,預設 0 表示替換所有的匹配。
pos可選引數,指定字串的起始位置,預設為 0。
endpos可選引數,指定字串的結束位置,預設為字串的長度。
maxsplit分隔次數,maxsplit=1 分隔一次,預設為 0,不限制次數。

正則分組替換

re.sub(r'(?P<p>[\s=]).*',r'\g<p>'+'127.0.0.1',' 128')

如果沒有數字

re.sub(r'([\s=]).*',r'\1asd',' 128')

生成驗證碼

def verifycode(request):
    # 引入繪圖模組
    from PIL import Image, ImageDraw, ImageFont
    # 引入隨機函式模組
    import random
    # 定義變數,用於畫面的背景色、寬、高
    bgcolor = (random.randrange(20, 100), random.randrange(
        20, 100), 255)
    width = 100
    height = 25
    # 建立畫面物件
    im = Image.new('RGB', (width, height), bgcolor)
    # 建立畫筆物件
    draw = ImageDraw.Draw(im)
    # 呼叫畫筆的point()函式繪製噪點
    for i in range(0, 100):
        xy = (random.randrange(0, width), random.randrange(0, height))
        fill = (random.randrange(0, 255), 255, random.randrange(0, 255))
        draw.point(xy, fill=fill)
    # 定義驗證碼的備選值
    str1 = 'ABCD123EFGHIJK456LMNOPQRS789TUVWXYZ0'
    # 隨機選取4個值作為驗證碼
    rand_str = ''
    for i in range(0, 4):
        rand_str += str1[random.randrange(0, len(str1))]
    # 構造字型物件
    font = ImageFont.truetype('Monaco.ttf', 18)
    # 構造字型顏色
    fontcolor = (255, random.randrange(0, 255), random.randrange(0, 255))
    # 繪製4個字
    draw.text((5, 2), rand_str[0], font=font, fill=fontcolor)
    draw.text((25, 2), rand_str[1], font=font, fill=fontcolor)
    draw.text((50, 2), rand_str[2], font=font, fill=fontcolor)
    draw.text((75, 2), rand_str[3], font=font, fill=fontcolor)
    # 釋放畫筆
    del draw
    # 存入session,用於做進一步驗證
    # request.session['verifycode'] = rand_str
    # 記憶體檔案操作
    import io
    buf = io.StringIO()
    # 將圖片儲存在記憶體中,檔案型別為png
    im.save(buf, 'png')
    # 將記憶體中的圖片資料返回給客戶端,MIME型別為圖片png
    return HttpResponse(buf.getvalue(), 'image/png')

python的記憶體管理機制

先從較淺的層面來說,Python的記憶體管理機制可以從三個方面來講

(1)垃圾回收

(2)引用計數

(3)記憶體池機制

一、垃圾回收:

python不像C++,Java等語言一樣,他們可以不用事先宣告變數型別而直接對變數進行賦值。對Python語言來講,物件的型別和記憶體都是在執行時確定的。這也是為什麼我們稱Python語言為動態型別的原因(這裡我們把動態型別可以簡單的歸結為對變數記憶體地址的分配是在執行時自動判斷變數型別並對變數進行賦值)。

二、引用計數:

Python採用了類似Windows核心物件一樣的方式來對記憶體進行管理。每一個物件,都維護這一個對指向該對物件的引用的計數。

三、記憶體池機制

Python的記憶體機制以金字塔行,-1,-2層主要有作業系統進行操作,

第0層是C中的malloc,free等記憶體分配和釋放函式進行操作;

第1層和第2層是記憶體池,有Python的介面函式PyMem_Malloc函式實現,當物件小於256K時有該層直接分配記憶體;

第3層是最上層,也就是我們對Python物件的直接操作;

在 C 中如果頻繁的呼叫 malloc 與 free 時,是會產生效能問題的.再加上頻繁的分配與釋放小塊的記憶體會產生記憶體碎片. Python 在這裡主要乾的工作有:

如果請求分配的記憶體在1~256位元組之間就使用自己的記憶體管理系統,否則直接使用 malloc.

這裡還是會呼叫 malloc 分配記憶體,但每次會分配一塊大小為256k的大塊記憶體.

經由記憶體池登記的記憶體到最後還是會回收到記憶體池,並不會呼叫 C 的 free 釋放掉.以便下次使用.對於簡單的Python物件,例如數值、字串,元組(tuple不允許被更改)採用的是複製的方式(深拷貝?),也就是說當將另一個變數B賦值給變數A時,雖然A和B的記憶體空間仍然相同,但當A的值發生變化時,會重新給A分配空間,A和B的地址變得不再相同

python包自己安裝

必須有__init__檔案
setup.py

from os.path import dirname, join
from pip.req import parse_requirements

# 包管理工具
from setuptools import (
    find_packages,
    setup
)

with open(join(dirname(__file__), './VERSION.txt'), 'rb') as f:
    version = f.read().decode('ascii').strip()
    '''
        作為一個合格的模組,應該有版本號
    '''

setup(
    name='mini_scrapy',  # 模組名
    version=version,  # 版本號
    description='A mini spider frameword, like scrapy',  # 描述
    packages=find_packages(exclude=[]),  # 包含目錄中所有包,exclude=['哪些檔案除外']
    author='WangJY',  # 作者
    author_email='wangjunyan456@gmail.com',  # 作者郵箱
    license='Apache License v2',
    package_data={'': ['*.*']},  # {'包名': ['正則']}
    url='#',
    install_requires=[str(ir.req) for ir in parse_requirements("requirements.txt",session=False)],  # 所需的執行環境
    zip_safe=False,
    classifiers=[
        'Programming Language :: Python',
        'Operating System :: Microsoft :: Windows',
        'Operating System :: Unix',
        'Programming Language :: Python :: 2.7',
        'Programming Language :: Python :: 3.4',
        'Programming Language :: Python :: 3.5',
        'Programming Language :: Python :: 3.6',
    ],
)
requirements.txt

requests>=2.18.4
six>=1.11.0
w3lib>=1.18.0
redis>=2.10.6
gevent>=1.2.2
VERSION.txt

1.0

使用ipython儲存到檔案

%hist -f 'filename.py'
import time
import datetime
 
#計算兩個日期相差天數,自定義函式名,和兩個日期的變數名。
def Caltime(date1,date2):
    #%Y-%m-%d為日期格式,其中的-可以用其他代替或者不寫,但是要統一,同理後面的時分秒也一樣;可以只計算日期,不計算時間。
    #date1=time.strptime(date1,"%Y-%m-%d %H:%M:%S") 
    #date2=time.strptime(date2,"%Y-%m-%d %H:%M:%S")
    date1=time.strptime(date1,"%Y-%m-%d")
    date2=time.strptime(date2,"%Y-%m-%d")
    #根據上面需要計算日期還是日期時間,來確定需要幾個陣列段。下標0表示年,小標1表示月,依次類推...
    #date1=datetime.datetime(date1[0],date1[1],date1[2],date1[3],date1[4],date1[5])
    #date2=datetime.datetime(date2[0],date2[1],date2[2],date2[3],date2[4],date2[5])
    date1=datetime.datetime(date1[0],date1[1],date1[2])
    date2=datetime.datetime(date2[0],date2[1],date2[2])
    #返回兩個變數相差的值,就是相差天數
    return date2-date1

描述符

任何實現了__get__(), set(), 或者 delete()方法的物件就是描述符。一個class的屬性是一個描述符的時候,對這個屬性的訪問會觸發特定的繫結行為。一般的我們使用a.b的方式訪問,修改和刪除屬性,它通過查詢class的字典來訪問屬性b,當時如果b是一個描述符,那麼get,set和delete相關的描述符方法會被呼叫。理解描述符是深入理解python的關鍵,因為描述符是很多特性實現的基礎,比如:方法,函式,屬性,類方法,靜態方法還有對父類方法的引用。詳細的說明請看描述符的實現。

描述符協議:

__get__(self, instance, owner) --> return value
__set__(self, instance, value)
__delete__(self, instance)
  • 實現 get 和 set 方法,稱為 data descriptor。
  • 僅有 get 方法的,稱為 non-data descriptor。
  • get 對 owner_class、owner_instance 訪問有效。
  • set、delete 僅對 owner_instance 訪問有效。
class Typed:
    def __init__(self, key, expected_type):
        self.key = key
        self.expected_type = expected_type

    def __get__(self, instance, owner):
        print('get方法')
        # print('instance引數【%s】' %instance)
        # print('owner引數【%s】' %owner)
        return instance.__dict__[self.key]

    def __set__(self, instance, value):
        print('set方法')
        # print('instance引數【%s】' % instance)
        # print('value引數【%s】' % value)
        # print('====>',self)
        if not isinstance(value, self.expected_type):
            # print('你傳入的型別不是字串,錯誤')
            # return
            raise TypeError('%s 傳入的型別不是%s' % (self.key, self.expected_type))
        instance.__dict__[self.key] = value

    def __delete__(self, instance):
        print('delete方法')
        # print('instance引數【%s】' % instance)
        instance.__dict__.pop(self.key)


class People:
    name = Typed('name', str)  # t1.__set__()  self.__set__()  # 類的屬性被代理
    age=Typed('age',int) #t1.__set__()  self.__set__()

    def __init__(self, name, age, salary):
        self.name = name
        self.age = age
        self.salary = salary
解決粘包
# Server端

from socketserver import ThreadingTCPServer, StreamRequestHandler
import struct
import subprocess


class MyRequestHandler(StreamRequestHandler):

    def handle(self):

        while True:
            print("connect from:", self.client_address)
            cmd = bytes.decode(self.request.recv(1024))
       if not cmd: break
            res = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            err = res.stderr.read()
            if err:
                back_msg = err
            else:
                back_msg = res.stdout.read()

            self.request.send(struct.pack("i", len(back_msg)))
            self.request.send(back_msg)


if __name__ == '__main__':

    tcp_Server = ThreadingTCPServer(("127.0.0.1", 8081), MyRequestHandler)
    tcp_Server.allow_reuse_address = True
    tcp_Server.serve_forever()
#Client端

import socket
import struct

host = "127.0.0.1"
port = 8081

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))

while True:
    cmd = input(">>>>").strip()
    if not cmd:
        continue
    s.send(cmd.encode("utf-8"))

    package_len = s.recv(4)
    package_size = struct.unpack("i",package_len)[0]

    recv_size = 0
    recv_bytes = b""

    while recv_size < package_size:
        res = s.recv(1024)
        recv_bytes += res
        recv_size += len(res)

    print(recv_bytes.decode("utf-8"))

s.close()

python3.6 新特性

https://docs.python.org/3.6/whatsnew/3.6.html#pep-498-formatted-string-literals

格式化字串文字

格式化的字串文字以字首’f’為的格式字串為字首,並且與之接受的格式字串類似str.format()。它們包含由花括號包圍的替換欄位。替換欄位是表示式,在執行時進行評估,然後使用format()協議進行格式化 :

>>> name = "Fred"
>>> f"He said his name is {name}."
'He said his name is Fred.'
>>> width = 10
>>> precision = 4
>>> value = decimal.Decimal("12.34567")
>>> f"result: {value:{width}.{precision}}"  # nested fields
'result:      12.35'

變數註釋的語法

PEP 484引入了函式引數型別註釋的標準,即型別提示。此PEP為Python新增語法以註釋變數型別,包括類變數和例項變數:

primes: List[int] = []

captain: str  # Note: no initial value!

class Starship:
    stats: Dict[str, int] = {}

與函式註釋一樣,Python直譯器不會將任何特定含義附加到變數註釋,只將它們儲存在__annotations__類或模組的 屬性中。

與靜態型別語言中的變數宣告相比,註釋語法的目標是提供一種通過抽象語法樹和__annotations__屬性為第三方工具和庫指定結構化型別後設資料的簡便方法。

數字文字中的下劃線

PEP 515增加了在數字文字中使用下劃線的能力,以提高可讀性。例如:

>>> 1_000_000_000_000_000
1000000000000000
>>> 0x_FF_FF_FF_FF
4294967295

非同步發生器

PEP 492引入了 對Python 3.5的本機協同程式和async/await語法的支援。Python的3.5實現的一個顯著的限制是,它是不可能使用await,並yield在同一個函式體。在Python 3.6中,這個限制已被解除,從而可以定義非同步生成器:

async def ticker(delay, to):
    """Yield numbers from 0 to *to* every *delay* seconds."""
    for i in range(to):
        yield i
        await asyncio.sleep(delay)

非同步理解

PEP 530增加了對list,set,dict comprehensions和generator表示式中使用的支援:async for

result = [i async for i in aiter() if i % 2]

此外,await各種理解都支援表示式:

result = [await fun() for fun in funcs if await condition()]

更簡單的類建立自定義

現在可以在不使用元類的情況下自定義子類建立。__init_subclass__每當建立新的子類時,都會在基類上呼叫新的classmethod:

class PluginBase:
    subclasses = []

    def __init_subclass__(cls, **kwargs):
        super().__init_subclass__(**kwargs)
        cls.subclasses.append(cls)

class Plugin1(PluginBase):
    pass

class Plugin2(PluginBase):
    pass

為了允許零引數super()呼叫從__init_subclass__()實現中正確工作 ,自定義元類必須確保將新的__classcell__名稱空間條目傳播到 type.new(如建立類物件中所述)。

描述符協議增強

PEP 487擴充套件了描述符協議以包括新的可選 set_name()方法。每當定義新類時,將在定義中包含的所有描述符上呼叫新方法,為它們提供對所定義的類的引用以及在類名稱空間中給予描述符的名稱。換句話說,描述符的例項現在可以知道所有者類中描述符的屬性名稱:

class IntField:
    def __get__(self, instance, owner):
        return instance.__dict__[self.name]

    def __set__(self, instance, value):
        if not isinstance(value, int):
            raise ValueError(f'expecting integer in {self.name}')
        instance.__dict__[self.name] = value

    # this is the new initializer:
    def __set_name__(self, owner, name):
        self.name = name

class Model:
    int_field = IntField()

新增檔案系統路徑協議

檔案系統路徑歷來被表示為str 或bytes物件。這導致編寫在檔案系統路徑上執行的程式碼的人認為這些物件只是這兩種型別中的一種(int表示檔案描述符不計算為不是檔案路徑)。不幸的是,這種假設阻止了檔案系統路徑的替代物件表示,例如pathlib使用預先存在的程式碼,包括Python的標準庫。

為了解決這種情況,os.PathLike已經定義了一個新的介面 。通過實現該 fspath()方法,物件表示它表示路徑。然後物件可以提供一個檔案系統路徑的低階表示作為一個str或 bytes物件。這意味著一個物件被認為是 路徑樣如果它實現 os.PathLike或者是str或bytes物件,表示一個檔案系統路徑。程式碼可以使用os.fspath(), os.fsdecode()或os.fsencode()顯式獲取路徑類物件的 str和/或bytes表示。

內建open()函式已更新為接受 os.PathLike物件,os與os.path模組中的所有相關函式 以及標準庫中的大多數其他函式和類一樣。本os.DirEntry類和相關類pathlib也進行了更新來實現os.PathLike。

希望更新用於在檔案系統路徑上操作的基本功能將導致第三方程式碼隱式支援所有類似路徑的物件而不需要任何程式碼更改,或者至少是非常小的os.fspath()程式碼(例如,在操作之前呼叫 程式碼的開頭)在路徑上的物件)。

以下是一些示例,說明新介面如何 pathlib.Path使用預先存在的程式碼更輕鬆,更透明地使用:

>>> import pathlib
>>> with open(pathlib.Path("README")) as f:
...     contents = f.read()
...
>>> import os.path
>>> os.path.splitext(pathlib.Path("some_file.txt"))
('some_file', '.txt')
>>> os.path.join("/a/b", pathlib.Path("c"))
'/a/b/c'
>>> import os
>>> os.fspath(pathlib.Path("some_file.txt"))
'some_file.txt'

當地時間消歧

在大多數世界地區,曾經並且有時會將本地時鐘移回。在這些時間,引入間隔,其中本地時鐘在同一天顯示兩次相同的時間。在這些情況下,本地時鐘上顯示的資訊(或儲存在Python日期時間例項中)不足以識別特定時刻。

PEP 495將新的 fold屬性新增到例項 datetime.datetime和datetime.time類中,以區分當地時間相同的兩個時刻:

>>> u0 = datetime(2016, 11, 6, 4, tzinfo=timezone.utc)
>>> for i in range(4):
...     u = u0 + i*HOUR
...     t = u.astimezone(Eastern)
...     print(u.time(), 'UTC =', t.time(), t.tzname(), t.fold)
...
04:00:00 UTC = 00:00:00 EDT 0
05:00:00 UTC = 01:00:00 EDT 0
06:00:00 UTC = 01:00:00 EST 1
07:00:00 UTC = 02:00:00 EST 0

concurrent.futures- 啟動並行任務

https://docs.python.org/3.6/library/concurrent.futures.html#concurrent.futures.ThreadPoolExecutor

類concurrent.futures.Executor
一個抽象類,提供非同步執行呼叫的方法。它不應該直接使用,而是通過其具體的子類。

submit(fn,* args,** kwargs )
將可呼叫的fn排程為執行, 並返回表示可呼叫執行的物件。fn(*args **kwargs)Future

with ThreadPoolExecutor(max_workers=1) as executor:
    future = executor.submit(pow, 323, 1235)
    print(future.result())

map(func,* iterables,timeout = None,chunksize = 1 )
與以下類似:map(func, *iterables)

  • 在iterables收集立即而不是懶洋洋地;
  • func以非同步方式執行,並且可以同時對func進行多次呼叫 。
    返回的迭代器引發一個concurrent.futures.TimeoutError if next()被呼叫,結果在從原始呼叫到超時秒後不可用Executor.map()。 timeout可以是int或float。如果未指定 超時None,則等待時間沒有限制。

如果func呼叫引發異常,那麼當從迭代器中檢索其值時,將引發該異常。

在使用時ProcessPoolExecutor,此方法將可迭代元件 切換為多個塊,並將其作為單獨的任務提交到池中。可以通過將chunksize設定為正整數來指定這些塊的(近似)大小。對於很長的iterables,採用大值CHUNKSIZE可以顯著改善效能相比的1.預設大小 ThreadPoolExecutor,CHUNKSIZE沒有效果。

shutdown(wait = True )
向執行者發出訊號,表示當目前待處理的期貨執行完畢時,它應該釋放它正在使用的任何資源。關機後撥打電話Executor.submit()並撥打電話 。Executor.map()RuntimeError

如果等待,True那麼在所有待處理的期貨完成執行並且與執行程式關聯的資源已被釋放之前,此方法將不會返回。如果等待,False則此方法將立即返回,並且當執行所有待處理的期貨時,將釋放與執行程式關聯的資源。無論wait的值如何,整個Python程式都不會退出,直到所有待處理的期貨都執行完畢。

如果使用with語句,則可以避免必須顯式呼叫此方法 ,該語句將關閉Executor (等待,就像Executor.shutdown()使用wait set 呼叫一樣True):

import shutil
with ThreadPoolExecutor(max_workers=4) as e:
    e.submit(shutil.copy, 'src1.txt', 'dest1.txt')
    e.submit(shutil.copy, 'src2.txt', 'dest2.txt')
    e.submit(shutil.copy, 'src3.txt', 'dest3.txt')
    e.submit(shutil.copy, 'src4.txt', 'dest4.txt')

ThreadPoolExecutor是一個Executor子類,它使用一個執行緒池來非同步執行呼叫。

當與a關聯的callable Future等待另一個的結果時,可能會發生死鎖Future。例如:

import time
def wait_on_b():
    time.sleep(5)
    print(b.result())  # b will never complete because it is waiting on a.
    return 5

def wait_on_a():
    time.sleep(5)
    print(a.result())  # a will never complete because it is waiting on b.
    return 6


executor = ThreadPoolExecutor(max_workers=2)
a = executor.submit(wait_on_b)
b = executor.submit(wait_on_a)

def wait_on_future():
    f = executor.submit(pow, 5, 2)
    # This will never complete because there is only one worker thread and
    # it is executing this function.
    print(f.result())

executor = ThreadPoolExecutor(max_workers=1)
executor.submit(wait_on_future)

class concurrent.futures.ThreadPoolExecutor(max_workers = None,thread_name_prefix =’’ )
Executor使用最多max_workers 執行緒池的子類,以非同步方式執行呼叫。

initializer是一個可選的callable,在每個工作執行緒的開頭呼叫; initargs是傳遞給初始化器的引數元組。如果初始化程式引發異常,則所有當前掛起的作業都將引發BrokenThreadPool,以及向池中提交更多作業的任何嘗試。

改變在3.5版本中:如果max_workers是None或者沒有給出,將預設為機器上的處理器,乘以數量5,假設ThreadPoolExecutor經常使用重疊的I / O,而不是CPU的工作,工人的數量應比工人數量ProcessPoolExecutor。

在3.6版本的新功能:該thread_name_prefix加入引數,允許使用者控制threading.Thread由池更容易除錯建立工作執行緒的名字。

ThreadPoolExecutor示例
import concurrent.futures
import urllib.request

URLS = ['http://www.foxnews.com/',
        'http://www.cnn.com/',
        'http://europe.wsj.com/',
        'http://www.bbc.co.uk/',
        'http://some-made-up-domain.com/']

# Retrieve a single page and report the URL and contents
def load_url(url, timeout):
    with urllib.request.urlopen(url, timeout=timeout) as conn:
        return conn.read()

# We can use a with statement to ensure threads are cleaned up promptly
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
    # Start the load operations and mark each future with its URL
    future_to_url = {executor.submit(load_url, url, 60): url for url in URLS}
    for future in concurrent.futures.as_completed(future_to_url):
        url = future_to_url[future]
        try:
            data = future.result()
        except Exception as exc:
            print('%r generated an exception: %s' % (url, exc))
        else:
            print('%r page is %d bytes' % (url, len(data)))
ProcessPoolExecutor

本ProcessPoolExecutor類是Executor使用的過程池非同步執行呼叫子類。 ProcessPoolExecutor使用該multiprocessing模組,它允許它側向全域性直譯器鎖定,但也意味著只能執行和返回可選物件。

該__main__模組必須可由工作程式子程式匯入。這意味著ProcessPoolExecutor在互動式直譯器中不起作用。

從提交給a的可呼叫呼叫Executor或Future方法ProcessPoolExecutor將導致死鎖。

class concurrent.futures.ProcessPoolExecutor(max_workers = None )
Executor使用最多max_workers程式池非同步執行呼叫的子類。如果max_workers是None或者沒有給出,將預設為機器上的處理器數量。如果max_workers低於或等於0,則將ValueError 引發a。

版本3.3中更改:當其中一個工作程式突然終止時, BrokenProcessPool現在會引發錯誤。以前,行為未定義,但執行者或其未來的操作通常會凍結或死鎖。

ProcessPoolExecutor示例
import concurrent.futures
import math

PRIMES = [
    112272535095293,
    112582705942171,
    112272535095293,
    115280095190773,
    115797848077099,
    1099726899285419]

def is_prime(n):
    if n % 2 == 0:
        return False

    sqrt_n = int(math.floor(math.sqrt(n)))
    for i in range(3, sqrt_n + 1, 2):
        if n % i == 0:
            return False
    return True

def main():
    with concurrent.futures.ProcessPoolExecutor() as executor:
        for number, prime in zip(PRIMES, executor.map(is_prime, PRIMES)):
            print('%d is prime: %s' % (number, prime))

if __name__ == '__main__':
    main()

相關文章