u参数
有的时候在运行Python的时候,会遇到python -u xx.py
,这是什么意思呢?
背景
python中标准错误(std.err)和标准输出(std.out)的输出规则:标准输出默认需要缓存后再输出到屏幕,而标准错误则直接打印到屏幕。如在test.py
中有如下内容:
1 | import sys |
其中sys.stdout.write()和sys.stderr.write()均是向屏幕打印的语句。其实python中的print语句就是调用了sys.stdout.write(),例如在打印对象调用print obj 时,事实上是调用了 sys.stdout.write(obj+’\n’)。
预想的结果是:
1 | Stdout1Stderr1Stdout2Stderr2 |
实际的结果为:
1 | Stderr1Stderr2Stdout1Stdout2 |
原因:是python缓存机制,虽然stderr和stdout默认都是指向屏幕的,但是stderr是无缓存的,程序往stderr输出一个字符,就会在屏幕上显示一个;而stdout是有缓存的,只有遇到换行或者积累到一定的大小,才会显示出来。这就是为什么上面的会最先显示两个stderr的原因。
注意要使用
python test.py
才能验证,不要在ipython中。
-u参数的作用
python命令加上-u(unbuffered)参数后会强制其标准输出也同标准错误一样不通过缓存直接打印到屏幕。
运行结果:
1 | Stdout1Stderr1Stdout2Stderr2 |
字符串前u,r,b
u/U:表示unicode字符串。不是仅仅是针对中文, 可以针对任何的字符串,代表是对字符串进行unicode编码。
r/R:非转义的原始字符串。与普通字符相比,其他相对特殊的字符,其中可能包含转义字符,即那些,反斜杠加上对应字母,表示对应的特殊含义的,比如最常见的”\n”表示换行,”\t”表示Tab等。而如果是以r开头,那么说明后面的字符,都是普通的字符了,即如果是“\n”那么表示一个反斜杠字符,一个字母n,而不是表示换行了。以r开头的字符,常用于正则表达式,对应着re模块。变量前面可以添加repr
。
b:bytes。
字符编码
字符在内存中的编码
字符在内存里的表示是unicode,如果要存盘或者发到网络就经过编码,具体为使用encode
函数将其转为bytes形式,然后对端收到依次解码,具体为使用decode
函数将其转为str形式。
Python 3里面,str在内存里是unicode表示的,所以’中文’ == ‘\u4e2d\u6587’,类型都是str。
1 | '\u4e2d\u6587' |
对str编码,本质上还是对str表示的字符编码,可以用ascii(如果字符属于ascii字符集的话),也可以用utf-8,也可以用gb2312(中文),都行。但是注意并没有unicode这个encode形式。
1 | '\u0041').encode('ascii') ( |
编码后是bytes,俗称的01010101,如果这个010101不在ascii的表示范围内,就会显示成\x(010101的十六进制形式)。
这就是说,像汉字编码成bytes以后,去查看这个bytes肯定只能看到\x系列,因为这个bytes的内容肯定不在ascii范围内;但如果换英文,就可以看到对应的英文字母,不过不要误会,本质上它还是没有含义的010101而不是字符。
1 | "abc".encode('utf-8') |
由于对同一个英文字符,ascii编码和utf-8编码的结果是一致的,所以用一个编码然后再另一个解码,是可以成功还原的。不过一般是不会这么做的。
1 | >>>'abc'.encode('ascii').decode('utf-8') |
爬虫若拿到的是形如0101的bytes,首先会指定一个编码做decode,这时候可能会碰到部分不符合出错,可以加上ignore参数试试。
1 | b'\xe4\xb8\xad\xff'.decode('utf-8', errors='ignore') |
ord函数获取字符的整数表示和chr数把编码转换为对应的字符
1 | ord('A') |
另外,对str和对bytes用len,意义是不同的。
len(str)统计字符数,len(bytes)统计bytes数,即——这串010101一共是多少个bits,除以8就是bytes。
1 | '中文') len( |
如何判断字符串编码方式
我们经常遇到的编码其实主要的就只有三种:utf-8,gbk,unicode
- unicode一般是
\u
带头的,然后后面跟四位数字或字母,例如\u6d4b\u8bd5
,一个\u
对应一个汉字 - utf-8一般是
\x
带头的,后面跟两位字母或数字,例如\xe6\xb5\x8b\xe8\xaf\x95\xe5\x95\x8a
,三个\x
代表一个汉字 - gbk一般是
\x
带头的,后面跟两位字母或数字,例如\xb2\xe2\xca\xd4\xb0\xa1
,两个\x
代表一个汉字。
除了粗略的根据是否乱码看编码方式外,还可以用chardet模块猜测、
1 | import chardet |
输出:
1 | {'encoding': 'utf-8', 'confidence': 0.99, 'language': ''} |
chardet模块可以计算这个字符串是某个编码的概率,基本对于99%的应用场景,这个模块都够用了。
\x字符串转码
在使用Python的时候,经常遇到类似于\xe4\xbd\xa0\xe5\xa5\xbd\xe4\xb8\x96\xe7\x95\x8c
的字符串,其实它是utf-8编码,但数据类型是字符串类型,而不是bytes类型的utf-8编码。如果我们需要将\x开头的字符串编码转换中文。
方法一:先将字符串编码指定为unicode_escape,
1 | s = '\xe4\xbd\xa0\xe5\xa5\xbd\xe4\xb8\x96\xe7\x95\x8c' |
接着再对bytes类型进行utf-8解码,得到字符串,将字符串中的 “ \x “ 替换为 “ % “,
1 | # bytes to string |
最后利用urllib中的unquote方法将url编码解码,得到中文
1 | import urllib.parse |
方法二:
1 | s = '\xe4\xbd\xa0\xe5\xa5\xbd\xe4\xb8\x96\xe7\x95\x8c' |
\u字符串转码
在使用Python的时候,经常遇到类似于'\u5403\u9e21\u6218\u573a'
的字符串,其实它是Unicode编码,可以直接解码。
1 | In [63]: s = '\u5403\u9e21\u6218\u573a' |
关于
unicode-escape
以及raw-unicode-escape
,可以参考codecs —- 编解码器注册和相关基类。
参考
解析python 命令的-u参数
关于\x开头的字符串编码转换中文解决方法
【Python】笔记:关于\u和\x
python中的编码和解码及\x和\u问题
python学习:字符串前面添加u,r,b的含义
python对变量的字符串不转义 变量如何加r
https://blog.csdn.net/mijichui2153/article/details/105516152
不得不知道的Python字符串编码相关的知识