À propos de divers encodages de Python 3

C'est beaucoup plus facile que Python 2, mais dans certains environnements, vous pouvez rencontrer des erreurs UnicodeErrors inattendues dans Python 3. Voyons la gestion de divers encodages Python à partir de Python 3.6.

Encodage Python

filesystem encoding (sys.getfilesystemencoding())

Ce codage est principalement utilisé pour les chemins de fichiers, mais il est également utilisé pour les arguments de ligne de commande. (Sinon, vous aurez du mal à passer le chemin du fichier comme argument de ligne de commande)

De plus, comme les paramètres régionaux sont liés, ils sont en fait utilisés lorsque vous travaillez avec la glibc, etc. C'est peut-être un vestige de l'ère Python 2, mais maintenant je pense que l'appeler codage système plutôt que codage système de fichiers représente la réalité.

preferred encoding (locale.getpreferredencoding())

Cet encodage est principalement utilisé pour le contenu des fichiers texte. ʻUtilisé lors de l'ouverture d'un fichier texte avec la fonction open`.

Codage d'entrée / sortie standard (`` sys.stdout.encoding '')

Le codage d'entrée / sortie standard est le codage du système de fichiers pour les terminaux et le codage préféré pour les autres, mais il peut être modifié avec la variable d'environnement PYTHONIOENCODING.

default encoding (sys.getdefaultencoding())

Il s'agit du codage par défaut utilisé lorsque vous ne spécifiez pas explicitement un codage lors de la conversion entre une chaîne unicode ( str '') et une chaîne d'octets ( octets ''). En Python 3, il est complètement UTF-8 fixe quel que soit l'environnement.

>>> "Bonjour".encode()
b'\xe3\x81\x93\xe3\x82\x93\xe3\x81\xab\xe3\x81\xa1\xe3\x81\xaf'
>>> _.decode()
'Bonjour'

C'était ascii à l'ère Python 2, et il y avait une conversion de type implicite, donc cela avait tendance à être une source de problèmes. (Il y avait aussi un hack pour forcer utf-8 à exécuter une application qui ne pensait pas au multi-octet)

Python 3 ne fait pas de conversion de type implicite entre str et bytes, c'est donc juste un argument par défaut. Vous pouvez oublier l'existence elle-même.

Comportement dans divers environnements

macOS, android

Comme il est fixé à UTF-8 au niveau du système d'exploitation, le codage du système de fichiers sera toujours UTF-8.

L'encodage préféré est toujours UTF-8 fixé pour Android et peut être modifié avec les paramètres régionaux pour macOS, mais je pense que c'est rarement un problème. (Si la locale est définie, ce sera la même chose que Linux décrit plus tard)

Windows

Étant donné que Windows utilise des API basées sur W à la fois lors de l'ouverture de fichiers et lors de la réception d'arguments de ligne de commande, le codage du système de fichiers est rarement utilisé.

Le comportement lors du traitement des chemins de fichiers sous forme de chaînes d'octets était la page de code actuelle cp932 '' car jusqu'à Python 3.5, il s'agissait d'un appel Windows A API. À partir de Python 3.6, ce comportement a changé et la conversion UTF-8 => UTF-16 et les API basées sur W sont utilisées, le codage du système de fichiers est donc utf-8 ''. (Il existe également des variables d'environnement pour revenir au comportement de Python 3.5)

Le codage préféré, en revanche, utilise toujours des pages de codes. C'est un héritage jusqu'à ce que Microsoft fasse le codage de fichier texte standard UTF-8. Je suis désolé.

Linux, autre Unix

Le plus décevant est l'autre Unix. Cela dépend des paramètres régionaux (`` LC_CTYPE ''). Si quelqu'un dit encore LANG = ja_JP.eucJP, le codage du système de fichiers et le codage préféré seront EUC-JP. Si vous voulez créer un fichier texte en UTF-8, même si vous ne voulez pas du tout prendre en charge Windows, spécifiez le codage explicitement dans la fonction ʻopen` pour les environnements où la locale n'est pas UTF-8.

La dépendance locale est particulièrement décevante car le codage par défaut (C ou POSIX) (LC_CTYPE) pour les paramètres régionaux est par défaut ASCII.

Certaines personnes utilisent les paramètres régionaux C ou POSIX car ils n'aiment pas le comportement de diverses commandes telles que le tri selon les paramètres régionaux. Les images intégrées ou conteneurs peuvent ne pas avoir les paramètres régionaux en_US.utf8 ou ja_JP.utf8 pour réduire le poids. De plus, si vous ssh depuis mac (parce que la variable d'environnement LANG est envoyée), vous pouvez obtenir une erreur et revenir à C lorsque vous essayez d'utiliser ja_JP.UTF-8 sur Linux qui n'a que en_US.UTF-8. A cette époque, Python est complètement en mode ASCII.

$ export LC_ALL=C
$ echo 'print("Bonjour\n")' > hello
$ ruby hello
Bonjour
$ perl hello
Bonjour
$ python3 hello
Traceback (most recent call last):
  File "hello", line 1, in <module>
    print("\u3053\u3093\u306b\u3061\u306f\n")
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-4: ordinal not in range(128)

Si le codage du système de fichiers peut rester ASCII, vous pouvez spécifier le codage d'entrée / sortie standard avec PYTHONIOENCODING sans définir de paramètres régionaux. Écrivez-le dans .bashrc ou crontab.

$ PYTHONIOENCODING=utf-8 python3 hello
Bonjour

(Annexe) Paramètres régionaux Linux pour utiliser UTF-8 avec Python

La première chose à retenir est la commande locale, qui affiche la locale actuelle, et la commande locale -a, qui affiche une liste des locales disponibles.

