软件测试学习 之 Pycharm 乱码问题(四)控制台中执行python语句显示乱码
笔者使用的python解释器版为
python3.7,pycharm版本为pycharm2018.3
如无特殊说明,代码均在此环境执行
目录
一、pycharm控制台
二、修改项目编码对于控制台的影响
三、print函数的执行过程
四、print函数与sys.stdout.encoding的关系
五、python控制台与系统命令
一、pycharm控制台
常见的pycharm的控制台有三个:
运行输出控制台,命令终端控制台,python控制台(ipython控制台)

设置ipython控制台,如果安装有ipython则启动

是否有ipython,可以通过选择编译器查看

选择python控制台时,pycharm会自动转为ipython

二、修改项目编码对于控制台的影响
之前在研究乱码问题时,已经知道,修改项目编码会直接影响项目文件的显示
Pycharm 乱码问题(一) 文件和代码内容乱码
这里再来谈谈项目编码对与控制台的影响
首先,将项目编码由原来的UTF-8改为GBK

然后分别使用python源文件和终端获取如下几个值
- 系统环境变量里是否包含PYTHONIOENCODING
- 系统环境变量PYTHONIOENCODING的值
- 是否是
tty设备 - 当前标准输出编码
- 注:
tty设备包括如下几种
(1)串口端口终端
(2)控制终端
(3)伪终端
(4)控制台终端
(5)虚拟终端
详见 tty各种设备的情况
获取方式如下:
# 系统环境变量里是否包含PYTHONIOENCODING
os.environ.__contains__('PYTHONIOENCODING')
# 系统环境变量PYTHONIOENCODING的值
os.environ.get('PYTHONIOENCODING')
# 是否是tty设备
sys.stdout.isatty()
# 标准输出编码
sys.stdout.encoding
使用各个终端分别执行
run—运行控制台
代码如下:
import sys
import os
print("os.environ.__contains__('PYTHONIOENCODING'): ",
os.environ.__contains__('PYTHONIOENCODING'))
if os.environ.__contains__('PYTHONIOENCODING'):
print("os.environ.get('PYTHONIOENCODING'): ",
os.environ.get('PYTHONIOENCODING'))
print('sys.stdout.isatty(): ', sys.stdout.isatty())
print('sys.stdout.encoding: ', sys.stdout.encoding)
运行结果如下:
os.environ.__contains__('PYTHONIOENCODING'): True
os.environ.get('PYTHONIOENCODING'): GBK
sys.stdout.isatty(): False
sys.stdout.encoding: GBK
在pycharm中显示如图所示

输出编码sys.stdout.encoding的值随着项目编码而改变,同时
环境变量PYTHONIOENCODING的值也随之改变
此时,强制改变PYTHONIOENCODING的值,不会影响sys.stdout.encoding的值
os.environ.update(PYTHONIOENCODING='UTF-8')
print("os.environ.get('PYTHONIOENCODING'): ",
os.environ.get('PYTHONIOENCODING'))
print('sys.stdout.encoding: ', sys.stdout.encoding)
结果如下:
os.environ.get('PYTHONIOENCODING'): UTF-8
sys.stdout.encoding: GBK
Terminal—本地系统命令行终端
执行结果如下:
>>> import sys
>>> import os
>>> os.environ.__contains__('PYTHONIOENCODING')
False
>>> os.environ.get('PYTHONIOENCODING') # 获取结果为空时,不报错,也不输出结果
>>> sys.stdout.isatty()
True
>>> sys.stdout.encoding
'utf-8'
>>>
在pycharm中显示如下:

(根据结果推测)
本地系统命令行终端 = cmd控制台,不受pycharm配置影响,系统中没有添加环境变量,输出编码也没有发生变化
Python Console —python / ipython控制台
In[16]: import os
In[17]: import sys
In[18]: os.environ.__contains__('PYTHONIOENCODING')
Out[18]: True
In[19]: os.environ.get('PYTHONIOENCODING')
Out[19]: 'GBK'
In[20]: sys.stdout.isatty()
Out[20]: False
In[21]: sys.stdout.encoding
Out[21]: 'GBK'
在pycharm中显示如下图所示:

