使用socket.gethostname()结果时的UnicodeDecodeError

时间:2009-08-17 21:36:54

标签: python unicode

我的一些用户报告说,当主机名包含非ascii字符时,以下代码可能会引发UnicodeDecodeError(但我无法在Windows Vista计算机上复制此代码):

    self.path = path
    self.lock_file = os.path.abspath(path) + ".lock"
    self.hostname = socket.gethostname()
    self.pid = os.getpid()
    dirname = os.path.dirname(self.lock_file)
    self.unique_name = os.path.join(dirname, "%s.%s" % (self.hostname, self.pid))

追溯的最后一部分是:

    File "taskcoachlib\thirdparty\lockfile\lockfile.pyo", line 537, in FileLock
    File "taskcoachlib\thirdparty\lockfile\lockfile.pyo", line 296, in __init__
    File "taskcoachlib\thirdparty\lockfile\lockfile.pyo", line 175, in __init__
    File "ntpath.pyo", line 102, in join
    UnicodeDecodeError: 'ascii' codec can't decode byte 0xcf in position 7: ordinal not in range(128)

关于为什么以及如何预防它的任何想法?

(Windows XP上的Python 2.5发生异常)

4 个答案:

答案 0 :(得分:1)

我认为gethostname()不一定会给你一个unicode对象。它可能是lockfile的目录名称。无论如何,其中一个是标准字符串,其中包含非ASCII(高于127)字符,另一个是unicode字符串。

问题是ntpath模块中的join函数(Python用于Windows上的os.path的模块)尝试加入给定的参数。这会导致Python尝试将正常的字符串部分转换为unicode。在您的情况下,非unicode字符串似乎具有非ASCII字符。这无法可靠地转换为unicode,因此Python引发了异常。

触发问题的简单方法:

>> from ntpath import join
>> join(u'abc', '\xff')
---------------------------------------------------------------------------
UnicodeDecodeError                        Traceback (most recent call last)

/home/msmits/<ipython console> in <module>()

/usr/lib64/python2.6/ntpath.pyc in join(a, *p)
    106                     path += b
    107                 else:
--> 108                     path += "\\" + b
    109             else:
    110                 # path is not empty and does not end with a backslash,

回溯显示ntpath.py中的问题行。

你可以通过首先将args转换为join()到标准字符串来解决这个问题。或者,您可以先将所有内容转换为unicode。如果给decode()一个特定的编码,则高字节可以转换为unicode。

例如:

>> '\xff'.decode('latin-1')
u'\xff'

答案 1 :(得分:0)

是的,如果主机名或dirname是unicode字符串,则可能会给您错误。最好的解决方案通常是确保两者都是unicode,而不仅仅是其中之一。

答案 2 :(得分:0)

您需要一个基于主机名的唯一字符串,但它中包含Unicode字符。有多种方法可以将Unicode字符串缩减为ascii字符串,具体取决于您希望如何处理非ascii字符。这是一个:

self.hostname = socket.gethostname().encode('ascii', 'replace').replace('?', '_')

这将用问号替换所有非ascii字符,然后将其更改为下划线(因为文件系统不喜欢文件名中的问号)。

答案 3 :(得分:0)

即使socket.gethostname()返回unicode对象,我也不认为您发布的实际代码存在问题。当您尝试使用name以使其首先转换为字符串时会出现问题:

import os
hostname = u'\u1306blah'
pid = os.getpid()
name = os.path.join(os.path.dirname('/tmp/blah.lock'), "%s.%s" % (hostname, pid))

>>> type(name)
<type 'unicode'>

>>> name
u'/tmp/\u1306blah.28292'

>>> print name
/tmp/ጆblah.29032

>>> str(name)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\u1306' in position 5: ordinal not in range(128)

您可以看到str(name)引发了您所看到的异常,但在此之前一切正常。一旦你构建了name,你在做什么?