py 스크립트에서 sys.setdefaultencoding (“utf-8”)을 사용해서는 안되는 이유는 무엇입니까?


166

스크립트 상단에 이것을 사용하는 파이 스크립트는 거의 없습니다. 어떤 경우에 사용해야합니까?

import sys
reload(sys)
sys.setdefaultencoding("utf-8")

2
ipython에서 이것을 사용하는 데 문제가 있습니다. % time은 github.com/ipython/ipython/issues/8071
seanv507

3
@ seanv507, 답변을 읽고-그것을 사용하는 것이 심각하지 않습니다
Alastair McCormack


2
이것은 sys.setdefaultencoding ( 'utf-8')위험과 정확히 어떻게 중복되지 않습니까? 이것 (2010)이 그 중 하나 (2015)보다 우선하지만? 그러나 그 질문에는 좋은 대답도 있습니다. 무엇을해야합니까? 또한 분명히이 질문은 3이 아닌 Python 2에서만 의미가 있지만 태그가 없거나 언급되지 않았습니다.
smci

SO의 답변에 다이빙을하기 전에 가치 읽기 : pythonhosted.org/kitchen/unicode-frustrations.html
ccpizza

답변:


141

설명서에 따르면 : 기본 ASCII에서 UTF-8과 같은 다른 인코딩으로 전환 할 수 있습니다. UTF-8은 문자열 버퍼를 유니 코드로 디코딩해야 할 때마다 Python 런타임에서 사용합니다.

이 함수는 Python이 환경을 스캔 할 때 Python 시작시에만 사용할 수 있습니다. 시스템 전체 모듈에서 호출해야합니다. sitecustomize.py이 모듈을 평가 한 후에는 setdefaultencoding()함수가 sys모듈 에서 제거됩니다 .

실제로 그것을 사용하는 유일한 방법은 속성을 다시 가져 오는 재로드 해킹입니다.

또한, 사용 sys.setdefaultencoding()은 항상 권장 되지 않았으며 py3k에서 no-op가되었습니다. py3k의 인코딩은 "utf-8"에 고정되어 있으며이를 변경하면 오류가 발생합니다.

나는 읽는 것에 대한 몇 가지 조언을 제안한다.


6
여기에 너무 많은 정보로 인해 약간의 죽음이 있지만 훌륭한 물건입니다. 나는이 기사에 초점을 가장 많이 배웠습니다 : blog.notdot.net/2010/07/Getting-unicode-right-in-Python
mbb

3
나는 기본 인코딩이 또한 사용되는 추가하고 싶습니다 인코딩 (에 기록 할 때 sys.stdout그것이있을 때 None파이썬 프로그램의 출력을 리디렉션 할 때와 같은 인코딩을).
Eric O Lebigot

14
+1 "사용을 sys.setdefaultencoding()권장하지 않았습니다"
jfs

7
'utf-8에 하드 와이어'는 사실이 아니며, 하드 와이어가 아니며 항상 그런 것은 아닙니다 UTF-8. LC_ALL=en_US.UTF-8 python3 -c 'import sys; print(sys.stdout.encoding)'제공 UTF-8하지만 LC_ALL=C python3 -c 'import sys; print(sys.stdout.encoding)'제공 ANSI_X3.4-1968(또는 아마도 다른 것)
Tino

7
@Tino, 콘솔 인코딩은 기본 인코딩과 별개입니다.
Alastair McCormack

59

tl; dr

대답은 결코 아니다 ! (내가하는 일을 정말로 모른다면)

인코딩 / 디코딩에 대한 적절한 이해를 통해 솔루션의 9/10 배를 해결할 수 있습니다.

1/10 명의 사용자가 로케일 또는 환경을 잘못 정의했으며 다음을 설정해야합니다.

PYTHONIOENCODING="UTF-8"  

환경에서 콘솔 인쇄 문제를 해결합니다.

무엇을합니까?

sys.setdefaultencoding("utf-8")(재사용을 피하기 위해 충돌) Python 2.x가 Unicode ()를 str ()로 변환해야하고 인코딩이 제공되지 않을 때마다 사용되는 기본 인코딩 / 디코딩을 변경합니다. 즉 :

str(u"\u20AC")
unicode("€")
"{}".format(u"\u20AC") 

Python 2.x에서 기본 인코딩은 ASCII로 설정되어 있으며 위 예제는 실패합니다.

UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 0: ordinal not in range(128)

(내 콘솔은 UTF-8로 구성되어 "€" = '\xe2\x82\xac'있으므로 예외입니다 \xe2)

또는

UnicodeEncodeError: 'ascii' codec can't encode character u'\u20ac' in position 0: ordinal not in range(128)

