Python sqlite3模組的text_factory屬性的使用方法研究

來源:互聯網
上載者:User

標籤:

寫這篇文章,起源於要寫一個指令碼批量把CSV檔案(檔案採用GBK或utf-8編碼)寫入到sqlite資料庫裡。

Python版本:2.7.9

sqlite3模組提供了con = sqlite3.connect("D:\\text_factory.db3") 這樣的方法來建立資料庫(當檔案不存在時,建立庫),資料庫預設編碼為UTF-8,支援使用特殊sql語句設定編碼

PRAGMA encoding = "UTF-8"; 
PRAGMA encoding = "UTF-16"; 
PRAGMA encoding = "UTF-16le"; 
PRAGMA encoding = "UTF-16be";    

但設定編碼必須在main庫之前,否則無法更改。 https://www.sqlite.org/pragma.html#pragma_encoding

認識text_factory屬性,大家應該都是通過以下錯誤知曉的:

sqlite3.ProgrammingError: You must not use 8-bit bytestrings unless you use a text_factory that can interpret 8-bit bytestrings (like text_factory = str). It is highly recommended that you instead just switch your application to Unicode strings.

大意是推薦你把字串入庫之前轉成unicode string,你要用bytestring位元組型字串(如ascii ,gbk,utf-8),需要加一條語句text_factory = str。

Python擁有兩種字串類型。標準字串是單位元組字元序列,允許包含位元據和嵌入的null字元。 Unicode 字串是雙位元組字元序列,一個字元使用兩個位元組來儲存,因此可以有最多65536種不同的unicode字元。儘管最新的Unicode標準支援最多100萬個不同的字元,Python現在尚未支援這個最新的標準。 

預設text_factory = unicode,原以為這unicode、str是函數指標,但貌似不是,是<type ‘unicode‘>和<type ‘str‘>

下面寫了一段測實驗證代碼:

 1 # -*- coding: utf-8 -*- 2 import sqlite3 3 ‘‘‘ 4 GBK   UNIC  UTF-8 5 B8A3  798F  E7 A6 8F  福 6 D6DD  5DDE  E5 B7 9E  州 7 ‘‘‘ 8  9 con = sqlite3.connect(":memory:")10 # con = sqlite3.connect("D:\\text_factory1.db3")11 # con.executescript(‘PRAGMA encoding = "UTF-16";‘)12 cur = con.cursor()13 14 a_text      = "Fu Zhou"15 gb_text     = "\xB8\xA3\xD6\xDD"16 utf8_text   = "\xE7\xA6\x8F\xE5\xB7\x9E"17 unicode_text= u"\u798F\u5DDE"18 19 print ‘Part 1: con.text_factory=str‘20 con.text_factory = str21 print type(con.text_factory)22 cur.execute("CREATE TABLE table1 (city);")23 cur.execute("INSERT INTO table1 (city) VALUES (?);",(a_text,))24 cur.execute("INSERT INTO table1 (city) VALUES (?);",(gb_text,))25 cur.execute("INSERT INTO table1 (city) VALUES (?);",(utf8_text,))26 cur.execute("INSERT INTO table1 (city) VALUES (?);",(unicode_text,))27 cur.execute("select city from table1")28 res = cur.fetchall()29 print "--  result: %s"%(res)30 31 print ‘Part 2: con.text_factory=unicode‘32 con.text_factory = unicode33 print type(con.text_factory)34 cur.execute("CREATE TABLE table2 (city);")35 cur.execute("INSERT INTO table2 (city) VALUES (?);",(a_text,))36 # cur.execute("INSERT INTO table2 (city) VALUES (?);",(gb_text,))37 # cur.execute("INSERT INTO table2 (city) VALUES (?);",(utf8_text,))38 cur.execute("INSERT INTO table2 (city) VALUES (?);",(unicode_text,))39 cur.execute("select city from table2")40 res = cur.fetchall()41 print "--  result: %s"%(res)42 43 print ‘Part 3: OptimizedUnicode‘44 con.text_factory = str45 cur.execute("CREATE TABLE table3 (city);")46 cur.execute("INSERT INTO table3 (city) VALUES (?);",(a_text,))47 #cur.execute("INSERT INTO table3 (city) VALUES (?);",(gb_text,))48 cur.execute("INSERT INTO table3 (city) VALUES (?);",(utf8_text,))49 cur.execute("INSERT INTO table3 (city) VALUES (?);",(unicode_text,))50 con.text_factory = sqlite3.OptimizedUnicode51 print type(con.text_factory)52 cur.execute("select city from table3")53 res = cur.fetchall()54 print "--  result: %s"%(res)55 56 print ‘Part 4: custom fuction‘57 con.text_factory = lambda x: unicode(x, "gbk", "ignore")58 print type(con.text_factory)59 cur.execute("CREATE TABLE table4 (city);")60 cur.execute("INSERT INTO table4 (city) VALUES (?);",(a_text,))61 cur.execute("INSERT INTO table4 (city) VALUES (?);",(gb_text,))62 cur.execute("INSERT INTO table4 (city) VALUES (?);",(utf8_text,))63 cur.execute("INSERT INTO table4 (city) VALUES (?);",(unicode_text,))64 cur.execute("select city from table4")65 res = cur.fetchall()66 print "--  result: %s"%(res)

 

