note eight 使用元類 動態語言和靜態語言最大的不同,就是函數和類的定義,不是編譯時定義的,而是運行時動態創建的。 程式的調試用logging 模塊 import logging 單元測試 為了編寫單元測試,我們需要引入pytho... ...
note eight
使用元類
動態語言和靜態語言最大的不同,就是函數和類的定義,不是編譯時定義的,而是運行時動態創建的。
程式的調試用logging 模塊
import logging
單元測試
為了編寫單元測試,我們需要引入python自帶的unittest模塊
文件讀寫
讀寫文件是最常見的IO操作,python內置了讀寫文件的函數。讀寫文件就是請求操作系統打開一個文件對象,然後通過操作系統提供的介面從這個文件對象中讀取數據,或者把數據寫入這個文件對象。
step1:打開文件
使用python內置的open()函數
step2:對文件對象進行讀或寫
read(),write()
step3:關閉文件
close(),文件使用完後必須關閉,因為文件對象會占用操作系統的資源,並且操作系統同一時間能打開的文件數量也是有限的
但每次都這麼寫實在太繁瑣,所以PYthon引入了with語句來自動幫我們調用close()方法
with open() as f
二進位文件
前面講的預設都是讀取文本文件,並且是ASCII編碼的文本文件。要讀取二進位文件,比如圖片、視頻等等,用"rb"模式打開文件
字元編碼
要讀取非ASCII編碼的文本文件,就必須以二進位模式打開,再解碼。如GBK編碼的文件
f = open('/Users/michael/gbk.txt', 'rb')
>>> u = f.read().decode('gbk')
>>> u
u'\u6d4b\u8bd5'
>>> print u
測試
如果每次手動轉換嫌麻煩,python還提供了一個codecs模塊幫我們在讀文件時自動轉換編碼,直接讀出unicode
import codecs
with codecs.open('/Users/michael/gbk.txt', 'r', 'gbk') as f:
f.read() # u'\u6d4b\u8bd5'
序列化
在程式運行的過程中,所有的變數都是在記憶體中,可以隨時修改變數,但是一旦程式結束,,變數所占的記憶體就被操作系統全部收回。
我們把變數從記憶體中變成可存儲或傳輸的過程稱為序列化,在python中叫picking。序列化後,就可以把序列化之後的內容寫入磁碟,或通過網路傳輸到別的機器上。
反過來,把變數內容從序列化的對象重新讀到記憶體里稱為反序列化。
python提供兩個模塊來實現序列化
cPickle, pickle
導入模塊
: d
Out[11]: {'age': 20, 'name': 'Jack', 'score': 88}
In [12]: try :
....: import cPickle as pickle
....: except ImportError:
....: import pickle
....:
In [13]: pickle.dumps(d)
Out[13]: "(dp1\nS'age'\np2\nI20\nsS'score'\np3\nI88\nsS'name'\np4\nS'Jack'\np5\ns."
pickle.dumps()方法把任意對象序列化成一個str,然後就可以把這個str寫入文件、或者用另一個方法pickle.dump()直接把對象序列化後寫入一個file-like Object
In [15]: f= open(r"C:\Users\MyHome\Desktop\dumps.txt","wb")
In [16]: pickle.dump(d,f)
In [17]: f.close()
當我們要把對象從磁碟讀到記憶體時,可以先把內容讀到一個str,然後用pickle.loads()方法反序列化對象,也可以直接用pickle.load()方法從一個file-like Object 中直接反序列化對象。
In [18]: f= open(r"C:\Users\MyHome\Desktop\dumps.txt","rb")
In [19]: d = pickle.load(f)
In [20]: f.close()
In [21]: d
Out[21]: {'age': 20, 'name': 'Jack', 'score': 88}
JSON進階
如果我們要在不同的編程語言之間傳遞對象,就必須把對象序列化為標準格式,比如XML,但更好的方法是序列化為JSON,因為JSON表示出來就是一個字元串,可以被所有語言讀取,也可以方便地存儲到磁碟或者通過網路傳輸。JSON不僅是標準格式,並且比XML更快,而且可以直接在Web頁面中讀取,非常方便。
python中內置的json模塊提供了非常完善的Python對象到JSON格式的轉換。我們先看看如何把python對象變成一個JSON
In [22]: import json
In [23]: d = dict(name = "Jack",age = 24,score = 96)
In [24]: json.dumps(d)
Out[24]: '{"age": 24, "score": 96, "name": "Jack"}'
dumps()方法返回一個str,內容就是標準的JSON,類似的,dump()方法可以直接把JSON寫入一個file-like Object
要把JSON反序列化為python對象,用loads()或者對應的load()方法,前者把JSON的字元串反序列化,後者從file-like Object 中讀取字元串並反序列化
In [25]: json_str = '{"age": 24, "score": 96, "name": "Jack"}'
In [26]: json.loads(json_str)
Out[26]: {u'age': 24, u'name': u'Jack', u'score': 96}
Python的dict對象可以直接序列化為JSON的{},不過,很多時候,我們更喜歡用class表示對象,比如定義Student類,然後序列化:
import json
class Student(object):
def __init__(self, name, age, score):
self.name = name
self.age = age
self.score = score
s = Student('Bob', 20, 88)
print(json.dumps(s))
運行代碼,毫不留情地得到一個TypeError:
Traceback (most recent call last):
...
TypeError: <__main__.Student object at 0x
錯誤的原因是Student對象不是一個可序列化為JSON的對象。
如果連class的實例對象都無法序列化為JSON,這肯定不合理!
別急,我們仔細看看dumps()方法的參數列表,可以發現,除了第一個必須的obj參數外,dumps()方法還提供了一大堆的可選參數:
https://docs.python.org/2/library/json.html#json.dumps
這些可選參數就是讓我們來定製JSON序列化。前面的代碼之所以無法把Student類實例序列化為JSON,是因為預設情況下,dumps()方法不知道如何將Student實例變為一個JSON的{}對象。
可選參數default就是把任意一個對象變成一個可序列為JSON的對象,我們只需要為Student專門寫一個轉換函數,再把函數傳進去即可:
def studentdict(std):
return {"name":std.name,"age":std.age,"score":std.score}
print (json.dumps(s,default=studentdict))
不過,下次如果遇到一個Teacher類的實例,照樣無法序列化為JSON。我們可以偷個懶,把任意class的實例變為dict:
print(json.dumps(s, default=lambda obj: obj.__dict__))
同樣的道理,如果我們要把JSON反序列化為一個Student對象實例,loads()方法首先轉換出一個dict對象,然後,我們傳入的object_hook函數負責把dict轉換為Student實例:
def dict2student(d):
return Student(d['name'], d['age'], d['score'])
json_str = '{"age": 20, "score": 88, "name": "Bob"}'
print(json.loads(json_str, object_hook=dict2student))
運行結果如下:
<__main__.Student object at 0x10cd3c190>
列印出的是反序列化的Student實例對象。
解析
如果我們要編寫一個搜索引擎,第一步是用爬蟲把目標網站的頁面抓取下來,第二部就是解析該HTML頁面,看看裡面的內容到底是新聞、圖片還是視頻。
如何解析HTML呢,python提供了HTMLParser來非常方便地解析HTML