sys.setdefaultencoding("utf-8")이것들은 나를 위해 작동 하지만 UTF-8을 사용하지 않는 사람들에게는 반드시 작동하지는 않습니다. ASCII의 기본값은 인코딩 가정이 코드로 구워지지 않도록합니다.

콘솔

sys.setdefaultencoding("utf-8")또한 sys.stdout.encoding콘솔에 문자를 인쇄 할 때 사용되는 것으로 나타나는 부작용이 있습니다. Python은 사용자 로캘 (Linux / OS X / Un * x) 또는 코드 페이지 (Windows)를 사용하여이를 설정합니다. 때때로 사용자의 로캘이 손상 PYTHONIOENCODING되어 콘솔 인코딩 만 수정하면 됩니다 .

예:

$ export LANG=en_GB.gibberish
$ python
>>> import sys
>>> sys.stdout.encoding
'ANSI_X3.4-1968'
>>> print u"\u20AC"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\u20ac' in position 0: ordinal not in range(128)
>>> exit()

$ PYTHONIOENCODING=UTF-8 python
>>> import sys
>>> sys.stdout.encoding
'UTF-8'
>>> print u"\u20AC"
€

sys.setdefaultencoding ( "utf-8") 의 문제점은 무엇입니까 ?

사람들은 기본 인코딩이 ASCII라는 것을 이해하면서 16 년 동안 Python 2.x에 대해 개발해 왔습니다. UnicodeError비 ASCII를 포함하는 것으로 확인 된 문자열에서 문자열을 유니 코드로 변환하는 것을 처리하기 위해 예외 처리 방법이 작성되었습니다.

에서 https://anonbadger.wordpress.com/2015/06/16/why-sys-setdefaultencoding-will-break-code/

def welcome_message(byte_string):
    try:
        return u"%s runs your business" % byte_string
    except UnicodeError:
        return u"%s runs your business" % unicode(byte_string,
            encoding=detect_encoding(byte_string))

