個人筆記系列,隨便參考
1、python 中字典與json的差別
字典的生成
>>> a = dict(one=1, two=2, three=3) >>> b = {'one': 1, 'two': 2, 'three': 3} >>> c = dict(zip(['one', 'two', 'three'], [1, 2, 3])) >>> d = dict([('two', 2), ('one', 1), ('three', 3)]) >>> e = dict({'three': 3, 'one': 1, 'two': 2})
Python的字典和JSON在表現形式上非常相似
Python中的一個字典 dic = { 'str': 'this is a string', 'list': [1, 2, 'a', 'b'], 'sub_dic': { 'sub_str': 'this is sub str', 'sub_list': [1, 2, 3] }, 'end': 'end' } JSON對象 json_obj = { 'str': 'this is a string', 'arr': [1, 2, 'a', 'b'], 'sub_obj': { 'sub_str': 'this is sub str', 'sub_list': [1, 2, 3] }, 'end': 'end' }
實際上JSON就是Python字典的字符串表示,但是字典作為一個復雜對象是無法直接轉換成定義它的代碼的字符串
字典是一個數據的結構,而json只是一個具有一定規則的字符串,方便在不同平台上處理其中包含的數據
但本質上來講,字典是一種數據結構,json是一種格式;字典有很多內置函數,有多種調用方法,而json是數據打包的一種格式,並不像字典具備操作性,並且是格式就會有一些形式上的限制,比如json的格式要求必須且只能使用雙引號作為key或者值的邊界符號,不能使用單引號,而且“key”必須使用邊界符(雙引號),但字典就無所謂了。
形式上的相近也讓python提供了json.loads()轉換函數,方便json數據的調用。
使用方法如下:
import json a=json.loads('{"a":"1","b":"2"}') print a
2、python 中pickle與json的差別
# 1:Json的存數據到文件: import json info = { "name":"hjc", "age":22 } with open("a1.txt","w",encoding="utf-8") as f: f.write(json.dumps(info)) # 注意!!!此處json存數據時會使用unicode的16進制格式,所以中文在保存文件中是\u開頭的
# 當使用json.load()時會自動逆向識別,轉成可讀中文,大概為了不同平台的數據交流
# 若想保留中文的顯示,可以添加參數ensure_ascii = False,文件中即可保留中文
# 2.Json的取數據 import json with open("a1.txt","r",encoding="utf-8") as f: data = json.loads(f.readline()) print(data["age"]) # 3.Pickle的存數據 import pickle def func(): print("hello tomorrow!!!") info = { "name" : "hjc", "age" : 24, "hobby" : func } with open("a1.txt","wb") as f: f.write(pickle.dumps(info))
# 4.Pickle的取數據: import pickle def func(): print("hello tomorrow!!!") with open("a1.txt","rb") as f: data = pickle.loads(f.read()) data["hobby"]()
# 5 字典直接保存為文件(不推薦)
info = { "name" : "hjc", "age" : 24, "hobby" : func } with open("a1.txt","w") as f: f.write(str(info)) # 能夠直接保存中文,但是無法直接當作json文件來使用loads(),因為保存的是單引號,json使用雙引號。
json與字典的編碼問題
以下內容摘抄自Python 3中的json.dumps,會將中文轉換為unicode編碼后保存
先把這次踩坑的結論放在最前面
1. Python 3已經將unicode作為默認編碼
2. Python 3中的json在做dumps操作時,會將中文轉換成unicode編碼,並以16進制方式存儲,再做逆向操作時,會將unicode編碼轉換回中文
這就解釋了,為什么json.dumps操作后,得到的字符串是\uXXXX。
------------------分割線以下部分純屬扯淡,沒時間的現在可以關閉頁面了-------------------------
如果不知道上面兩點,加之python之前對編碼處理的不好名聲,就會陷入一個問題深坑中。
讀到這里,如果你趕時間,就可以不用往下看了。
爆出問題的代碼如下:
@app.route("/<desc>/<amount>")
def addSimpleRecord(desc, amount):
.....
file.write(json.dumps(buildJson(desc, amount)));
....
整個程序運行正常,但當我打開文件看到保存的中文數據變成了\uXXXX時,頭都大了。
經過了各種嘗試,我發現網上對python3中的編碼問題進行了如下歸納
- \uXXXX是unicode 16進制編碼的表現形式
- 在文件的第一行加上# -*- coding: utf-8 -*-
- 對字符串對象進行str.decode('...').encode('...')
- 對字符串對象進行操作:str.encode('utf-8').decode('unicode_escape')
關於第一條,print("你" == "\u4f60")得到的結果是True
關於第二條,那是python2的故事,在python3中默認的文件編碼就是utf-8。因此,在保存python 3的腳本時,請務必保存為utf-8。
關於第三條,那也是python2的故事,在ptyon3中,字符串默認采用unicode編碼。
關於第四條,最初我是參考 python3 把\u開頭的unicode轉中文,把str形態的unicode轉中文 ,發現不能重現,后來當我用\\uXXXX時,就重現了這篇文章中描述的問題,因為\在python字符串中起轉義作用(我居然給忘記了)。
為什么json.dumps處理過后的中文就變成了\uXXXX呢?原因在這里py_encode_basestring_ascii
- ESCAPE_ASCII = re.compile(r'([\\"]|[^\ -~])')
- HAS_UTF8 = re.compile(b'[\x80-\xff]')
- ESCAPE_DCT = {
- '\\': '\\\\',
- '"''"': '\\"',
- '\b': '\\b',
- '\f': '\\f',
- '\n': '\\n',
- '\r': '\\r',
- '\t': '\\t',
- }
- def py_encode_basestring_ascii(s):
- """Return an ASCII-only JSON representation of a Python string
- """
- def replace(match):
- s = match.group(0)
- try:
- return ESCAPE_DCT[s]
- except KeyError:
- n = ord(s)
- if n < 0x10000:
- return '\\u{0:04x}'.format(n)
- #return '\\u%04x' % (n,)
- else:
- # surrogate pair
- n -= 0x10000
- s1 = 0xd800 | ((n >> 10) & 0x3ff)
- s2 = 0xdc00 | (n & 0x3ff)
- return '\\u{0:04x}\\u{1:04x}'.format(s1, s2)
- return '"' + ESCAPE_ASCII.sub(replace, s) + '"'
關鍵的地方就在:
return '\\u{0:04x}'.format(n)
其中{0:04x}表示取第一個參數,並取長度為4的16進制小寫數字。
json.dumps的參數中有一個參數ensure_ascii,其默認值為True。我想這么做的目的可能是為了跨平台的通用性。
python3 把unicode轉中文,把str形態的unicode轉中文
今天用py3.5爬東西的時候,爬到的是json格式,里面的中文還都是unicode的形式.
講道理的話只要直接輸出就可以了,類似這樣的
>>> print ("\u751F\u5316\u5371\u673A") 生化危機 >>>
軟而坑爹的是他返回的匹配的list是這樣的
['\\u751F\\u5316\\u5371\\u673A']
結果print出來事這樣的
>>> print (a[0]) \u751F\u5316\u5371\u673A >>>
python3以上取消了decode,所以你直接想st.decode(“utf-8”)的話會報str沒有decode方法的錯
最后貼一下解決方案
>>> print (a[0].encode('utf-8').decode('unicode_escape')) 生化危機 >>>
到此為止,python 3的編碼問題總算是告一段落,如有問題,歡迎交流。