列印結果:

Part 1: con.text_factory=str<type ‘type‘>--  result: [(‘Fu Zhou‘,), (‘\xb8\xa3\xd6\xdd‘,), (‘\xe7\xa6\x8f\xe5\xb7\x9e‘,), (‘\xe7\xa6\x8f\xe5\xb7\x9e‘,)]Part 2: con.text_factory=unicode<type ‘type‘>--  result: [(u‘Fu Zhou‘,), (u‘\u798f\u5dde‘,)]Part 3: OptimizedUnicode<type ‘type‘>--  result: [(‘Fu Zhou‘,), (u‘\u798f\u5dde‘,), (u‘\u798f\u5dde‘,)]Part 4: custom fuction<type ‘function‘>--  result: [(u‘Fu Zhou‘,), (u‘\u798f\u5dde‘,), (u‘\u7ec2\u5fd3\u7a9e‘,), (u‘\u7ec2\u5fd3\u7a9e‘,)]

 

Part 1:unicode被轉換成了utf-8,utf-8和GBK被透傳,寫入資料庫,GBK字串被取出顯示時,需要用類似‘gbk chars‘.decode("cp936").encode("utf_8")的語句進行解析print

Part 2:預設設定,注釋的掉都會產生以上的經典錯誤,輸入範圍被限定在unicode對象或純ascii碼  

Part 3:自動最佳化,ascii為str對象,非ascii轉為unicode對象

Part 4:GBK被正確轉換,utf-8和unicode在存入資料庫時,都被轉為了預設編碼utf-8儲存,既‘\xe7\xa6\x8f\xe5\xb7\x9e‘,

In[16]: unicode(‘\xe7\xa6\x8f\xe5\xb7\x9e‘,‘gbk‘)
Out[16]: u‘\u7ec2\u5fd3\u7a9e‘

就得到了以上結果。

接著,用軟體查看資料庫裡是如何存放的。

分別用官方的sqlite3.exe和SqliteSpy查看,sqlite3.exe因為用命令列介面,命令列用的是GBK顯示;SqliteSpy則是用UTF顯示,所以GBK顯示亂碼。這就再次印證了GBK被允許存放入資料庫的時候,存放的是raw資料,並不會強制轉為資料庫的預設編碼utf-8儲存

Connection.text_factory使用此屬性來控制我們可以從TEXT類型得到什麼對象(我:這也印證寫入資料庫的時候,需要自己編碼,不能依靠這個)。預設情況下,這個屬性被設定為Unicode,sqlite3模組將會為TEXT返回Unicode對象。若你想返回bytestring對象,可以將它設定為str。

因為效率的原因,還有一個只針對非ASCII資料,返回Unicode對象,其它資料則全部返回bytestring對象的方法。要啟用它,將此屬性設定為sqlite3.OptimizedUnicode。

你也可以將它設定為任意的其它callabel,接收一個bytestirng類型的參數,並返回結果對象。《摘自http://www.360doc.com/content/11/1102/10/4910_161017252.shtml》

以上一段話是官方文檔的中文版關於text_factory描述的節選。

 

綜上,我談談我的看法*和使用建議:

1)sqlite3模組執行insert時,寫入的是raw資料,寫入前會根據text_factory屬性進行類型判斷,預設判斷寫入的是否為unicode對象;

2)使用fetchall()從資料庫讀出時,會根據text_factory屬性進行轉化。

3)輸入字串是GBK編碼的bytestring,decode轉為unicode寫入;或加text_factory=str直接寫入,讀出時仍為GBK,前提需要資料庫編碼為utf-8,注意用sqlitespy查看是亂碼。

4)輸入字串是Utf-8編碼的bytestring,可以設定text_factory=str直接寫入直接讀出,sqlitespy查看正常顯示。

5)如果不是什麼高效能情境,入庫前轉成unicode,效能開銷也很小,測試資料找不到了,像我這樣話一整天研究這一行代碼,不如讓機器每次多跑零點幾秒。。

*(因為沒有查看sqlite3模組的原始碼,所以只是猜測)

 

另外,附上資料庫設定為UTF-16編碼時,產生的結果,更亂,不推薦。

Part 1: con.text_factory=str<type ‘type‘>--  result: [(‘Fu Zhou‘,), (‘\xc2\xb8\xc2\xa3\xef\xbf\xbd\xef\xbf\xbd‘,), (‘\xe7\xa6\x8f\xe5\xb7\x9e‘,), (‘\xe7\xa6\x8f\xe5\xb7\x9e‘,)]Part 2: con.text_factory=unicode<type ‘type‘>--  result: [(u‘Fu Zhou‘,), (u‘\u798f\u5dde‘,)]Part 3: OptimizedUnicode<type ‘type‘>--  result: [(‘Fu Zhou‘,), (u‘\u798f\u5dde‘,), (u‘\u798f\u5dde‘,)]Part 4: custom fuction<type ‘function‘>--  result: [(u‘Fu Zhou‘,), (u‘\u8d42\u62e2\u951f\u65a4\u62f7‘,), (u‘\u7ec2\u5fd3\u7a9e‘,), (u‘\u7ec2\u5fd3\u7a9e‘,)]

  

 

Python sqlite3模組的text_factory屬性的使用方法研究

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.