Python 2.6에서 unicode_literals를 사용하는 문제가 있습니까?


101

우리는 이미 Python 2.6에서 실행되는 코드베이스를 얻었습니다. Python 3.0을 준비하기 위해 다음을 추가하기 시작했습니다.

__future__에서 unicode_literals 가져 오기

우리로 .py파일 (우리가 그들을 수정으로). 나는 다른 누군가가 이것을하고 있고 분명하지 않은 문제가 발생했는지 궁금합니다 (아마도 많은 시간을 디버깅 한 후).

답변:


101

내가 유니 코드 문자열로 작업 한 문제의 주요 원인은 utf-8 인코딩 문자열을 유니 코드 문자열과 혼합 할 때입니다.

예를 들어 다음 스크립트를 고려하십시오.

two.py

# encoding: utf-8
name = 'helló wörld from two'

one.py

# encoding: utf-8
from __future__ import unicode_literals
import two
name = 'helló wörld from one'
print name + two.name

실행의 출력 python one.py은 다음과 같습니다.

Traceback (most recent call last):
  File "one.py", line 5, in <module>
    print name + two.name
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 4: ordinal not in range(128)

이 예에서, two.nameUTF-8 인코딩 한 문자열 (유니 코드)는 가져 오지 않았기 때문에이다 unicode_literals, 그리고 one.name유니 코드 문자열입니다. 두 가지를 혼합하면 파이썬은 인코딩 된 문자열 (ascii라고 가정)을 디코딩하고이를 유니 코드로 변환하려고 시도하고 실패합니다. 당신이 그렇게한다면 그것은 작동 할 것 print name + two.name.decode('utf-8')입니다.

문자열을 인코딩하고 나중에 혼합하려고하면 동일한 일이 발생할 수 있습니다. 예를 들어 다음과 같이 작동합니다.

# encoding: utf-8
html = '<html><body>helló wörld</body></html>'
if isinstance(html, unicode):
    html = html.encode('utf-8')
print 'DEBUG: %s' % html

산출:

DEBUG: <html><body>helló wörld</body></html>

그러나 추가 한 후에는 import unicode_literals다음을 수행하지 않습니다.

# encoding: utf-8
from __future__ import unicode_literals
html = '<html><body>helló wörld</body></html>'
if isinstance(html, unicode):
    html = html.encode('utf-8')
print 'DEBUG: %s' % html

산출:

Traceback (most recent call last):
  File "test.py", line 6, in <module>
    print 'DEBUG: %s' % html
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 16: ordinal not in range(128)

'DEBUG: %s'은 유니 코드 문자열 이기 때문에 실패 하므로 파이썬은 디코딩을 시도합니다 html. 인쇄를 수정하는 몇 가지 방법은 print str('DEBUG: %s') % html또는 print 'DEBUG: %s' % html.decode('utf-8').

이것이 유니 코드 문자열을 사용할 때 잠재적 인 문제를 이해하는 데 도움이되기를 바랍니다.


11
또는 decode()솔루션 대신 솔루션을 사용 하는 것이 좋습니다 . 유니 코드 개체를 더 자주 사용할수록 코드가 더 명확 해집니다. 원하는 것은 외부 묵시적 인코딩을 사용하는 바이트 배열이 아닌 문자열을 조작하는 것입니다. str()encode()
Eric O Lebigot

8
용어를 수정하십시오. when you mix utf-8 encoded strings with unicode onesUTF-8과 유니 코드는 두 가지 다른 인코딩이 아닙니다. 유니 코드는 표준이고 UTF-8은 그것이 정의하는 인코딩 중 하나입니다.
Kos

11
@Kos : 그는 "utf-8로 인코딩 된 문자열" 객체 를 유니 코드 (따라서 디코딩 된) 객체 와 혼합하는 것을 의미한다고 생각 합니다 . 전자는 유형 str이고 후자는 유형 unicode입니다. 당신은 / CONCATENATE / 보간들을 요약하려고하면 다른 개체이기 때문에, 문제가 발생할 수 있습니다
MestreLion

이것이 python>=2.6또는에 적용됩니까 python==2.6?
joar

16

또한 2.6 (python 2.6.5 RC1 + 이전)에서는 유니 코드 리터럴이 키워드 인수 ( issue4978 ) 와 잘 어울리지 않습니다 .

예를 들어 다음 코드는 unicode_literals없이 작동하지만 TypeError : keywords must be stringunicode_literals가 사용되면 실패합니다 .

  >>> def foo(a=None): pass
  ...
  >>> foo(**{'a':1})
  Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
      TypeError: foo() keywords must be strings

