Python 开发常见问题集合

日常总结下 Python 开发过程中遇到的坑。

编码

josn.dumps() 中文输出问题

解决:

1
2
errors = ['aaaa', '中文']
print json.dumps(errors, ensure_ascii=False)

list/dict 包含中文时打印编码问题

问题现象:

1
2
3
4
5
6
7
>>> l = ['aaa', '中文']
>>> print l
['aaa', '\xe4\xb8\xad\xe6\x96\x87']

>>> d = {'aaa': '中文'}
>>> print d
{'aaa': '\xe4\xb8\xad\xe6\x96\x87'}

解决:

  • 使用上面 json.dumps 输出中文的方式输出。

  • 将 list/dist 转化成 str 类型后再转义

1
2
3
4
5
>>> print str(['中文'])    # 乱码
['\xe4\xb8\xad\xe6\x96\x87']

>>> print str(['中文']).decode('string_escape') # 正常显示
['中文']
  • 使用其他库(uniout)处理
1
2
3
4
5
6
7
8
9
sudo pip install uniout

>>> import uniout
>>> print l
['aaa', '中文']

>>> import _uniout
>>> print _uniout.unescape(str(d), 'utf8')
{'aaa': '中文'}

字符串和 unicode 间的转化

1
2
3
print s.decode('utf-8')    # str 类型转化成 unicode

print u.encode('utf-8') # unicode 类型转化成 str

os

/os.path.join() 的影响?

问题代码示例:

1
os.path.join('/a/b/c', '/d')   # /d

注意这里 join 的结果是 /d 而不是 /a/b/c/d

总结:os.path.join() 方法的第一个参数之后的所有字符串参数均不能以 / 开头,否则最终结果将是参数从右往左数第一个以 / 开头的值作为路径开头 join 剩余非 / 开头的参数。

说明:Python 这个函数这样子处理的好处在于,方便配置文件配置文件路径。比如,我们在代码中获取某个文件路径示例如下:

  • 当配置中文件路径是绝对路径 /path/to/dst:
1
os.path.join(os.getcwd(), '/path/to/dst')

此时最终的路径会是 /path/to/dst

  • 当配置中文件路径是相对路径 path/to/dst:
1
2
cwd = os.getcwd()  # /home/cjli/proj
os.path.join(cwd, 'path/to/dst')

此时最终的路径会是 /home/cjli/proj/path/to/dst

由此可见,如果通过 os.path.join 来获取最终的文件路径,那么程序可以获取的目标文件路径可以通过修改配置而不是修改代码来实现,实际应用中会非常灵。

paramiko

SFTP

递归调用 listdir_iter() 遍历远程文件目录时程序一直 hang?

问题代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
def traverse_remote_dir(self, sftp_client, dir_path):
if len(sftp_client.listdir(dir_path)) < 1:
sftp_client.rmdir(dir_path)
Log.warning('No any files or directories in :' + dir_path)
return

result = {
dir_path: {
'latest': {},
'task_map': [],
'children': {},
}
}
dirgen = sftp_client.listdir_iter(dir_path) # 问题代码所在
for file_obj in dirgen:
filepath = os.path.join(dir_path, file_obj.filename)
filemtime = file_obj.st_mtime
if stat.S_ISDIR(file_obj.st_mode):
result[dir_path]['children'] = self.traverse_remote_dir(
sftp_client, filepath)
continue
latest = result[dir_path]['latest']
if len(latest) < 1 or filemtime > latest['mtime']:
result[dir_path]['latest']['path'] = filepath
result[dir_path]['latest']['mtime'] = filemtime

result[dir_path]['task_map'].append({
'path': filepath,
'mtime': filemtime
})

return result

问题现象是当遍历远程路径遇到目录时,程序会一直卡住。

strce -p 查看会出现 futex(0x2a5fcc0, FUTEX_WAIT_PRIVATE, 0, NULL 系统调用。

原因:暂时未知。

解决:问题行代码 listdir_iter() 换成 listdir_attr()

mysql-python/MySQLdb

centos 7 执行 pip install mysql-python 时出现 “mysql_config command not found ”?

原因:mysql-python 包是 C 语言写的,安装时候需要编译,因此需要提前安装好依赖。

解决:

1
yum install mariadb-devel gcc python-devel    # python-devel 有可能根据实际执行的版本替换比如 python36u-devel

存储到数据库的中文乱码

原因:数据库连接没有指定 utf-8。

解决:在确认程序中的数据都是 utf-8 的前提下,连接 mysql 的时候需要指定客户端连接编码。示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import MySQLdb as db

conn = db.connect(
host=host,
port=port,
user=user,
passwd=passwd,
db=dbname,
use_unicode=True,
charset='utf8'
)
conn.set_character_set('utf8')

cur = conn.cursor()
# cur.execute('SET NAMES utf8;')
# cur.execute('SET CHARACTER SET utf8;')
# cur.execute('SET character_set_connection=utf8;')

参考