结果与运行控制台一致,随着项目编码的改变,环境变量PYTHONIOENCODING和标准输出编码sys.stdout.encoding同时发生变化
此时,若强制改变PYTHONIOENCODING的值,同样不会影响sys.stdout.encoding
os.environ.update(PYTHONIOENCODING='UTF-8')
os.environ.get('PYTHONIOENCODING')
Out[23]: 'UTF-8'
sys.stdout.encoding
Out[24]: 'GBK'
结论:
项目编码会影响程序运行控制台和python控制台,不影响本地系统终端项目编码会影响运行控制台的标准输出编码和控制台编码项目编码会影响python控制台的标准输出编码,不影响控制台编码
三、print函数的执行过程
简单来说就是,编码 → 解码 → 字体显示
python负责将内存中的unicode字符串编码成字节流bytes,交给终端控制台,控制台将字节序列再解码为unicode字符串,
控制台将字符映射到本地unicode字体库(窗体设置的字体)显示
其中任意一步出问题都可能会导致
报错,乱码或者显示异常,并且编码和解码的方式必须一致
可用以下代码模拟这个过程,
不过,由于python程序编码/解码出错时,会报出异常终止执行,而控制台往往不会,所以需要增加’ignore’参数,来模拟控制台的解码
'百度一下'.encode('gbk').decode('gbk','ignore')
# 与上述语句效果等同
bytes('百度一下','utf-8').decode('utf-8','ignore')
# 采用unicode的方式,与上述效果等同
bytes('\u767e\u5ea6\u4e00\u4e0b','utf-8').decode('utf-8','ignore')
print的完整格式为
print(objects,sep,end,file,flush),其中后面4个为可选参数
官方文档:
print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)
-
sep
在输出字符串之间插入指定字符串,默认是空格,例如:>>>print("a","b","c",sep="**") a**b**c -
end
在print输出语句的结尾加上指定字符串,默认是换行(\n),例如:>>>print("a",end="$") a$print默认是换行,即输出语句后自动切换到下一行,对于python3来说,如果要实现输出不换行的功能,那么可以设置end=’’(python2可以在print语句之后加“,”实现不换行的功能)
-
file
将文本输入到file-like对象中,可以是文件,数据流等等,默认是sys.stdout>>>f = open('abc.txt','w') >>>print('a',file=f) -
flush
flush值为True或者False,默认为Flase,表示是否立刻将输出语句输入到参数file指向的对象中(默认是sys.stdout)例如:>>>f = open('abc.txt','w') >>>print('a',file=f)可以看到abc.txt文件这时为空,只有执行f.close()之后才将内容写进文件。 如果改为:
>>>print('a',file=f,flush=True)则立刻就可以看到文件的内容
四、print函数与sys.stdout.encoding的关系
举个简单的例子:
在项目编码为gbk的情况下,执行如下代码
print('\ufffd') #特殊符号 »
必然会报错
UnicodeEncodeError: ‘gbk’ codec can’t encode character '\ufffd’ in position 0: illegal multibyte sequence
原因很简单,gbk字符集只是unicode的子集,不包含一些特殊字符,因此gbk编码器无法编码特殊字符 '\ufffd’
此时将标准输出的默认编码sys.stdout.encoding改为utf-8
(“或者直接修改项目编码为utf-8)
sys.stdout = io.TextIOWrapper(sys.stdout.buffer,encoding='utf-8')
print('\u00bb') #特殊符号 »
即可正常输出
»
结论:
sys.stdout.encoding直接关系着print函数的编码方式,若与控制台编码方式不一致,则会报错或者显示乱码
#项目编码,标准输出编码与控制台编码均为UTF-8
print(sys.stdout.encoding)
#修改标准输出编码为GBK
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='gbk')
print(sys.stdout.encoding)
print('异常')
输出
----------
UTF-8
gbk
�쳣
五、python控制台与系统命令
当python调用系统命令,如ls,os.system("dir")等时,python控制台会对回显的结果,再次编码和解码,相当于执行了一次print()
例如:
>>> import os
>>> os.system("echo 你好") #显示你好
显示结果:
你好
0
控制台会将系统命令回显的结果做类似如下过程处理
'你好'.encode('utf-8').decode('utf-8','ignore')
- 注:
os.system()是无法获得到系统命令的输出和返回值—‘你好’的,python控制台能看到python命令的执行结果,如果是在py文件中,只能得到函数的返回结果—0,返回值为0,表示命令执行成功 - 补充:
想要获取系统命令的执行结果,可以使用os.popen(),可以实现一个“管道”,从这个命令获取的值可以继续被使用。因为它返回一个文件对象,可以对这个文件对象进行相关的操作。这里不做展开
不过,值得注意的是:
- 在python控制台执行文件—
os.system(‘python xx.py’)时,等同于将输出结果作为print的参数,标准输出编码为python默认编码UTF-8 - 在python控制台执行系统命令(如dir ehco等),分两种情况
(1)在从Terminal切入python控制台执行,等同于将输出结果作为print的参数,标准输出编码为python默认编码UTF-8
(2)在从Pycharm进入python console执行,等同于将输出结果作为print的参数,标准输出编码为本地终端代码页cp936(系统默认编码GBK)
于是,就会出现这样奇怪的现象
在Pycharm中的python console,执行系统命令时,结果中如果包含中文,就会出现乱码
>>> os.system("dir")
������ F �еľ��� ����
�������� 0006-F904
F:\Practice\PycharmProjects\PythonOOP ��Ŀ¼
2019/04/24 15:18 <DIR> .
2019/04/24 15:18 <DIR> ..
2019/04/24 15:52 <DIR> .idea
2019/04/24 15:18 2,861 file_test.py
2019/03/31 23:21 <DIR> venv
2019/04/04 00:08 <DIR> _01_�̳�_��װ�Ͷ�̬
2019/04/04 16:12 <DIR> _02_������������
2019/04/02 00:32 <DIR> _03_α˽�����Ժͷ���
2019/04/01 11:53 <DIR> _04_dz���������
2019/04/07 14:38 <DIR> _05_����ʵ��_����_����_��̬����
2019/04/06 15:00 <DIR> _06_����ģʽ
2019/04/01 11:40 <DIR> _07_���������б�
2019/04/06 16:29 <DIR> _08_�쳣
2019/04/07 12:21 <DIR> _09_��������
2019/04/23 14:13 <DIR> _10_�����
2019/04/24 14:53 <DIR> __pycache__
1 ���ļ� 2,861 �ֽ�
15 ��Ŀ¼ 41,792,479,232 �����ֽ�
而查看项目编码和标准输出编码和控制台编码,均为UTF-8
>>> import sys
>>> sys.stdout.encoding
'UTF-8'
此时,查看本地终端代码页可以发现问题所在
>>> os.system("chcp")
�����ҳ: 936
0
修改代码页为65001,即UTF-8
>>> os.system("chcp 65001")
Active code page: 65001
0
再次执行,即可显示正常
>>> os.system("dir")
Volume in drive F is 数据
Volume Serial Number is 0006-F904
Directory of F:\Practice\PycharmProjects\PythonOOP
2019/04/24 15:18 <DIR> .
2019/04/24 15:18 <DIR> ..
2019/04/24 16:09 <DIR> .idea
2019/04/24 15:18 2,861 file_test.py
2019/03/31 23:21 <DIR> venv
2019/04/04 00:08 <DIR> _01_继承_封装和多态
2019/04/04 16:12 <DIR> _02_遍历对象属性
2019/04/02 00:32 <DIR> _03_伪私有属性和方法
2019/04/01 11:53 <DIR> _04_浅拷贝与深拷贝
2019/04/07 14:38 <DIR> _05_类与实例_属性_方法_静态方法
2019/04/06 15:00 <DIR> _06_单例模式
2019/04/01 11:40 <DIR> _07_遍历对象列表
2019/04/06 16:29 <DIR> _08_异常
2019/04/07 12:21 <DIR> _09_导入包与模块
2019/04/23 14:13 <DIR> _10_文件操作
2019/04/24 14:53 <DIR> __pycache__
1 File(s) 2,861 bytes
15 Dir(s) 41,792,479,232 bytes free
0
另外,如果在pycharm中启用ipython的话,还可以采取如下!chcp 65001的方式修改代码页,
代码演示如下:
In[3]: import os
In[4]: os.system("echo 你好")
���
Out[4]: 0
In[5]: !chcp 65001
Active code page: 65001
In[6]: os.system("echo 你好")
你好
Out[6]: 0
注:
- 为避免今后调用系统命令总是要做这步操作,可以将其配置在控制台的启动脚本中
File|Settings|Build, Execution, Deployment|Console|Python Console

每次启动控制台时,脚本会自动执行

以上大致就是自己总结的,关于控制台中执行python语句显示乱码的原因,以及一些解决的办法
部分内容参考以下文章整理
PyCharm----中文显示乱码的解决方法总结
作者:n_laomomo
出处:csdn
PyCharm Python Console 中文输出乱码
作者: 月尽天明_
出处:csdn
python print的参数介绍
作者:几度夏
出处:博客园
python字符编码错误 UnicodeEncodeError: ‘gbk’ codec can’t encode character ‘\xxx’
作者:阿锋佬/zjfeng
出处:bbsmax/博客园
UnicodeEncodeError: ‘gbk’ codec can’t encode character '\ufffd’等类似问题
作者:周小董
出处:csdn
更多推荐
所有评论(0)