$ locale
LANG=C.UTF-8
LANGUAGE=en_US:en
LC_CTYPE="C.UTF-8"
LC_NUMERIC="C.UTF-8"
LC_TIME="C.UTF-8"
LC_COLLATE="C.UTF-8"
LC_MONETARY="C.UTF-8"
LC_MESSAGES="C.UTF-8"
LC_PAPER="C.UTF-8"
LC_NAME="C.UTF-8"
LC_ADDRESS="C.UTF-8"
LC_TELEPHONE="C.UTF-8"
LC_MEASUREMENT="C.UTF-8"
LC_IDENTIFICATION="C.UTF-8"
LC_ALL=

$ locale -a
C
C.UTF-8
POSIX
en_US.utf8

Je pense que C.UTF-8 est inclus dans Linux moderne. Une version UTF-8 de la locale C qui ne fait rien de plus. Il est parfait pour les personnes qui souhaitent utiliser les paramètres régionaux C, mais qui souhaitent utiliser des noms de fichiers UTF-8. S'il n'existe pas, vous devriez pouvoir le créer avec sudo localedef -c -i POSIX -f UTF-8 C.UTF-8 si vous avez les privilèges root.

Si ja_JP.UTF-8 ou en_US.UTF-8 existe et que vous souhaitez l'utiliser, définissez-le dans la variable d'environnement LANG et vérifiez-le avec la commande locale.

$ export LANG=en_US.utf8
$ locale
LANG=en_US.utf8
LANGUAGE=en_US:en
LC_CTYPE="en_US.utf8"
LC_NUMERIC="en_US.utf8"
LC_TIME="en_US.utf8"
LC_COLLATE="en_US.utf8"
LC_MONETARY="en_US.utf8"
LC_MESSAGES="en_US.utf8"
LC_PAPER="en_US.utf8"
LC_NAME="en_US.utf8"
LC_ADDRESS="en_US.utf8"
LC_TELEPHONE="en_US.utf8"
LC_MEASUREMENT="en_US.utf8"
LC_IDENTIFICATION="en_US.utf8"
LC_ALL=

Je veux utiliser la locale C! Mais je veux utiliser UTF-8! Mais je ne peux pas faire C.UTF-8! Dans ce cas, contrôlons-le un peu plus précisément. De chaque LC_XXXXX, celui que Python utilise pour déterminer le codage est LC_CTYPE. La variable d'environnement LANG définit le LC_XXXX entier sauf LC_ALL et peut être remplacée individuellement pour chaque LC_XXXX, mais si LC_ALL est défini, elle écrasera tout davantage. Vous pouvez donc définir LC_CTYPE sur certains paramètres régionaux UTF-8 tout en définissant LANG = C.

$ export LANG=C
$ export LC_CTYPE=en_US.UTF-8
$ locale
LANG=C
LANGUAGE=en_US:en
LC_CTYPE=en_US.UTF-8
LC_NUMERIC="C"
LC_TIME="C"
LC_COLLATE="C"
LC_MONETARY="C"
LC_MESSAGES="C"
LC_PAPER="C"
LC_NAME="C"
LC_ADDRESS="C"
LC_TELEPHONE="C"
LC_MEASUREMENT="C"
LC_IDENTIFICATION="C"
LC_ALL=

$ locale charmap
UTF-8
$ python3 -c 'import sys; print(sys.getfilesystemencoding())'
utf-8

Recommended Posts

À propos de divers encodages de Python 3
Divers traitements de Python
À propos des fonctionnalités de Python
À propos de la liste de base des bases de Python
À propos des tranches Python
À propos de la notation d'inclusion de python
À propos de la création de l'interface graphique à l'aide de TKinter de Python
À propos de Python tqdm.
À propos du rendement Python
À propos de python, classe
Mémorandum des débutants en python
Résumé de diverses instructions for en Python
À propos de l'héritage Python
Les bases de Python ①
Bases de python ①
À propos de python, range ()
# 3 [python3] Divers opérateurs
Copie de python
À propos de Python Decorator
1. Statistiques apprises avec Python 1-3. Calcul de diverses statistiques (statistiques)
Diverses spécifications de format de la méthode str.format () de Python3
À propos de la référence Python
[Python] Diverses combinaisons de chaînes de caractères et de valeurs
À propos des décorateurs Python
Note de problèmes sur la coexistence du système Python 2/3
[Python] Chapitre 02-04 Bases du programme Python (À propos des commentaires)
[Python] À propos du multi-processus
Introduction de Python
[python] Créer une liste de différents types de caractères
1. Statistiques apprises avec Python 1-2. Calcul de diverses statistiques (Numpy)
Écrire une note sur la version python de python virtualenv
Divers paramètres de l'outil de génération de blog statique Python 'Pélican'
[Note] À propos du rôle du trait de soulignement "_" en Python
À propos des copies superficielles et profondes de Python / Ruby
À propos de Python for loop
[Python] Opération d'énumération
À propos des arguments de fonction (python)
À propos de tout numpy
Unification de l'environnement Python
Copie des préférences python
Principes de base du grattage Python
À propos de l'attribution de numpy.ndarray
[python] comportement d'argmax
[Python] Mémo sur les fonctions
À propos de MultiIndex of Pandas
Résumé sur Python3 + OpenCV3
Divers outils de visualisation Python
Utilisation des locaux Python ()
le zen de Python
À propos de Python, pour ~ (plage)
Installation de Python 3.3 rc1
[Python] Mémo sur les erreurs
À propos de l'environnement de développement Python
Python: à propos des arguments de fonction
Python, à propos de la gestion des exceptions