print(welcome_message(u"Angstrom (Å®)".encode("latin-1"))

defaultencoding을 설정하기 전에이 코드는 ASCII 인코딩에서 "Å"을 디코딩 할 수 없었으며 예외 처리기를 입력하여 인코딩을 추측하고 올바르게 유니 코드로 바꿨습니다. 인쇄 : Angstrom (Å®)은 비즈니스를 운영합니다. defaultencoding을 utf-8로 설정하면 코드는 byte_string이 utf-8로 해석 될 수 있음을 발견하여 데이터를 엉망으로 만들고이를 대신 반환합니다. Angstrom (Ů)은 비즈니스를 운영합니다.

일정한 것을 변경하면 의존하는 모듈에 큰 영향을 미칩니다. 코드에서 들어오고 나가는 데이터를 수정하는 것이 좋습니다.

문제 예

다음 예제에서 기본 인코딩을 UTF-8로 설정하는 것이 근본 원인은 아니지만 문제가 어떻게 마스크되는지, 입력 인코딩이 변경 될 때 코드가 명백하지 않은 방식으로 중단되는 방법을 보여줍니다. UnicodeDecodeError : 'utf8'codec can 3131 위치에서 바이트 0x80을 디코딩하지 않습니다 : 유효하지 않은 시작 바이트


2
에 놀라움이 있지만 sys.setdefaultencoding("utf-8")코드가 Python 3처럼 작동하도록하는 것이 좋습니다. 지금은 2017입니다. 2015 년에 답을 썼을 때도, 나는 거꾸로가 아니라 앞으로 기대하는 것이 더 낫다고 생각합니다. 출력이 리디렉션되는지 여부에 따라 Python 2에서 코드가 다르게 동작한다는 것을 알았을 때 실제로 가장 간단한 솔루션이었습니다 (Python 2의 경우 매우 힘든 문제). 말할 필요도없이, 나는 이미 가지고 # coding: utf-8있으며 Python 3에 대한 해결 방법이 필요하지 않습니다 (실제로 setdefaultencoding사용중인 버전 확인 을 마스크 해야합니다).
Yongwei Wu

훌륭하고 작동하지만 sys.setdefaultencoding("utf-8")Py 2.x 코드를 Python 3과 호환하지는 않습니다. 기본 인코딩이 ASCII라고 가정하는 외부 모듈도 수정하지 않습니다. Python 3 호환 코드를 작성하는 것은 매우 간단하며이 해킹이 필요하지 않습니다. 예를 들어 이것이 실제 문제를 일으키는 이유는 다음과 같습니다. stackoverflow.com/questions/39465220/…
Alastair McCormack

1
@AlastairMcCormack you rock, 내 사이트는 몇 달이 지났으며 어떻게해야할지 알 수 없었습니다. 마지막으로 PYTHONIOENCODING="UTF-8"Python2.7 Django-1.11 환경을 도왔습니다. 감사.
sam

예제를 복사 한 것으로 알고 있지만 패키지의 내용을 찾을 수 있습니다 detect_encoding.
dlamblin

@dlamblin 코드 예제는 인용을 증명하기위한 것이며 코드에서 사용해서는 안됩니다. detect_encoding언어 단서를 기반으로 문자열 인코딩을 감지 할 수있는 방법이라고 상상해보십시오 .
Alastair McCormack

18
#!/usr/bin/env python
#-*- coding: utf-8 -*-
u = u'moçambique'
print u.encode("utf-8")
print u

chmod +x test.py
./test.py
moçambique
moçambique

./test.py > output.txt
Traceback (most recent call last):
  File "./test.py", line 5, in <module>
    print u
UnicodeEncodeError: 'ascii' codec can't encode character 
u'\xe7' in position 2: ordinal not in range(128)

쉘에서 작동하지만 sdtout으로 보내지 않으므로 stdout에 쓰는 것이 하나의 해결 방법입니다.

sys.stdout.encoding이 정의되지 않은 경우 또는 달리 말하면 stdout에 쓰려면 먼저 PYTHONIOENCODING = UTF-8 내보내기가 필요한 다른 방법을 사용했습니다.

import sys
if (sys.stdout.encoding is None):            
    print >> sys.stderr, "please set python env PYTHONIOENCODING=UTF-8, example: export PYTHONIOENCODING=UTF-8, when write to stdout." 
    exit(1)


따라서 동일한 예제를 사용하십시오.

export PYTHONIOENCODING=UTF-8
./test.py > output.txt

작동합니다


3
요청한대로 질문에 답변하지 않습니다. 오히려 그 주제에 대한 약간의 탄탄한 생각.
ivan_pozdeev

3
  • 첫 번째 위험은에 reload(sys)있습니다.

    모듈을 다시로드하면 실제로 런타임에 두 개의 모듈 사본이 제공됩니다. 이전 모듈은 다른 모든 것과 마찬가지로 Python 객체이며 참조가있는 한 살아 있습니다. 따라서 객체의 절반은 이전 모듈을 가리키고 절반은 새 모듈을 가리 킵니다. 변경하면 임의의 객체가 변경 사항을 볼 수 없을 때 변경 사항이 표시되지 않습니다.

    (This is IPython shell)
    
    In [1]: import sys
    
    In [2]: sys.stdout
    Out[2]: <colorama.ansitowin32.StreamWrapper at 0x3a2aac8>
    
    In [3]: reload(sys)
    <module 'sys' (built-in)>
    
    In [4]: sys.stdout
    Out[4]: <open file '<stdout>', mode 'w' at 0x00000000022E20C0>
    
    In [11]: import IPython.terminal
    
    In [14]: IPython.terminal.interactiveshell.sys.stdout
    Out[14]: <colorama.ansitowin32.StreamWrapper at 0x3a9aac8>
  • 지금, sys.setdefaultencoding() 적절한

    영향을 미치는 것은 암시 적 변환str<->unicode 입니다. 자, utf-8지구상에서 가장 안전한 인코딩 (ASCII 및 모든 버전과 역 호환 가능), 변환이 "작동합니다", 무엇이 잘못 될 수 있습니까?

    뭐든지 요 그리고 그것은 위험입니다.

    • UnicodeError비 ASCII 입력에 대해 발생하거나 오류 처리기를 사용하여 코드 변환을 수행하는 일부 코드가있을 수 있으며 이로 인해 예기치 않은 결과가 발생합니다. 과 모든 코드는 기본 설정으로 테스트되었으므로 여기서 "지원되지 않는"영역을 엄격하게 따르고 아무도 코드의 작동 방식을 보증하지 않습니다.
    • Python 2에는 실제로 여러 개의 독립적 인 "기본 문자열 인코딩"이 있기 때문에 시스템의 모든 것이 UTF-8을 사용하지 않는 경우 트랜스 코딩에서 예기치 않거나 사용할 수없는 결과가 발생할 수 있습니다. . (프로그램은 고객의 장비에서 고객을 위해 작동해야 함을 기억하십시오.)
      • 다시, 최악의 상황은 당신이 알고하지 않습니다 변환이 암시하기 때문에 언제 어디에서 그런 일이 정말 모르겠어요 -. (Python Zen, koan 2 ahoy!) 코드가 한 시스템에서 작동하고 다른 시스템에서 작동하는 이유를 알 수 없습니다. (또는 아직은 IDE에서 작동하고 콘솔에서 작동하지 않습니다.)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.