我的一些用户报告说,当主机名包含非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发生异常)
答案 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
,你在做什么?