Python linux utf 8

Changing default encoding of Python?

I have many «can’t encode» and «can’t decode» problems with Python when I run my applications from the console. But in the Eclipse PyDev IDE, the default character encoding is set to UTF-8, and I’m fine. I searched around for setting the default encoding, and people say that Python deletes the sys.setdefaultencoding function on startup, and we can not use it. So what’s the best solution for it?

The best solution is to learn to use encode and decode correctly instead of using hacks. This was certainly possible with python2 at the cost of always remembering to do so / consistently using your own interface. My experience suggests that this becomes highly problematic when you are writing code that you want to work with both python2 and python3.

14 Answers 14

Here is a simpler method (hack) that gives you back the setdefaultencoding() function that was deleted from sys :

import sys # sys.setdefaultencoding() does not exist, here! reload(sys) # Reload does the trick! sys.setdefaultencoding('UTF8') 

(Note for Python 3.4+: reload() is in the importlib library.)

This is not a safe thing to do, though: this is obviously a hack, since sys.setdefaultencoding() is purposely removed from sys when Python starts. Reenabling it and changing the default encoding can break code that relies on ASCII being the default (this code can be third-party, which would generally make fixing it impossible or dangerous).

PS: This hack doesn’t seem to work with Python 3.9 anymore.

I downvoted, because that answer doesn’t help for running existing applications (which is one way to interpret the question), is wrong when you are writing/maintaining an application and dangerous when writing a library. The right way is to set LC_CTYPE (or in an application, check whether it is set right and abort with a meaningful error message).

well, it did not mention, it’s a hack at first. other than that, dangerous answers that lack any mention that they are, are not helpful.

@EOL you are right. It does effect the preferredencoding though (in python 2 and 3): LC_CTYPE=C python -c ‘import locale; print( locale.getpreferredencoding())’

@user2394901 The use of sys.setdefaultencoding() has always been discouraged!! And the encoding of py3k is hard-wired to «utf-8» and changing it raises an error.

If you get this error when you try to pipe/redirect output of your script

UnicodeEncodeError: ‘ascii’ codec can’t encode characters in position 0-5: ordinal not in range(128)

Just export PYTHONIOENCODING in console and then run your code.

export PYTHONIOENCODING=utf8 

This is the only solution that made any difference for me. — I’m on Debian 7, with broken locale settings. Thanks.

Читайте также:  Time zone setting in linux

A bigger bug in Python3 is, that PYTHONIOENCODING=utf8 is not the default. This makes scripts break just because LC_ALL=C

Set LC_CTYPE to something sensible instead This is a reasonable suggestion. This doesn’t work so well when you are trying to distribute code that just works on another person’s system.

Debian and Redhat OSes use a C.utf8 locale to provide more sensible C. glibc upstream is working on adding it, so perhaps we should not be blaming Python for respecting locale settings\…?

A) To control sys.getdefaultencoding() output:

python -c 'import sys; print(sys.getdefaultencoding())' 
echo "import sys; sys.setdefaultencoding('utf-16-be')" > sitecustomize.py 
PYTHONPATH=".:$PYTHONPATH" python -c 'import sys; print(sys.getdefaultencoding())' 

You could put your sitecustomize.py higher in your PYTHONPATH .

Also you might like to try reload(sys).setdefaultencoding by @EOL

B) To control stdin.encoding and stdout.encoding you want to set PYTHONIOENCODING :

python -c 'import sys; print(sys.stdin.encoding, sys.stdout.encoding)' 
PYTHONIOENCODING="utf-16-be" python -c 'import sys; print(sys.stdin.encoding, sys.stdout.encoding)' 

Finally: you can use A) or B) or both!

(python2 only) separate but interesting is extending above with from __future__ import unicode_literals see discussion

Starting with PyDev 3.4.1, the default encoding is not being changed anymore. See this ticket for details.

For earlier versions a solution is to make sure PyDev does not run with UTF-8 as the default encoding. Under Eclipse, run dialog settings («run configurations», if I remember correctly); you can choose the default encoding on the common tab. Change it to US-ASCII if you want to have these errors ‘early’ (in other words: in your PyDev environment). Also see an original blog post for this workaround.

