以此示例摘录。
import subprocess
import os
env = os.environ.copy()
env["FOO"] = u"foo"
subprocess.check_call(["ls", "-l"], env=env)
在Windows上,此操作失败。
C:\Python27\python.exe test.py
Traceback (most recent call last):
File "test.py", line 7, in <module>
subprocess.check_call(["ls", "-l"], env=env)
File "C:\Python27\lib\subprocess.py", line 535, in check_call
retcode = call(*popenargs, **kwargs)
File "C:\Python27\lib\subprocess.py", line 522, in call
return Popen(*popenargs, **kwargs).wait()
File "C:\Python27\lib\subprocess.py", line 710, in __init__
errread, errwrite)
File "C:\Python27\lib\subprocess.py", line 958, in _execute_child
startupinfo)
TypeError: environment can only contain strings
sys.path
documented与unicode完全正常。处理这个(和类似代码)的正确方法是什么,以便一切按预期工作?显而易见的解决方案是在unicode路径上调用.encode()
,但我不确定这是否会导致意外行为。
答案 0 :(得分:4)
在Windows上,将环境字典传递给subprocess.check_call()
归结为将环境传递给CreateProcess()
。那个人实际上可以使用unicode字符串(在CreateProcessW()
化身)。
然而,从python 2.7的 _subprocess.c :
/* TODO: handle unicode command lines? */
/* TODO: handle unicode environment? */
所以你不是第一个想到这个问题的人。
您的问题也没有通用的解决方案,因为环境由被调用的进程解释,其中一些也由系统或系统库自动解释。因此正确的编码取决于目标进程所期望的内容。
不幸的是,虽然Windows上的Python 2确实处理了Unicode,但它实际上将零终止的窄字符串(即PyString_AS_STRING()
返回char *
)传递给系统函数。
现在,Windows本身如何处理两个不同版本的环境变量,因为很明显,它似乎可以传递宽或窄的环境字符串。
目标进程只能访问GetEnvironmentStrings()
,它返回宽字符或窄字符,具体取决于应用程序是使用Unicode支持编译还是不支持。
那么当您从狭窄的(ANSI)进程执行CreateProcess()
以启动Unicode进程时会发生什么?与所有参数相同的事情,它们在调用者的代码页中被解码并转换为Windows版本的UCS-2宽字符。
所以正确的方法可能是使用系统代码页,因为只有这样才能在unicode目标进程中正确显示字符串。这当然会阻止您使用不在该代码页中的字符......
所以,是的,Python 2上的Unicode环境或多或少都会被破坏。