Python 2.6 で動作するコード ベースを既に取得しています。Python 3.0 に備えるために、以下の追加を開始しました。
from __future__ import unicode_literals
私たちの.py
ファイルに(私たちがそれらを変更するにつれて)。他の誰かがこれを行っていて、明らかでない落とし穴に遭遇したかどうか疑問に思っています (おそらくデバッグに多くの時間を費やした後)。
Python 2.6 で動作するコード ベースを既に取得しています。Python 3.0 に備えるために、以下の追加を開始しました。
from __future__ import unicode_literals
私たちの.py
ファイルに(私たちがそれらを変更するにつれて)。他の誰かがこれを行っていて、明らかでない落とし穴に遭遇したかどうか疑問に思っています (おそらくデバッグに多くの時間を費やした後)。
私がユニコード文字列を扱う際に発生した問題の主な原因は、utf-8 でエンコードされた文字列とユニコード文字列を混在させた場合です。
たとえば、次のスクリプトを考えてみましょう。
2.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.name
は、 は をインポートしていないため、utf-8 でエンコードされた文字列 (Unicode ではない)unicode_literals
であり、one.name
は Unicode 文字列です。両方を混在させると、python はエンコードされた文字列 (ASCII であると仮定) をデコードし、それを Unicode に変換しようとして失敗します。そうすればうまくいくでしょう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'
はユニコード文字列であるため失敗し、したがって python は をデコードしようとしhtml
ます。印刷を修正する方法はいくつかありprint str('DEBUG: %s') % html
ますprint 'DEBUG: %s' % html.decode('utf-8')
。
これが、Unicode 文字列を使用する際の潜在的な落とし穴を理解するのに役立つことを願っています。
また、2.6 (python 2.6.5 RC1+ より前) では、Unicode リテラルはキーワード引数で適切に機能しません ( issue4978 ):
たとえば、次のコードは unicode_literals なしで機能しますが、keywords must be string
Unicode_literals が使用されている場合は TypeError: で失敗します。
>>> 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
unicode_literals
ディレクティブを追加する場合は、次のようなものも追加する必要があることがわかりました。
# -*- coding: utf-8
.pyファイルの1行目または2行目に。それ以外の場合、次のような行:
foo = "barré"
次のようなエラーが発生します。
SyntaxError:198行目のファイルmumble.pyの非ASCII文字'\ xc3'、 ただし、エンコーディングは宣言されていません。http://www.python.org/peps/pep-0263.htmlを参照してください 詳細については
unicode_literal
また、影響はあるが影響は受けeval()
ないrepr()
(imhoがバグである非対称の動作)、つまり(Python 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')
評価されるため、2番目のアサーションはたまたま機能します。u'\xa4'
もっとあります。
Unicode を許容しない文字列を想定するライブラリとビルトインがあります。
2 つの例:
組み込み:
myenum = type('Enum', (), enum)
(少し難解ですが) 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() への呼び出しでいっぱいである場合、後者は壊滅的です(これは私のものです)。
ぶっちゃけ、えっ?!?