17
참고로 python 2.6.5 RC1 +가이 문제를 해결했습니다.
Mahmoud Abdelkader

13

난 당신이 추가하면 찾을 않았다 unicode_literals지시를 당신은 또한 같은 것을 추가해야합니다 :

 # -*- coding: utf-8

.py 파일의 첫 번째 또는 두 번째 줄에. 그렇지 않으면 다음과 같은 줄이 있습니다.

 foo = "barré"

다음과 같은 오류가 발생합니다.

구문 오류 : 198 행의 mumble.py 파일에있는 비 ASCII 문자 '\ xc3',
 그러나 인코딩이 선언되지 않았습니다. http://www.python.org/peps/pep-0263.html 참조
 자세한 내용은

5
@IanMackinnon : 파이썬 3 파일이 기본적으로 UTF8 있다고 가정
endolith

3
@endolith :하지만 Python 2는 그렇지 않습니다. 주석에서도 ASCII가 아닌 문자를 사용하면 구문 오류가 발생합니다 ! 그래서 이럴 # -*- coding: utf-8당신이 사용하는 경우에 관계없이 사실상 의무적으로 문을 것입니다 unicode_literals여부
MestreLion

-*-필요하지 않습니다; emacs와 호환되는 방식을 원한다면 필요하다고 생각합니다 -*- encoding: utf-8 -*-( -*-마지막의 참조 ). 필요한 것은 coding: utf-8(또는 =대신 : )입니다.
Chris Morgan

2
이 오류가 발생합니다 from __future__ import unicode_literals.
Flimm 2013-04-12

3
Emacs 호환성 에는 # -*- coding: utf-8 -*- "코딩"이 필요합니다 ( "인코딩"또는 "파일 인코딩"또는 다른 어떤 것도 아닙니다-파이썬은 접두어에 관계없이 "코딩"만 찾습니다).
Alex Dupuy 2014

7

또한 unicode_literal영향을 미치지는 eval()않지만 repr()(imho가 버그 인 비대칭 동작), 즉 (파이썬 3 에서처럼) eval(repr(b'\xa4'))같지 b'\xa4'않을 것임을 고려하십시오.

이상적으로 다음 코드는 모든 조합 unicode_literals및 Python {2.7, 3.x} 사용에 대해 항상 작동해야하는 고정 코드입니다 .

from __future__ import unicode_literals

bstr = b'\xa4'
assert eval(repr(bstr)) == bstr # fails in Python 2.7, holds in 3.1+

ustr = '\xa4'
assert eval(repr(ustr)) == ustr # holds in Python 2.7 and 3.1+

두 번째 주장 은 Python 2.7에서 repr('\xa4')평가 되기 때문에 작동 u'\xa4'합니다.


2
여기서 더 큰 문제 repr는 개체를 재생성하는 데 사용한다는 것 입니다. repr문서는 명확임을 명시 하지 요구 사항. 제 생각에는 이것은 repr디버깅에만 유용한 것으로 간주됩니다.
jpmc26 2014 년

5

더있다.

유니 코드를 허용하지 않는 문자열을 기대하는 라이브러리와 내장 기능이 있습니다.

두 가지 예 :

내장 :

myenum = type('Enum', (), enum)

(약간 esotic) unicode_literals에서 작동하지 않습니다 : type ()은 문자열을 기대합니다.

도서관:

from wx.lib.pubsub import pub
pub.sendMessage("LOG MESSAGE", msg="no go for unicode literals")

작동하지 않습니다 : wx pubsub 라이브러리는 문자열 메시지 유형을 예상합니다.

전자는 난해하고 쉽게 고정됩니다.

myenum = type(b'Enum', (), enum)

그러나 코드가 pub.sendMessage ()에 대한 호출로 가득 차 있다면 후자는 파괴적입니다.

젠장, 어?!?


3
그리고 형 물건도 메타 클래스에 누수 - 그래서 장고에 당신이 선언 모든 문자열이 class Meta:있어야한다b'field_name'
해미 다우 너에게

2
예 ... 제 경우에는 모든 sendMessage 문자열을 검색하고 b '버전으로 바꾸는 것이 가치가 있다는 것을 깨달았습니다. 무시 무시한 "디코드"예외를 피하려면 프로그램에서 엄격하게 유니 코드를 사용하고 필요에 따라 입력 및 출력을 변환하는 것과 같은 것은 없습니다 (이 주제에 대해 읽은 일부 논문에서 언급 한 "유니 코드 샌드위치"). 전반적으로, unicode_literals은 ... 저를위한 큰 승리했다
GreenAsJade

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.