Python學習筆記(高階篇二)

筆記整理出處:廖雪峯教程java

經常使用內建模塊

datetime

datetime是Python處理日期和時間的標準庫。python

datetime模塊還包含一個datetime類,經過from datetime import datetime導入的纔是datetime這個類。
若是僅導入import datetime,則必須引用全名datetime.datetime。
datetime.now()返回當前日期和時間,其類型是datetime。nginx

datetime的timestamp() 方法能夠獲取毫秒時間,可是須要注意:
Python的timestamp是一個浮點數。若是有小數位,小數位表示毫秒數。某些編程語言(如Java和JavaScript)的timestamp使用整數表示毫秒數,這種狀況下只須要把timestamp除以1000就獲得Python的浮點表示方法。算法

fromtimestamp(t)方法與上面的相反,能夠把毫秒時間轉換成 一個標準時間,這裏一樣注意,須要傳入一個浮點的毫秒時間不要使用整型毫秒時間。spring

str轉換爲datetime編程

不少時候,用戶輸入的日期和時間是字符串,要處理日期和時間,首先必須把str轉換爲datetime。轉換方法是經過datetime.strptime()實現,須要一個日期和時間的格式化字符串:json

>>> from datetime import datetime
>>> cday = datetime.strptime('2015-6-1 18:19:59', '%Y-%m-%d %H:%M:%S')
>>> print(cday)
2015-06-01 18:19:59複製代碼

字符串'%Y-%m-%d %H:%M:%S'規定了日期和時間部分的格式。詳細的說明請參考Python文檔。
注意轉換後的datetime是沒有時區信息的。api

datetime加減瀏覽器

對日期和時間進行加減實際上就是把datetime日後或往前計算,獲得新的datetime。加減能夠直接用+和-運算符,不過須要導入timedelta這個類:安全

>>> from datetime import datetime, timedelta
>>> now = datetime.now()
>>> now
datetime.datetime(2015, 5, 18, 16, 57, 3, 540997)
>>> now + timedelta(hours=10)
datetime.datetime(2015, 5, 19, 2, 57, 3, 540997)
>>> now - timedelta(days=1)
datetime.datetime(2015, 5, 17, 16, 57, 3, 540997)
>>> now + timedelta(days=2, hours=12)
datetime.datetime(2015, 5, 21, 4, 57, 3, 540997)複製代碼

可見,使用timedelta你能夠很容易地算出前幾天和後幾天的時刻。

collections

collections是Python內建的一個集合模塊,提供了許多有用的集合類。

namedtuple

namedtuple是一個函數,它用來建立一個自定義的tuple對象,而且規定了tuple元素的個數,並能夠用屬性而不是索引來引用tuple的某個元素。

這樣一來,咱們用namedtuple能夠很方便地定義一種數據類型,它具有tuple的不變性,又能夠根據屬性來引用,使用十分方便。
典型使用:座標點的定義:

>>> from collections import namedtuple
>>> Point = namedtuple('Point', ['x', 'y'])
>>> p = Point(1, 2)
>>> p.x
1
>>> p.y
2複製代碼
deque

使用list存儲數據時,按索引訪問元素很快,可是插入和刪除元素就很慢了,由於list是線性存儲,數據量大的時候,插入和刪除效率很低。

deque是爲了高效實現插入和刪除操做的雙向列表,適合用於隊列和棧:

>>> from collections import deque
>>> q = deque(['a', 'b', 'c'])
>>> q.append('x')
>>> q.appendleft('y')
>>> q
deque(['y', 'a', 'b', 'c', 'x'])複製代碼

deque除了實現list的append()和pop()外,還支持appendleft()和popleft(),這樣就能夠很是高效地往頭部添加或刪除元素,(猜想設計初衷和java中的linkList相似,彌補list的短板)。

defaultdict

使用dict時,若是引用的Key不存在,就會拋出KeyError。若是但願key不存在時,返回一個默認值,就能夠用defaultdict(一般咱們應該會使用這個dict,畢竟誰也不能保證是都每一個key都存在或者取以前去判斷一次):

>>> 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自己排序:

>>> od = OrderedDict()
>>> od['z'] = 1
>>> od['y'] = 2
>>> od['x'] = 3
>>> list(od.keys()) # 按照插入的Key的順序返回
['z', 'y', 'x']複製代碼

OrderedDict能夠實現一個FIFO(先進先出)的dict,當容量超出限制時,先刪除最先添加的Key

