2016-10-12 2 views
5
Pythonで

'is'演算子がリテラルで機能するように、Pythonが文字列を格納する方法は?

>>> a = 5 
>>> a is 5 
True 

しかし

>>> a = 500 
>>> a is 500 
False 

それは単一のアドレスとして低い整数値を格納するためです。しかし、数値が複雑になると、各intは固有のアドレス空間を取得します。これは私には意味がある。

現在の実装では、-5から256までのすべての整数の配列を保持しています。その範囲にintを作成すると、実際には既存のオブジェクトへの参照が返されます。

ここで、これは文字列には適用されないのはなぜですか?文字列は大きな整数ほど複雑ではありません(moresoでない場合)?

>>> a = '1234567' 
>>> a is '1234567' 
True 

pythonはどのようにしてすべての文字列リテラルに対して同じアドレスを効率的に使用しますか?それは数字のようにすべての可能な文字列の配列を保持できません。

答えて

0

すべての可能な文字列の配列を格納するのではなく、現在宣言されているすべての文字列のメモリアドレスを指し示すハッシュテーブルを持ち、文字列のハッシュによってインデックスされます。例

については

あなたがa = 'foo'を言うとき、エントリが既にハッシュテーブルに存在する場合、それは最初の文字列fooとチェックをハッシュします。はいの場合、変数aはそのアドレスを参照するようになりました。

テーブルにエントリが見つからない場合、pythonは文字列を格納するためにメモリを割り当て、ハッシュfooを割り当て、割り当てられたメモリのアドレスとともにテーブルにエントリを追加します。

関連項目:

  1. How is the 'is' keyword implemented in Python?
  2. https://en.wikipedia.org/wiki/String_interning
+0

'is'オブジェクト' id'sを比較します –

+0

これはメモリアドレスも比較します。 http://stackoverflow.com/questions/2987958/how-is-the-is-keyword-implemented-in-python –

+1

id == CPython IIRCのメモリアドレスを参照してください。 –

3

これはinterningと呼ばれる最適化手法です。 CPythonはequal values of string constantsを認識し、新しいインスタンスに余分なメモリを割り当てませんが、同じものを指しているだけです(インターン)。id()を与えます。手動intern()を使用して、既存のものにマップする文字列を強制することができますしかし

# Two string constants 
a = "aaaa" 
b = "aa" + "aa" 

# Prevent interpreter from figuring out string constant 
c = "aaa" 
c += "a" 

print id(a)   # 4509752320 
print id(b)   # 4509752320 
print id(c)   # 4509752176 !! 

一つは、定数だけがこのように(bような簡単な操作が認識されている)で処理されていることを確認するために遊ぶことができます:

c = intern(c) 

print id(a)   # 4509752320 
print id(b)   # 4509752320 
print id(c)   # 4509752320 !! 

他の通訳は、これとは別に行うことがあります。文字列は不変なので、2つのうちの一方を変更しても他方は変更されません。

+0

それは-5 256に予め定義された整数の範囲のように見えます。他のすべてはリテラルからオンザフライで作成されるように見えるので、「is」はFalseを返します。 –

+0

あなたは「最適化」と言っているが、それがどのように格納されているのかを説明していないので、答えとしてマークをしなかった。あるいは、他の人は最適化をどうやってやっていますか? –

関連する問題