sys.argv作为Python 3k中的字节

Dav*_*vid 8 python string unicode python-3.x

由于Python 3k引入了字符串和字节之间的严格区分,因此数组sys.argv中的命令行参数显示为字符串.有时需要将参数视为字节,例如,在传递不需要在Unix中的任何特定字符编码的路径时.

我们来看一个例子吧.下面是一个简短的Python 3k程序argv.py:

import sys

print(sys.argv[1])
print(b'bytes')
Run Code Online (Sandbox Code Playgroud)

当它执行python3.1 argv.py français时产生预期的输出:

法语

b'bytes'

请注意,参数français是我的语言环境编码.但是,当我们以不同的编码传递参数时,我们会得到一个错误:python3.1 argv.py `echo français|iconv -t latin1`

Traceback (most recent call last):
  File "argv.py", line 3, in <module>
    print(sys.argv[1])
  UnicodeEncodeError: 'utf-8' codec can't encode character '\udce7' in position 4: surrogates not allowed
Run Code Online (Sandbox Code Playgroud)

我们如何通过命令行参数将二进制数据传递给Python 3k程序?使用示例是将路径传递给使用其他语言环境的用户的文件.

nco*_*lan 9

请注意,错误是一个UnicodeEncodeError而不是一个UnicodeDecodeError.Python保留了在命令行上传递的确切字节(通过PEP 383 surrogateescape错误处理程序),但这些字节不是有效的UTF-8,因此无法编码为写入控制台.

处理此问题的最佳方法是使用正确编码的应用程序级别知识来重新解释应用程序内的命令行参数,如以下示例代码所示:

$ python3.2 -c "import os, sys; print(os.fsencode(sys.argv[1]).decode('latin-1'))" `echo français|iconv -t latin1`
français
Run Code Online (Sandbox Code Playgroud)

os.fsencode功能调用反转处理命令行参数时的Python自动应用所述变换.然后,decode('latin-1')方法调用执行正确的转换,以获得正确解码的字符串.

Python的3.2添加os.fsencode到专门做这类问题更容易处理.

对于Python 3.1,os.fsencode(sys.argv[1])is 的等效构造sys.argv[1].encode(sys.getfilesystemencoding(), 'surrogateescape')

编辑2013年2月:更新为Python 3.2+,并避免假设Python自动检测"UTF-8"作为命令行编码

  • 确实.虽然,在Python 3.3中,使用`os.fsencode`更容易.我还提交了一个错误,指出sys.argv文档应该真正解释这一点. (2认同)

JBe*_*rdo 1

你可以做:

sys.argv[1].encode()或者,如果您知道编码,请将其用作参数或调用bytes(sys.argv[1], 'latin-1')

两者都应该为您提供 unicode 字符串的字节表示形式。

默认情况下,Python3 使用 UTF-8。

  • 不,Python不一定使用UTF8,这取决于平台。 (3认同)
  • 不,事情没那么简单。终端的默认编码不一定是 UTF-8,文件系统的默认编码也不是。我引用“有一个依赖于平台的默认编码,在 Unixy 平台上可以使用 LANG 环境变量(有时也使用一些其他特定于平台的区域设置相关的环境变量)进行设置。在很多情况下,但不是全部,系统默认值是 UTF-8;你永远不应该指望这个默认值。” 事实上 cp1252 是 Windows 上的默认值。不过 .py 文件的默认值是 UTF8。 (3认同)
  • @Lennart Python 3 确实使用 UTF-8 作为默认编码。 (2认同)
  • 我同意 Lennart 的观点,认为事情没那么简单 - 需要反转自动代理转义过程才能获取原始字节,然后可以根据应用程序特定知识对其进行处理。 (2认同)