unicode() がエンコードを指定せずにオブジェクトに対してのみ str() を使用するのはなぜですか?

StackOverflow https://stackoverflow.com/questions/106630

  •  01-07-2019
  •  | 
  •  

質問

まず、いくつかの文字列変数を作成します 非アスキー UTF-8 その上のエンコードされたデータ:

>>> text = 'á'
>>> text
'\xc3\xa1'
>>> text.decode('utf-8')
u'\xe1'

使用する unicode() エラーが発生します...

>>> unicode(text)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 0: 
                    ordinal not in range(128)

...しかし、エンコーディングがわかっていれば、それを 2 番目のパラメータとして使用できます。

>>> unicode(text, 'utf-8')
u'\xe1'
>>> unicode(text, 'utf-8') == text.decode('utf-8')
True

このテキストを返すクラスがあるとします。 __str__() 方法:

>>> class ReturnsEncoded(object):
...     def __str__(self):
...         return text
... 
>>> r = ReturnsEncoded()
>>> str(r)
'\xc3\xa1'

unicode(r) 使っているようです str() と同じエラーが発生するため、 unicode(text) その上:

>>> unicode(r)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 0: 
                    ordinal not in range(128)

ここまではすべて計画通りです!

しかし、誰も予想していなかったように、 unicode(r, 'utf-8') 試してもみません:

>>> unicode(r, 'utf-8')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: coercing to Unicode: need string or buffer, ReturnsEncoded found

なぜ?なぜこのような一貫性のない動作が起こるのでしょうか?バグですか?それは意図されたものですか?とても気まずい。

役に立ちましたか?

解決

この動作は混乱を招くように見えますが、意図的なものです。ここに、Unicode ドキュメント全体を転載します。 Python 組み込み関数のドキュメント (これを書いている時点ではバージョン 2.5.2 の場合):

unicode([オブジェクト[, エンコード[, エラー]]])

次のいずれかのモードを使用して、オブジェクトの Unicode 文字列バージョンを返します。

エンコードおよび/またはエラーが指定されている場合、Unicode()は、エンコードのためにコーデックを使用して、8ビット文字列または文字バッファーのいずれかであるオブジェクトをデコードします。エンコーディングパラメーターは、エンコードの名前を与える文字列です。エンコーディングが知られていない場合、lookuperrorが上昇します。エラー処理はエラーに従って行われます。これは、入力エンコードで無効な文字の処理を指定します。エラーが「厳格」(デフォルト)の場合、バリューエラーがエラーで上昇し、「無視」の値はエラーを静かに無視し、「置換」の値は公式のユニコード置換文字u+fffdを引き起こします。デコードできない入力文字を交換するために使用されます。も参照してください。 コーデック モジュール。

オプションのパラメーターが与えられていない場合、Unicode()は、8ビット文字列の代わりにUnicode文字列を返すことを除いて、str()の動作を模倣します。より正確には、オブジェクトがUnicode文字列またはサブクラスである場合、追加のデコードを適用することなく、そのUnicode文字列を返します。

__ unicode __()メソッドを提供するオブジェクトの場合、Unicode文字列を作成するために引数なしでこの方法を呼び出します。他のすべてのオブジェクトについては、8ビット文字列バージョンまたは表現が要求され、「Strict」モードでデフォルトのエンコードのためにコーデックを使用してUnicode文字列に変換されます。

バージョン 2.0 の新機能。バージョン 2.2 で変更された点:__unicode__() のサポートが追加されました。

それで、あなたが電話するとき、 unicode(r, 'utf-8'), 、最初の引数として 8 ビット文字列または文字バッファーが必要なので、 __str__() メソッドを使用し、それをデコードしようとします。 utf-8 コーデック。なしで utf-8, 、 unicode() 関数は a を探します __unicode__() オブジェクトのメソッドが見つからず、 __str__() あなたが提案したように、デフォルトのコーデックを使用して Unicode に変換しようとしています。

他のヒント

unicode はテキストのエンコーディングを推測しません。オブジェクト自体を次のように出力できる場合 unicode, を定義します。 __unicode__() Unicode 文字列を返すメソッド。


その秘密は、 unicode(r) 実際に電話をかけているわけではありません __str__() 自体。代わりに、 __unicode__() 方法。デフォルトの実装は、 __unicode__() 電話します __str__() そして、それを使用してデコードを試みます ascii 文字コード。エンコーディングを渡すと、 unicode() 最初のオブジェクトがデコードできるもの、つまり、のインスタンスであることを期待します。 basestring.


「utf-8」を渡さないとASCIIとしてデコードしようとするため、動作が奇妙です。しかし、「utf-8」を渡すと、別のエラーが発生します...

これは、「utf-8」を指定すると、最初のパラメータがデコードされる文字列のようなオブジェクトとして扱われるためです。これがないと、パラメータは Unicode に強制されるオブジェクトとして扱われます。

混乱がわかりません。そのオブジェクトが text 属性は常に UTF-8 でエンコードされます。定義するだけです __unicode__() そうすればすべてがうまくいくでしょう。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top