天天看點

Python程式設計:Python2編碼問題與pymysql查詢結果亂碼解決1、SyntaxError: Non-ASCII character2、中文變成了?3、UnicodeEncodeError總結

訂閱專欄

Python2編碼一直是個讓人頭疼的問題,能夠讓一個充滿激情的新手,從剛安裝完python解釋器到放棄。

我就曾經放棄過,後來又拿了起來,真是一波多折。

so,如果可能就盡量使用Python3吧

下面我就python2通過pymysql處理查詢結果為例說明

要查詢的資料表(包含中文)

mysql> use demo
mysql> select * from names limit 3;
+----+--------+------+
| id | name   | age  |
+----+--------+------+
|  1 | 大紅   |   24 |
|  2 | 大壯   |   24 |
|  3 | 秀英   |   24 |
+----+--------+------+      

python2原始代碼

from collections import namedtuple
import pymysql

db = pymysql.Connect(
    host="localhost",
    user="root",
    password="123456",
    database="demo",
    port=3306
)

sql = "select name, age from names limit 3"

cursor = db.cursor()
cursor.execute(sql)
rows = cursor.fetchall()
cursor.close()
db.close()

print(rows)


Row = namedtuple("Row", ["name", "age"])
rows = map(Row._make, rows)

for row in rows:
    person = "{}{}".format(row.name, row.age)
    print(person)      

1、SyntaxError: Non-ASCII character

看着好好的代碼,莫名其妙的來個文法錯誤SyntaxError: Non-ASCII character

SyntaxError: Non-ASCII character '\xe5' in file text.py on line 56, 
but no encoding declared; 
see http://python.org/dev/peps/pep-0263/ for details      

根據報錯提示的連結: 

http://python.org/dev/peps/pep-0263/

打開後發現需要在檔案頭加檔案編碼說明

# coding=utf-8      

或者

#!/usr/bin/python
# -*- coding: utf-8 -*-      

2、中文變成了

?

添加完檔案編碼後,繼續運作代碼,代碼檔案中有print(rows)和print(person)列印出來的内容分别是:

(('??', 24), ('??', 24), ('??', 24))

??24
??24
??24      

what? 檢視pymysql.Connect 的源碼,發現有一個參數charset字元集,那麼添加一個字元編碼試試

db = pymysql.Connect(
    host="localhost",
    user="root",
    password="123456",
    database="demo",
    port=3306,
    
    # 添加字元編碼
    charset="utf8"
)      

3、UnicodeEncodeError

添加完編碼字元集參數後,運作又報錯了!

((u'\u5927\u7ea2', 24), (u'\u5927\u58ee', 24), (u'\u79c0\u82f1', 24))

Traceback (most recent call last):
  File "text.py", line 37, in <module>
    person = "{}{}".format(row.name, row.age)
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)      

發現print(rows)已經列印了,而且沒有?,前面帶u,說明是unicode字元

報錯代碼是:person = "{}{}".format(row.name, row.age),使用format格式化報錯

明明已經在檔案開頭指定了檔案的編碼是utf-8了,怎麼還是說unicode呢?

百思不得其解,經過百度,google,發現隻用添加以下代碼就行:

import sys
reload(sys)
sys.setdefaultencoding("utf-8")      
from __future__ import unicode_literals      

推薦使用後者

參考

1.

https://stackoverflow.com/questions/3828723/why-should-we-not-use-sys-setdefaultencodingutf-8-in-a-py-script

2.

https://stackoverflow.com/questions/9942594/unicodeencodeerror-ascii-codec-cant-encode-character-u-xa0-in-position-20

運作代碼檔案,發現輸出正常了

((u'\u5927\u7ea2', 24), (u'\u5927\u58ee', 24), (u'\u79c0\u82f1', 24))

大紅24
大壯24
秀英24      

當然,直接列印整個元組對象是不能直覺的看到内容的,列印出來的是unicode碼,而python3就可以

總結

好了,一路過來解決3個編碼問題,都需要設定編碼為utf-8

報錯 解決 示例
SyntaxError: Non-ASCII character 檔案編碼 # -*- coding: utf-8 -*-
中文變成了? 資料庫連接配接編碼 charset="utf8"
UnicodeEncodeError 引入py3的新特性 from __future__ import unicode_literals

注意,pymysql的編碼設定charset="utf8"中間沒有-

python2中的編碼問題基本可以用以下兩行代碼解決

# -*- coding: utf-8 -*-
from __future__ import unicode_literals      

給出最後的完整代碼

# -*- coding: utf-8 -*-

# @Date    : 2018-12-20
# @Author  : Peng Shiyu

from __future__ import unicode_literals
from collections import namedtuple
import pymysql

db = pymysql.Connect(
    host="localhost",
    user="root",
    password="123456",
    database="demo",
    port=3306,
    charset="utf8"
)

sql = "select name, age from names limit 3"

cursor = db.cursor()
cursor.execute(sql)
rows = cursor.fetchall()
cursor.close()
db.close()

print(rows)


Row = namedtuple("Row", ["name", "age"])
rows = map(Row._make, rows)

for row in rows:
    person = "{}{}".format(row.name, row.age)
    print(person)

"""
((u'\u5927\u7ea2', 24), (u'\u5927\u58ee', 24), (u'\u79c0\u82f1', 24))

大紅24
大壯24
秀英24
"""