Counter

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'各出現了兩次,其餘字符各出現了一次。

struct

Python提供了一個struct模塊來解決bytes和其餘二進制數據類型的轉換。

struct的pack函數把任意數據類型變成bytes:

>>> import struct
>>> struct.pack('>I', 10240099)
b'\x00\x9c@c'複製代碼

pack的第一個參數是處理指令,'>I'的意思是:
>表示字節順序是big-endian,也就是網絡序,I表示4字節無符號整數。
後面的參數個數要和處理指令一致。
unpack把bytes變成相應的數據類型:

>>> struct.unpack('>IH', b'\xf0\xf0\xf0\xf0\x80\x80')
(4042322160, 32896)複製代碼

根據>IH的說明,後面的bytes依次變爲I:4字節無符號整數和H:2字節無符號整數。

hashlib

Python的hashlib提供了常見的摘要算法,如MD5,SHA1等等。
咱們以常見的摘要算法MD5爲例,計算出一個字符串的MD5值:

import hashlib

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

計算結果以下:

d26a53750bc40b38b65a520292f69306
若是數據量很大,能夠分塊屢次調用update(),最後計算的結果是同樣的:

import hashlib

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

試試改動一個字母,看看計算的結果是否徹底不一樣。
比SHA1更安全的算法是SHA256和SHA512,不過越安全的算法不只越慢,並且摘要長度更長。
要注意摘要算法不是加密算法,不能用於加密(由於沒法經過摘要反推明文),只能用於防篡改

itertools

Python的內建模塊itertools提供了很是有用的用於操做迭代對象的函數。

首先,咱們看看itertools提供的幾個「無限」迭代器:

>>> import itertools
>>> natuals = itertools.count(1)
>>> for n in natuals:
...     print(n)
...
1
2
3
...複製代碼

由於count()會建立一個無限的迭代器,因此上述代碼會打印出天然數序列,根本停不下來,只能按Ctrl+C退出。

cycle()會把傳入的一個序列無限重複下去

>>> import itertools
>>> cs = itertools.cycle('ABC') # 注意字符串也是序列的一種
>>> for c in cs:
...     print(c)
...
'A'
'B'
'C'
'A'
'B'
'C'
...複製代碼

一樣停不下來。
repeat()負責把一個元素無限重複下去,不過若是提供第二個參數就能夠限定重複次數

>>> ns = itertools.repeat('A', 3)
>>> for n in ns:
...     print(n)
...
A
A
A複製代碼

無限序列雖然能夠無限迭代下去,可是一般咱們會經過takewhile()等函數根據條件判斷來截取出一個有限的序列

>>> natuals = itertools.count(1)
>>> ns = itertools.takewhile(lambda x: x <= 10, natuals)
>>> list(ns)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]複製代碼

itertools提供的幾個迭代器操做函數更加有用:

chain()
**chain()能夠把一組迭代對象串聯起來,造成一個更大的迭代器**:
~~~python
>>> for c in itertools.chain('ABC', 'XYZ'):
...     print(c)複製代碼

迭代效果:'A' 'B' 'C' 'X' 'Y' 'Z'

groupby()
groupby()把迭代器中相鄰的重複元素挑出來放在一塊兒

>>> for key, group in itertools.groupby('AAABBBCCAAA'):
...     print(key, list(group))
...
A ['A', 'A', 'A']
B ['B', 'B', 'B']
C ['C', 'C']
A ['A', 'A', 'A']複製代碼

itertools模塊提供的所有是處理迭代功能的函數,它們的返回值不是list,而是Iterator,只有用for循環迭代的時候才真正計算

contextlib

contextlib中提供了可讓普通方法使用with。。。as...:的調用

寫try...finally很是繁瑣。Python的with語句容許咱們很是方便地使用資源,而沒必要擔憂資源沒有關閉,因此上面的代碼能夠簡化爲:

with open('/path/to/file', 'r') as f:
f.read()
並非只有open()函數返回的fp對象才能使用with語句。實際上,任何對象,只要正確實現了上下文管理,就能夠用於with語句。

實現上下文管理是經過enterexit這兩個方法實現的。例如,下面的class實現了這兩個方法:

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語句:

with Query('Bob') as q:
    q.query()複製代碼

編寫enterexit仍然很繁瑣,所以Python的標準庫contextlib提供了更簡單的寫法,上面的代碼能夠改寫以下:

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')複製代碼