Thanks Chris. Especially considering Mark T’s comment above, your answer seems to be the most appropriate to me. And for somebody who’s not primarily an Eclipse/PyDev user, I never would have figured that out on my own.

I’d like to change this globally (rather than once per run configuration), but haven’t figured out how — have asked a separate q: stackoverflow.com/questions/9394277/…

Regarding python2 (and python2 only), some of the former answers rely on using the following hack:

import sys reload(sys) # Reload is a hack sys.setdefaultencoding('UTF8') 

It is discouraged to use it (check this or this)

In my case, it come with a side-effect: I’m using ipython notebooks, and once I run the code the ´print´ function no longer works. I guess there would be solution to it, but still I think using the hack should not be the correct option.

After trying many options, the one that worked for me was using the same code in the sitecustomize.py , where that piece of code is meant to be. After evaluating that module, the setdefaultencoding function is removed from sys.

So the solution is to append to file /usr/lib/python2.7/sitecustomize.py the code:

import sys sys.setdefaultencoding('UTF8') 

When I use virtualenvwrapper the file I edit is ~/.virtualenvs/venv-name/lib/python2.7/sitecustomize.py .

And when I use with python notebooks and conda, it is ~/anaconda2/lib/python2.7/sitecustomize.py

There is an insightful blog post about it.

Читайте также:  Kali linux ssh raspberry pi

I paraphrase its content below.

In python 2 which was not as strongly typed regarding the encoding of strings you could perform operations on differently encoded strings, and succeed. E.g. the following would return True .

That would hold for every (normal, unprefixed) string that was encoded in sys.getdefaultencoding() , which defaulted to ascii , but not others.

The default encoding was meant to be changed system-wide in site.py , but not somewhere else. The hacks (also presented here) to set it in user modules were just that: hacks, not the solution.

Python 3 did changed the system encoding to default to utf-8 (when LC_CTYPE is unicode-aware), but the fundamental problem was solved with the requirement to explicitly encode «byte»strings whenever they are used with unicode strings.

First: reload(sys) and setting some random default encoding just regarding the need of an output terminal stream is bad practice. reload often changes things in sys which have been put in place depending on the environment — e.g. sys.stdin/stdout streams, sys.excepthook, etc.

Solving the encode problem on stdout

The best solution I know for solving the encode problem of print ‘ing unicode strings and beyond-ascii str ‘s (e.g. from literals) on sys.stdout is: to take care of a sys.stdout (file-like object) which is capable and optionally tolerant regarding the needs:

  • When sys.stdout.encoding is None for some reason, or non-existing, or erroneously false or «less» than what the stdout terminal or stream really is capable of, then try to provide a correct .encoding attribute. At last by replacing sys.stdout & sys.stderr by a translating file-like object.
  • When the terminal / stream still cannot encode all occurring unicode chars, and when you don’t want to break print ‘s just because of that, you can introduce an encode-with-replace behavior in the translating file-like object.
#!/usr/bin/env python # encoding: utf-8 import sys class SmartStdout: def __init__(self, encoding=None, org_stdout=None): if org_stdout is None: org_stdout = getattr(sys.stdout, 'org_stdout', sys.stdout) self.org_stdout = org_stdout self.encoding = encoding or \ getattr(org_stdout, 'encoding', None) or 'utf-8' def write(self, s): self.org_stdout.write(s.encode(self.encoding, 'backslashreplace')) def __getattr__(self, name): return getattr(self.org_stdout, name) if __name__ == '__main__': if sys.stdout.isatty(): sys.stdout = sys.stderr = SmartStdout() us = u'aouäöüфżß²' print us sys.stdout.flush() 

Using beyond-ascii plain string literals in Python 2 / 2 + 3 code

