我是否可以将其编写为与python 2.x和3.x一起使用,而不对其进行明确测试?
# -*- coding: utf-8 -*-
from __future__ import (unicode_literals, division, absolute_import, print_function)
import os
import sys
if (sys.version_info[0] > 2):
# python 3.x
os.environ['foo'] = 'bár'
print(os.environ['foo'])
else:
# python 2.x
os.environ['foo'] = 'bár'.encode('utf8')
print(os.environ['foo'].decode('utf8'))
答案 0 :(得分:4)
设置时,可以使用异常处理;在Python 2上尝试将环境变量设置为unicode
对象会引发异常:
try:
# Python 3
os.environ['foo'] = 'bár'
except UnicodeEncodeError:
# Python 2
os.environ['foo'] = 'bár'.encode('utf8')
获取时,尝试使用decode
方法;它在Python 3中失败并出现属性错误:
try:
# Python 2
print(os.environ['foo'].decode('utf8'))
except AttributeError:
# Python 3
print(os.environ['foo'])
答案 1 :(得分:1)
总的来说,我认为Martijn的回答是最好的答案,但是如果你因为某种原因正在寻找替代方案,我会在一段时间内成功地使用它:
os.environ[key] = {
type(''): lambda x: x.encode('utf-8'), # Python 2
str: lambda x: x, # Python 3
}.get(type(value), str)(value)
这有点棘手,但基本上在python2中,dict看起来像这样:
{unicode: lambda x: x.encode('utf-8'),
str: lambda x: x}
并在python3中它看起来像这样:
{str: lambda x: x}
这是因为python3中的type('')
是str
,所以第二个str
是第一个body {
background-color: rgb(224,224,224,0.6);
background: url(../img/backlogo.png),url(../img/backlogo2.png);
}
。然后它从dict中获取相应的lambda,将你的值转换为os.environ dict所需的格式。
这样做的好处是,如果您使用覆盖率报告工具,则dict将计为单个语句,并且python2和3将报告100%覆盖率,即使一个使用一个lambda而另一个使用另一个。如果你没有像我一样过于沉迷于100%的代码覆盖率,那么try / except方法通常更容易理解,更加pythonic和更惯用。
答案 2 :(得分:0)
编辑:我想我可能误解了您的问题。我认为你的问题涉及到每次访问os.environ
时都不必测试python版本。但是,我相信你可能意味着如何在没有明确查看版本信息的情况下检查python版本。
如果在python 2上你可以用你自己的处理编码和解码的字典替换os.environ
。或者作为一种更保守的方法,您可以创建一个对象,在必要时对字符串进行编码和解码,然后只通过此包装器访问os.environ
。例如
取代os.environ
# -*- coding: utf-8 -*-
from __future__ import (unicode_literals, division, absolute_import, print_function)
import os
import sys
if sys.version_info[0] < 3:
class _EnvironDict(dict):
def __getitem__(self, key):
return super(_EnvironDict, self).__getitem__(key).decode("utf8")
def __setitem__(self, key, value):
return super(_EnvironDict, self).__setitem__(key, value.encode("utf8"))
os.environ = _EnvironDict(os.environ)
s = 'bár'
os.environ['foo'] = s
print(os.environ['foo'])
一种不会取代的保守方法 os.environ
。
# -*- coding: utf-8 -*-
from __future__ import (unicode_literals, division, absolute_import, print_function)
import os
if sys.version_info[0] > 2:
class _Environ(object):
def __init__(self, environ):
self.environ = environ
def __getitem__(self, key):
return self.environ[key]
def __setitem__(self, key, value):
self.environ[key] = value
else:
class _Environ(object):
def __init__(self, environ):
self.environ = environ
def __getitem__(self, key):
return self.environ[key].decode("utf8")
def __setitem__(self, key, value):
self.environ[key] = value.encode("utf8")
environ = _Environ(os.environ)
s = 'bár'
environ['foo'] = s
print(environ['foo'])
答案 3 :(得分:0)
作为替代方案,您可以avoid the unicode_literals
import if your code uses native string API heavily:
#!/usr/bin/env python
from __future__ import division, absolute_import, print_function
import os
os.environ['foo'] = 'bar'
print(os.environ['foo'])
UnicodeEncodeError
的Linux上的默认POSIX(C)语言环境中失败sshing,cron,init.d脚本等)sys.stdout.encoding
不是utf-8 要支持任意Unicode envvars,请在Windows和_wenviron
上使用Unicode API(use bytes on POSIX)。
如果您不需要支持任意值,并且您确信当前区域设置/ sys.stdout.encoding
/ sys.getfilesystemencoding()
可以解码所有值:
import os
import sys
# values are representable in `sys.getfilesystemencoding() in this case
def os_encode(unicode_string, encoding=sys.getfilesystemencoding()):
return unicode_string.encode(encoding, 'strict')
def os_decode(bytestring, encoding=sys.getfilesystemencoding()):
return bytestring.decode(encoding, 'strict')
# bytestrings mapping (all values are decodable so it is ok to use bytes)
_environ = getattr(os, 'environb', os.environ)
def setenv(key, value):
_environ[os_encode(key)] = os_encode(value)
def getenv(key):
return os_decode(_environ[os_encode(key)])
然后你可以启用unicode_literals
导入并在字符串文字中使用非ascii字符:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import division, unicode_literals, absolute_import, print_function
import os
setenv('foo', 'bár')
print(getenv('foo'))