@contextmanager這個decorator接受一個generator,用yield語句把with ... as var把變量輸出出去,而後,with語句就能夠正常地工做了:

with create_query('Bob') as q:
    q.query()複製代碼

不少時候,咱們但願在某段代碼執行先後自動執行特定代碼,也能夠用@contextmanager實現。例如:

@contextmanager
def tag(name):
    print("<%s>" % name)
    yield
    print("</%s>" % name)

with tag("h1"):
    print("hello")
    print("world")複製代碼

上述代碼執行結果爲:

<h1>
hello
world
</h1>複製代碼

代碼的執行順序是:

with語句首先執行yield以前的語句,所以打印出h1;
yield調用會執行with語句內部的全部語句,所以打印出hello和world;
最後執行yield以後的語句,打印出h1。
所以,@contextmanager讓咱們經過編寫generator來簡化上下文管理。

@closing

若是一個對象沒有實現上下文,咱們就不能把它用於with語句。這個時候,能夠用closing()來把該對象變爲上下文對象。例如,用with語句使用urlopen():

from contextlib import closing
from urllib.request import urlopen

with closing(urlopen('www.python.org')) as page:
for line in page:
print(line)
closing也是一個通過@contextmanager裝飾的generator,這個generator編寫起來其實很是簡單:

@contextmanager
def closing(thing):
try:
yield thing
finally:
thing.close()
它的做用就是把任意對象變爲上下文對象,並支持with語句。

@contextlib還有一些其餘decorator,便於咱們編寫更簡潔的代碼。

urllib

urllib提供了一系列用於操做URL的功能。

Get

urllib的request模塊能夠很是方便地抓取URL內容,也就是發送一個GET請求到指定的頁面,而後返回HTTP的響應:

例如,對豆瓣的一個URLapi.douban.com/v2/book/212…

from urllib import request

with request.urlopen('https://api.douban.com/v2/book/2129650') as f:
    data = f.read()
    print('Status:', f.status, f.reason)
    for k, v in f.getheaders():
        print('%s: %s' % (k, v))
    print('Data:', data.decode('utf-8'))複製代碼

能夠看到HTTP響應的頭和JSON數據:

Status: 200 OK
Server: nginx
Date: Tue, 26 May 2015 10:02:27 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 2049
Connection: close
Expires: Sun, 1 Jan 2006 01:00:00 GMT
Pragma: no-cache
Cache-Control: must-revalidate, no-cache, private
X-DAE-Node: pidl1
Data: {"rating":{"max":10,"numRaters":16,"average":"7.4","min":0},"subtitle":"","author":["廖雪峯編著"],"pubdate":"2007-6","tags":[{"count":20,"name":"spring","title":"spring"}...}複製代碼

若是咱們要想模擬瀏覽器發送GET請求,就須要使用Request對象,經過往Request對象添加HTTP頭,咱們就能夠把請求假裝成瀏覽器。例如,模擬iPhone 6去請求豆瓣首頁:

from urllib import request

req = request.Request('http://www.douban.com/')
req.add_header('User-Agent', 'Mozilla/6.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/8.0 Mobile/10A5376e Safari/8536.25')
with request.urlopen(req) as f:
    print('Status:', f.status, f.reason)
    for k, v in f.getheaders():
        print('%s: %s' % (k, v))
    print('Data:', f.read().decode('utf-8'))
這樣豆瓣會返回適合iPhone的移動版網頁:

...
    <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0">
    <meta name="format-detection" content="telephone=no">
    <link rel="apple-touch-icon" sizes="57x57" href="http://img4.douban.com/pics/cardkit/launcher/57.png" />
...複製代碼

PIL

PIL:Python Imaging Library,已是Python平臺事實上的圖像處理標準庫了。PIL功能很是強大,但API卻很是簡單易用。

因爲PIL僅支持到Python 2.7,加上年久失修,因而一羣志願者在PIL的基礎上建立了兼容的版本,名字叫Pillow,支持最新Python 3.x,又加入了許多新特性,所以,咱們能夠直接安裝使用Pillow。

安裝Pillow

在命令行下直接經過pip安裝:

$ pip install pillow
若是遇到Permission denied安裝失敗,請加上sudo重試。

若是遇到Permission denied安裝失敗,請加上sudo重試。

操做圖像

來看看最多見的圖像縮放操做,只需三四行代碼:

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')複製代碼
相關文章
相關標籤/搜索