2009-05-01 14 views
95

すでにコードベースはPython 2.6で動作しています。私たちの.pyファイルにPython 2.6でunicode_literalsを使用している問題はありますか?

 
from __future__ import unicode_literals 

(我々はそれらを修正するよう):Pythonの3.0のために準備するために、我々は追加を開始しました。私は他の誰かがこれをやっていて、(おそらく多くの時間を費やしてデバッグした後に)不明瞭な問題を起こしているのだろうかと思います。第一または第二のラインあなたの.pyファイルへ

# -*- coding: utf-8 

答えて

99

あなたとUTF-8エンコードされた文字列を混在させるときに私はUnicode文字列での作業持っていた問題の主な原因は次のようなエラーで

foo = "barré" 

結果次のようなそうでないラインユニコードのもの。

たとえば、次のスクリプトを考えます。

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は、UTF-8でエンコードされた文字列であります(unicodeではなく)unicode_literalsとをインポートしなかったためですはユニコード文字列です。両方を混在させると、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'はユニコード文字列であるため、pythonはhtmlをデコードしようとするため失敗します。印刷物を修正するには、print str('DEBUG: %s') % htmlまたはprint 'DEBUG: %s' % html.decode('utf-8')のいずれかの方法があります。

これは、ユニコード文字列を使用する際の潜在的な問題点を理解するのに役立ちます。

+11

私は 'str()'や 'encode()'の代わりに 'decode()'を使うことをお勧めします:Unicodeオブジェクトを使う頻度が高いほど、コードが明確になります。外部的に暗示されたエンコーディングを持つバイト配列ではなく、文字列を操作します。 – EOL

+7

用語を修正してください。UTF-8でエンコードされた文字列とUnicodeの文字列を混在させた場合UTF-8とUnicodeでは2つの異なるエンコーディングがありません。 Unicodeは標準であり、UTF-8はそれが定義するエンコーディングの1つです。 – Kos

+10

@Kos:私は彼がユニコード(結果としてデコードされた)*オブジェクト*とオブジェクト "*を組み合わせた" utf-8でエンコードされた文字列 "を意味すると思います。前者は 'str'型、後者は' unicode'型です。 – MestreLion

13

は、私はあなたがunicode_literalsディレクティブを追加する場合にも同じようなものを追加する必要があることを発見しました。

 
SyntaxError: Non-ASCII character '\xc3' in file mumble.py on line 198, 
but no encoding declared; see http://www.python.org/peps/pep-0263.html 
for details 
+5

+1。 *すべての状況でこれをしてはいけないのですか? –

+5

@IanMackinnon:Python 3は、ファイルがデフォルトでUTF8であるとみなします。 – endolith

+3

@endolith:Python 2はそうではなく、コメントでも*非ASCII文字*を使用すると構文エラーが発生します。だからIMHO '# - * - coding:utf-8'は' unicode_literals'を使うかどうかにかかわらず事実上必須の文です。 – MestreLion

16

2.6(Python 2.6より前。5 RC1 +)のUnicodeリテラルは、キーワード引数(issue4978)との素晴らしいプレーしていません。

例えば次のコードはunicode_literalsせずに動作しますが、TypeError例外で失敗します。unicode_literalsが使用されているkeywords must be string場合。

>>> 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 
+16

Python 2.6.5 RC1 +がこれを修正しました。 –

8

は、(私見バグある非対称動作)unicode_literaleval()なくrepr()に影響を与えることを考慮し、即ちeval(repr(b'\xa4'))は(それは、Python 3と同じように)b'\xa4'と等しくなりません。以降、第アサーションが動作するように起こる

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+ 

理想的には、次のコードは常にunicode_literalsとPython {2.7、3.xの}使用の全ての組み合わせについて、動作すべき、不変になりrepr('\xa4')はPython 2.7でu'\xa4'と評価されています。

+1

ここで大きな問題は、 'repr'を使ってオブジェクトを再生成することです。 ['repr' documentation](https://docs.python.org/2/library/functions.html#func-repr)は、これが必須ではないことを明確に述べています。私の意見では、これは 'repr'をデバッグのためだけに有用なものに格下げします。 – jpmc26

5

他にもあります。

ユニコードを許容しない文字列が必要なライブラリや組み込み関数があります。

二つの例:

組み込み:

myenum = type('Enum',(), enum) 

は(わずかにesotic)unicode_literalsで動作しません:タイプ()文字列を期待。

ライブラリ:

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()への呼び出しに満ちている場合、後者は壊滅的です。

Dang it、eh?!?

+3

また、タイプのものもメタクラスに漏れます.Djangoでは 'class Meta:'で宣言した文字列は 'b'field_name''であるべきです –

+2

ええと...私のケースでは、すべてのsendMessage文字列をb 'バージョンに置き換えます。恐ろしい "デコード"例外を避けたいのであれば、あなたのプログラムで厳密にユニコードを使用して、必要に応じて入力と出力を変換するようなものはありません(トピックで読んだ一部の論文で言及されている "unicode sandwich"全体として、unicode_literalsは私にとって大きな勝利を収めています... – GreenAsJade

関連する問題