Python警告unicode问题

时间:2015-10-08 16:35:37

标签: python unicode

我知道在网上的一些地方已经谈过这个问题,但是我想不出答案,所以我想问一下。

我有以下python代码调用存储过程需要一个整数,但是我给它一个非ascii£符号u'\xa3',这使得它'unicode its pants'!

# -*- coding: utf-8 -*-
import MySQLdb
import config.default as cfg

conn = MySQLdb.connect(
    host=cfg.db_host,
    user=cfg.db_user,
    passwd=cfg.db_pass,
    db=cfg.db_name,
    use_unicode=True
)

curs = conn.cursor(MySQLdb.cursors.DictCursor)

try:
    curs.callproc('get_user_by_id', [u'\xa3'])
    curs.nextset()
except MySQLdb.Warning, e:
    print e.message

curs.close()
conn.close()

以上将导致以下错误,因为存储过程需要int,因此生成警告,该数据库以unicode形式从数据库返回:

UnicodeEncodeError: 'ascii' codec can't encode character u'\xa3' in position 26: ordinal not in range(128)

如果我将use_unicode设置为默认值False,那么我会收到警告:

Warning: Incorrect integer value: '£' for column 'p_user_id' at row 1
  curs.nextset()

你们中的大多数人可能都知道python的unicode异常问题有点烦人(至少对我而且可能是非ascii语言ppl)

我找到了解决这个问题的几种方法:

1)覆盖_warning_check中的MySQLdb.BaseCursor功能并注释掉warn(w[-1], self.Warning, 3)行(约117行) - 不喜欢它,因为我希望看到警告

2)导入警告,然后添加warnings.filterwarnings('ignore', category=MySQLdb.Warning) - 并未真正解决其他unicode警告的问题

3)将warnings.py文件复制到我的应用程序的根目录,并更改formatwarning函数以将消息格式化为unicode: - 到目前为止似乎是最好的解决方案,但它是一个python核心文件!

def formatwarning(message, category, filename, lineno, line=None):
    """Function to format a warning the standard way."""
    # s = "%s:%s: %s: %s\n" % (filename, lineno, category.__name__, message)
    s = u"{}:{}: {}: {}\n".format(filename, lineno, category.__name__, message)
    line = linecache.getline(filename, lineno) if line is None else line
    if line:
        line = line.strip()
        s += "  %s\n" % line
    return s

当然有更好的方法吗?

1 个答案:

答案 0 :(得分:0)

这似乎不再是一个问题,可能是由于模块或MySQL服务器的更新 - 运行MySQL 5.7.12。

我也从使用use_unicode更改为设置字符集,因此我的连接字符串如下所示:

MySQLdb.connect(host=DB_HOST, user=DB_USER, passwd=DB_PSWD, db=DB_NAME, charset='UTF8', connect_timeout=5)

但是,我正在调整一个高吞吐量的应用程序,并发现通常Mysqldb模块在每次执行后请求警告,花费几毫秒。但是发现在执行之前向游标添加curs._defer_warnings = True会阻止它,然后你可以使用self.warnings = curs._warnings来获取警告的数量。

curs = self.conn.cursor(cursors.DictCursor)
curs._defer_warnings = True
try:
    self.affected = curs.execute(sql, args)
    self.warnings = curs._warnings
    if sql.lower().startswith('insert'):
        self.lastrowid = curs.lastrowid
    elif sql.lower().startswith('select'):
        self.data = curs.fetchall()
except MySQLError, e:
    if e.args[0] == 1064:
        raise Exception("MySQL Error [1064]: Error in SQL syntax")
    else:
        raise Exception("MySQL Error [{}]: {}".format(e.args[0], e.args[1]))
finally:
    curs.close()