修复在python中使用environb时的导入错误

2024-06-07 09:30:18 发布

您现在位置:Python中文网/ 问答频道 /正文

from os import environb as environ

在Windows Anacondapython 3.6安装中输入上述命令时,我得到以下错误:

ImportError: cannot import name 'environb'。在

这似乎是因为

environb is only available if supports_bytes_environ is True.

以及

supports_bytes_environ在Windows上为False。在

有办法绕过这个问题吗?在

参考号:https://docs.python.org/3/library/os.html#os.environb

具体地说,我在GRASS GIS Python scripting library中发现了这个错误。在


Tags: fromimport命令bytesisoswindowsas
2条回答

首先:你可能根本不需要os.environb。在

我将介绍在开发Python软件时为什么不这样做,并在最后介绍GRASS GIS以及如何正确地修复该项目。在

为什么你不需要这个东西

在非Windows系统上,只有当您需要从环境中访问原始二进制数据时,才需要使用os.environb映射,而不需要根据当前区域设置将其解码为Unicode。您可能希望拥有该访问权限,因为区域设置可能错误,或者您希望将二进制数据从环境变量传递到程序,而不必使用区域设置和surrogateescape错误处理程序对其进行重新编码,或者以不同的编码方式将数据传递给另一个程序,同样不必首先强制创建surrogateescape解码字符串。(我掩盖了这样一个事实:在POSIX中,您can't use nulls in environment variables但这与此无关)。在

在Windows上,您不需要这样做,因为在那个操作系统上,环境变量已经作为Unicode数据传递给Python。在没有二进制编码的情况下,你就不能接受二进制编码的数据。os.environb在Windows上没有任何作用!在

因此,如果您创建跨平台软件,您应该使用os.environ,并要求正确配置语言环境,而不必担心os.environb。在

用防御性代码代替

有时需要二进制环境数据访问吗?然后,下一个选项可以是用ImportError保护符对缺少的属性进行防御性编码,并接受它丢失的事实:

try:
    from os import environb
except ImportError:
    environb = None

# ...

if environb is not None:
    # ... it is available, use it

满的操作系统环境替换

最后一个选择是,对于某些第三方希望os.environb仍然可用而您无法更改的情况,或者您有一个很难更新的大型代码库的情况,就是只为Windows创建os.environb对象。在

这并不难;只需根据需要对原始os.environ中的数据进行编码,并在设置新的键或值时再次对其进行解码。POSIX的os.environ对象已经做了相同的事情,除了在另一个方向上,因此我们可以重用相同的基础设施:

^{pr2}$

这将创建相同类型的映射对象,该对象完全支持获取和设置环境变量,对该对象的更改将在os.environ中可见,反之亦然:

>>> os.environ
environ({'FOO': 'bar baz', 'SPAM': 'håm'})
>>> os.environb
environ({b'FOO': b'bar baz', b'SPAM': b'h\xc3\xa5m'})
>>> os.environb[b'eric'] = 'Îdlé'.encode('utf8')
>>> os.environ
environ({'FOO': 'bar baz', 'SPAM': 'håm', 'eric': 'Îdlé'})
>>> del os.environ['FOO']
>>> os.environb
environ({b'SPAM': b'h\xc3\xa5m', b'eric': b'\xc3\x8edl\xc3\xa9'})

草地地理信息系统

在你提到的评论中,你正在尝试让GRASS GIS工作。在Python2和Python3上,这个项目只是做了一个错误的选择,将一个环境变量设置为bytes,而且不仅对于Windows,而且对于所有需要寻址的平台都存在问题。在

它们try to use ^{} as a replacement for ^{},然后使用朴素的引用方法从sys.argv生成值。同时,同一个模块使用os.environ来满足所有其他环境变量的需要。在

在他们使用的lib/python/script/core.py的顶部

# python3
# ...
from os import environb as environ

然后在该映射中存储一个变量(在def parser():函数定义中):

cmdline = [basename(encode(sys.argv[0]))]
cmdline += [b'"' + encode(arg) + b'"' for arg in sys.argv[1:]]
environ[b'CMDLINE'] = b' '.join(cmdline)

b'"' + encode(arg) + b'"'是一种简单的引用值的方法,以避免子shell出现问题,但它不能处理嵌入的引号。在

这是一个字节值。sys.argv是python3上的Unicode字符串列表,python2上的bytestrings。这在任何一个Python版本上都遵循os.environ数据类型,因此在任何一个Python版本上,数据都应该作为str类型来处理。在

为了引用shell解释中的值,Python有^{} function,它碰巧在python2和python3上都是pipes.quotes()。在

{traceback>可以完全避免导入错误^ 1您的计算机所在位置):

# 1. at the top, add an import
import pipes

# 2. remove the `from os import environb as environ` line altogether

# 3. in def parse(), use
cmdline = [basename(sys.argv[0])]
cmdline += (pipes.quote(a) for a in sys.argv[1:])
os.environ['CMDLINE'] = ' '.join(cmdline)

我将把这个报告给GRASS GIS项目,这样他们就可以在将来的版本中修复这个问题。在

在Windows上,os模块没有environb属性,因此无法加载它。但是,您可以手动添加:

首先,将os加载到全局命名空间中:

import os

将其重载到os模块中。这将修改已加载的模块:

^{pr2}$

现在,如果运行from os import environb as environ,python将看到os已经导入,并且不会再次尝试加载它。在

environ[b'PATH']

>>> b'C:\\Windows\\System32'

如果还需要能够设置环境变量,则可以使用以下方法提供双向映射:

class Environb(object):
    def __init__(self):
        pass
    def __getitem__(self, item):
        return bytes(os.environ[item.decode('utf8')], encoding='utf-8')
    def __setitem__(self, key, item):
        os.environ[key.decode('utf8')] = item.decode('utf8')

os.environb = Environb()

os.environb[b'FOO'] = b'BAR'
print(os.environ['FOO']

>>> 'BAR'

相关问题 更多 >

    热门问题