Python 2.6。の下で実行するコードベースを既に取得しています。Python 3.0を準備するために、追加を開始しました:
from __future__ from unicode_literals
.py
ファイル(変更する場合)。他の誰かがこれをやっていて、明白でない落とし穴にぶつかったのではないかと思っています(おそらくデバッグに多くの時間を費やした後)。
Unicode文字列で作業していた問題の主な原因は、utf-8でエンコードされた文字列とUnicode文字列を混在させることです。
たとえば、次のスクリプトを検討してください。
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.name
_はunicode_literals
_をインポートしなかったため、_one.name
_はUnicode文字列ではなくutf-8エンコード文字列です。両方を混在させると、pythonはエンコードされた文字列を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'
_はUnicode文字列であるため失敗します。したがって、pythonはhtml
をデコードしようとします。印刷を修正するいくつかの方法は、print str('DEBUG: %s') % html
またはprint 'DEBUG: %s' % html.decode('utf-8')
。
これが、ユニコード文字列を使用する際の潜在的な落とし穴を理解するのに役立つことを願っています。
2.6でも(python 2.6.5 RC1 +より前)ユニコードリテラルは、キーワード引数( issue4978 )でニースを再生しません:
たとえば、次のコードはunicode_literalsがなくても動作しますが、TypeErrorで失敗します:keywords must be string
unicode_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
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()
(私見がバグである非対称の振る舞い)には影響しない、つまりeval(repr(b'\xa4'))
はb'\xa4'
(Python 3)と同様)。
理想的には、次のコードは不変式であり、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+
repr('\xa4')
はu'\xa4'
in Python 2.7。
もっとあります。
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()(これは私のものです)の呼び出しでいっぱいの場合、後者は壊滅的です。
それをやった、え?!?
クリックすると、あらゆる場所でUnicode例外が発生します if from __future__ import unicode_literals
は使用する場所にインポートされますclick.echo
。それは悪夢です…