9

Web とスタック オーバーフローの質問を検索しましたが、この質問に対する回答が見つかりませんでした。私が行った観察は、Python 2.7.3 では、2 つの変数に同じ単一の文字列を割り当てる場合、たとえば、

>>> a = 'a'
>>> b = 'a'
>>> c = ' '
>>> d = ' '

次に、変数は同じ参照を共有します。

>>> a is b
True
>>> c is d
True

これは、いくつかの長い文字列にも当てはまります。

>>> a = 'abc'
>>> b = 'abc'
>>> a is b
True
>>> '  ' is '  '
True
>>> ' ' * 1 is ' ' * 1
True

ただし、参照が (予期せず) 共有されない場合が多数あります。

>>> a = 'a c'
>>> b = 'a c'
>>> a is b
False
>>> c = '  '
>>> d = '  '
>>> c is d
False
>>> ' ' * 2 is ' ' * 2
False

誰かがこの理由を説明してもらえますか?

インタープリターによって単純化/置換が行われたり、Python 文字列が特別な場合に最適化するために不変であるという事実を利用したキャッシングメカニズムがあると思われますが、私は何を知っていますか? str コンストラクターと copy.deepcopy 関数を使用して文字列のディープ コピーを作成しようとしましたが、文字列の参照の共有には一貫性がありません。

私がこれに問題を抱えている理由は、新しいスタイルの python クラスの clone メソッド用に書いているいくつかの単体テストで、文字列への参照の不等式をチェックするためです。

4

3 に答える 3

8

The details of when strings are cached and reused are implementation-dependent, can change from Python version to Python version and cannot be relied upon. If you want to check strings for equality, use ==, not is.

In CPython (the most commonly-used Python implementation), string literals that occur in the source code are always interned, so if the same string literal occurs twice in the source code, they will end up pointing to the same string object. In Python 2.x, you can also call the built-in function intern() to force that a particular string is interned, but you actually shouldn't do so.

Edit regarding you actual aim of checking whether attributes are improperly shared between instances: This kind of check is only useful for mutable objects. For attributes of immutable type, there is no semantic difference between shared and unshared objects. You could exclude immutable types from your tests by using

Immutable = basestring, tuple, numbers.Number, frozenset
# ...
if not isinstance(x, Immutable):    # Exclude types known to be immutable

Note that this would also exclude tuples that contain mutable objects. If you wanted to test those, you would need to recursively descend into tuples.

于 2012-07-23T11:37:37.440 に答える
5

CPythonでは、実装の詳細として、コードポイントがLatin-1の範囲にある1文字の文字列と同様に、空の文字列が共有されます。この機能をバイパスすることが可能であるため、これに依存しないでください。

;を使用して文字列をインターンするように要求できます。sys.internこれは、場合によっては自動的に発生します。

通常、Pythonプログラムで使用される名前は自動的にインターンされ、モジュール、クラス、またはインスタンスの属性を保持するために使用されるディクショナリにはインターンされたキーがあります。

sys.internパフォーマンスのために(プロファイリング後に!)使用できるように公開されています。

文字列のインターンは、ディクショナリルックアップのパフォーマンスを少し向上させるのに役立ちます。ディクショナリ内のキーがインターンされ、ルックアップキーがインターンされている場合、キー比較(ハッシュ後)は、文字列比較の代わりにポインタ比較によって実行できます。

internこれはPython2に組み込まれていることに注意してください。

于 2012-07-23T11:53:04.550 に答える
4

実装と最適化のことだと思います。文字列が短い場合、それらは「共有」できます(そしてしばしばそうですか?)が、それに依存することはできません。文字列が長くなると、それらが同じではないことがわかります。

In [2]: s1 = 'abc'
In [3]: s2 = 'abc'

In [4]: s1 is s2
Out[4]: True

より長い文字列

In [5]: s1 = 'abc this is much longer'
In [6]: s2 = 'abc this is much longer'

In [7]: s1 is s2
Out[7]: False

==文字列を比較するために使用します(演算子ではありません)。is

-

これはトークンの数が原因である可能性があるというOPの観察/仮説(以下のコメント)は、以下によってサポートされているようです。

In [12]: s1 = 'a b c'
In [13]: s2 = 'a b c'

In [14]: s1 is s2
Out[14]: False

上記の最初の例と比較した場合abc

于 2012-07-23T11:38:15.863 に答える