The only good reason to change the global default encoding (to UTF-8 only) I think is regarding an application source code decision — and not because of I/O stream encodings issues: For writing beyond-ascii string literals into code without being forced to always use u’string’ style unicode escaping. This can be done rather consistently (despite what anonbadger‘s article says) by taking care of a Python 2 or Python 2 + 3 source code basis which uses ascii or UTF-8 plain string literals consistently — as far as those strings potentially undergo silent unicode conversion and move between modules or potentially go to stdout. For that, prefer » # encoding: utf-8 » or ascii (no declaration). Change or drop libraries which still rely in a very dumb way fatally on ascii default encoding errors beyond chr #127 (which is rare today).

Читайте также:  Linux secure delete file

And do like this at application start (and/or via sitecustomize.py) in addition to the SmartStdout scheme above — without using reload(sys) :

. def set_defaultencoding_globally(encoding='utf-8'): assert sys.getdefaultencoding() in ('ascii', 'mbcs', encoding) import imp _sys_org = imp.load_dynamic('_sys_org', 'sys') _sys_org.setdefaultencoding(encoding) if __name__ == '__main__': sys.stdout = sys.stderr = SmartStdout() set_defaultencoding_globally('utf-8') s = 'aouäöüфżß²' print s 

This way string literals and most operations (except character iteration) work comfortable without thinking about unicode conversion as if there would be Python3 only. File I/O of course always need special care regarding encodings — as it is in Python3.

Note: plains strings then are implicitely converted from utf-8 to unicode in SmartStdout before being converted to the output stream enconding.

Источник

Python 3 и русские символы: print(‘Всем привет!’) ведёт к UnicodeEncodeError: ‘ascii’ codec can’t encode. ошибке

Traceback (most recent call last):
File «main.py», line 1, in print(‘\u0412\u0441\u0435\u043c \u043f\u0440\u0438\u0432\u0435\u0442!’) UnicodeEncodeError: ‘ascii’ codec can’t encode characters in position 0-3: ordinal not in range(128)

webapp: ~/Applications $ uname -a Linux webapp 3.13.0-29-generic 53-Ubuntu SMP Wed Jun 4 21:00:20 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux

2 ответа 2

Питон использует кодировку терминала для печати, которая не имеет никакого отношения к sys.getdefaultencoding() .

Иногда переменные окружения, определяющие язык, такие как LANGUAGE , LC_ALL , LC_CTYPE , LANG могут быть не установлены, например, в окружении используемом ssh, upstart, Salt, mod_wsgi, crontab, etc. В этом случае используется C (POSIX) локаль, которая использует ascii кодировку, что приводит к UnicodeEncodeError ошибке, т.к. русские буквы не представимы в ascii. В Python 3.7, реализована PEP 540: Forced UTF-8 Runtime Mode: utf-8 режим включается по умолчанию для «C» локали.

Серверные варианты Linux могут использовать C локаль по умолчанию. Настольные инсталяции дитрибутивов Linux обычно имеют utf-8 локаль.

Ошибка в вопросе связана с Питон багом: Python 3 raises Unicode errors with the C locale. Разработчики решили следовать ascii кодировке из C локали, даже если это ошибка в подавляющем большинстве случаев, но в Python 3.7 ситуация может улучшится в поведении по умолчанию, см. PEP 538 — Coercing the legacy C locale to a UTF-8 based locale.

Чтобы временно изменить используемую кодировку можно определить PYTHONIOENCODING :

$ PYTHONIOENCODING=utf-8 python your-script.py 

В качестве более постоянного решения, нужно убедиться что используется utf-8 локаль в окружении, которое запускает python. Не обязательно русскую локаль устанавливать, чтобы напечатать русский текст. В этом достоинство Юникода, что можно работать с многими языками одновременно. Например, существует C.UTF-8 локаль.

Если locale -a не показывает ни одной utf-8 локали, то на Debian системах следует установить locales пакет и выбрать utf-8 локаль для использования:

root# aptitude install locales root# dpkg-reconfigure locales 

Индивидульно, каждый пользователь может настроить переменные окружения (см. Не сохраняются переменные XUBUNTU ), например:

Используется первая доступная переменная из списка: LC_ALL , LC_CTYPE , LANG .

Может потребоваться сконфигурировать для работы с utf-8 индивидуальные программы, такие как xterm, Gnome Terminal, screen, отдельно.

Источник

Оцените статью
Adblock
detector