id()関数は何に使用されますか?


99

はPython 2のドキュメントを読みid()関数に気づきました:

オブジェクトの「アイデンティティ」を返します。これは整数(または長整数)であり、このオブジェクトの存続期間中、一意であり、定数であることが保証されています。重複しない存続期間を持つ2つのオブジェクトは、同じid()値を持つことができます。

CPython実装の詳細:これは、メモリ内のオブジェクトのアドレスです。

だから、私id()はリストを使って実験しました:

>>> list = [1,2,3]
>>> id(list[0])
31186196
>>> id(list[1])
31907092 // increased by 896
>>> id(list[2])
31907080 // decreased by 12

関数から返される整数は何ですか?Cのメモリアドレスと同義ですか?もしそうなら、なぜ整数はデータ型のサイズに対応しないのですか?

いつid()実際に使用されますか?


4
スクリプト言語のデータ構造に32ビットのintを(たとえば)格納しているからといって、32ビットのメモリをより多く使用するわけではありません。保存するデータには常にメタデータが添付されています。タイプ、サイズ、長さ、何とか何とか何とか。
Marc B

cpythonは、オブジェクトがmallocされ、解放されるとスクランブルされるヒープから割り当てます。
tdelaney 2013年

Pythonの数値は単純なデータではありません。これらは、最初にlongを内部で使用するオブジェクトであり、値が大きくなりすぎると、BigNumberスタイルの表現に自動昇格します。
Gareth Latty、2013年

回答:


156

あなたの投稿はいくつかの質問をします:

関数から返される数値は何ですか?

これは、「存続期間中にこのオブジェクトに対して一意で一定であることが保証されている整数(または長整数)です。(Python標準ライブラリ-組み込み関数)一意の数値。それ以上でもそれ以下でもありません。Pythonオブジェクトの社会保障番号または従業員ID番号と考えてください。

Cのメモリアドレスと同じですか?

概念的には、そうです。どちらも、生涯を通じて宇宙で一意であることが保証されています。そして、Pythonの特定の実装では、これは実際には対応するCオブジェクトのメモリアドレスです。

はいの場合、データ型のサイズによって数値がすぐに増加しないのはなぜですか(intであると想定しています)?

リストは配列ではなく、リスト要素はオブジェクトではなく参照であるためです。

いつ実際に使用しますか id( )関数するのはいつですか?

めったに。id()(またはそれに相当する)がis演算子で使用されます。


ここでは同様にデモ目的で、通常のid()を使用stackoverflow.com/questions/17246693/...
Nabin

49

それが場所のアイデンティティですがメモリ内のオブジェクトのです...

この例は、概念をもう少し理解するのに役立ちます。

foo = 1
bar = foo
baz = bar
fii = 1

print id(foo)
print id(bar)
print id(baz)
print id(fii)

> 1532352
> 1532352
> 1532352
> 1532352

これらはすべてメモリ内の同じ場所を指しているため、値が同じです。この例で1は、は1回だけ格納され、それ以外を指すものはすべて1そのメモリ位置を参照します。


9
ただし、-5〜256の範囲を超える数値を使用すると、fii変数に同じIDが取得されません。
saurav

それは非常に興味深いことです。もっと共有できますか?
jouell 2018

3
これはほとんどの数値には当てはまらないため、この答えは誤解を招くと思います。「is」演算子が整数で予期せず動作することを参照してください。
kevinji

8

id()(CPythonで)参照されているオブジェクトのアドレスを返しますが、PythonのリストがCの配列とは大きく異なるため、混乱が生じます。Pythonリストでは、すべての要素が参照です。だからあなたがやっていることはこのCコードにもっと似ています:

int *arr[3];
arr[0] = malloc(sizeof(int));
*arr[0] = 1;
arr[1] = malloc(sizeof(int));
*arr[1] = 2;
arr[2] = malloc(sizeof(int));
*arr[2] = 3;
printf("%p %p %p", arr[0], arr[1], arr[2]);

つまり、リストからのアドレスではなく、参照からのアドレスを出力していることになります。

私の場合、id()C pythonから呼び出すときにCコードに戻る不透明なハンドルを作成するのに便利な関数を見つけました。そうすることで、ディクショナリーを簡単に使用して、ハンドルからオブジェクトを検索でき、一意であることが保証されます。


7

ロブの答え(上で最も投票された)は正しいです。IDを使用すると、オブジェクトの比較やオブジェクトを参照するオブジェクトの検索が可能になるため、状況によっては便利であることを付け加えておきます。

後者は通常、たとえば、可変オブジェクトがクラスを言うためのパラメーターとして渡され、クラス内のローカル変数に割り当てられる奇妙なバグをデバッグするのに役立ちます。これらのオブジェクトを変更すると、クラス内の変数が変更されます。これは、複数のものが同時に変化する奇妙な動作として現れます。

最近、Python / Tkinterアプリでこの問題が発生しました。あるテキスト入力フィールドでテキストを編集すると、入力時に別のテキスト入力フィールドのテキストが変更されました:)

次に、関数id()を使用して、それらの参照がどこにあるかを追跡する方法の例を示します。決してこれは考えられるすべてのケースをカバーする解決策ではありませんが、あなたはアイデアを得ます。繰り返しになりますが、IDはバックグラウンドで使用され、ユーザーには表示されません。

class democlass:
    classvar = 24

    def __init__(self, var):
        self.instancevar1 = var
        self.instancevar2 = 42

    def whoreferencesmylocalvars(self, fromwhere):
        return {__l__: {__g__
                    for __g__ in fromwhere
                        if not callable(__g__) and id(eval(__g__)) == id(getattr(self,__l__))
                    }
                for __l__ in dir(self)
                    if not callable(getattr(self, __l__)) and __l__[-1] != '_'
                }

    def whoreferencesthisclassinstance(self, fromwhere):
        return {__g__
                    for __g__ in fromwhere
                        if not callable(__g__) and id(eval(__g__)) == id(self)
                }

a = [1,2,3,4]
b = a
c = b
democlassinstance = democlass(a)
d = democlassinstance
e = d
f = democlassinstance.classvar
g = democlassinstance.instancevar2

print( 'My class instance is of', type(democlassinstance), 'type.')
print( 'My instance vars are referenced by:', democlassinstance.whoreferencesmylocalvars(globals()) )
print( 'My class instance is referenced by:', democlassinstance.whoreferencesthisclassinstance(globals()) )

出力:

My class instance is of <class '__main__.democlass'> type.
My instance vars are referenced by: {'instancevar2': {'g'}, 'classvar': {'f'}, 'instancevar1': {'a', 'c', 'b'}}
My class instance is referenced by: {'e', 'd', 'democlassinstance'}

変数名の下線は、名前の衝突を防ぐために使用されます。関数は「fromwhere」引数を使用するため、参照の検索を開始する場所を関数に通知できます。この引数には、指定された名前空間のすべての名前をリストする関数が入ります。Globals()はそのような関数の1つです。


素晴らしい説明!
Neeraj Verma

5

私はpythonから始めて、対話型シェルを使用して変数が同じものに割り当てられているかどうか、または同じように見えるかどうかを確認するときにidを使用しています。

すべての値はIDであり、コンピュータのメモリのどこに格納されているかに関連する一意の番号です。


5

Python 3.4.1を使用している場合は、質問に対して別の回答が得られます。

list = [1,2,3]
id(list[0])
id(list[1])
id(list[2])

戻り値:

1705950792   
1705950808  # increased by 16   
1705950824  # increased by 16

定数ID -5256持つ整数。ID を複数回検索しても、IDは変わりません。これは、見つけるたびにIDが異なる、その前後の他のすべての数値とは異なります。から-5までの番号は、256IDの昇順で、によって異なります16

id()関数によって返される番号は、メモリに格納されている各アイテムに与えられた一意のIDであり、類推的にはCのメモリ位置と同じです。


2

答えはほとんどありません。IDは主にPython内部で使用されます。

平均的なPythonプログラマーは、おそらくid()コードで使用する必要はないでしょう。


3
おそらく私は平均的ではないかもしれませんが、私はid()かなり使用しています。私の頭の上の2つのユースケース:(手巻き、アドホック)ID辞書と、repr()IDが重要であるがデフォルトreprが適切ではないオブジェクトのカスタム。

5
@delnan私はそれらが一般的なケースであると主張しません。
Gareth Latty 2013年

2

isオペレータは、(同じではなく)2つのオブジェクトが同一であるかどうかを確認するためにそれを使用します。から返される実際の値id()は、実際には意味がなく、プラットフォームに依存しているため、ほとんど何も使用されません。


2

これは、ドキュメントに記載されているとおり、メモリ内のオブジェクトのアドレスです。ただし、メタデータが添付されているため、メタデータを保存するには、オブジェクトのプロパティとメモリ内の場所が必要です。したがって、listという変数を作成すると、リストとその要素のメタデータも作成されます。

そのため、言語の絶対的な第一人者でない限り、前の要素に基づいてリストの次の要素のIDを特定することはできません。これは、言語が要素とともに割り当てるものを知らないためです。


1
実際、Pythonの第一人者であることは、オブジェクトの予測にはあまり役に立ちませんid()。問題のメモリマネージャー(複数形)をよく理解し、ある時点での正確な状態を把握し、オブジェクトが割り当てられた正確な順序を把握する必要があります。言い換えれば、起こらないでしょう。

可能なメモリマネージャーを含むすべてのニュアンスを完全に知っている場合、あなたは絶対的なPythonの第一人者です。
Lajos Arpad 2013年

1
Pythonを知ることと特定の実装(CPythonなど)を知ることは2つのまったく異なるものです。とにもあるように、助けにはなりません裏返しCPythonのを知って、いくつかはCPythonの一部が、それぞれのオペレーティングシステムの一部ではないという時にメモリマネージャCPythonのコールが。そして、前に述べたように、実際のアドレスはメモリマネージャーの実行時の状態に依存し、時にはランダム化されるため、これらの非Pythonのことをすべて知っていても役に立ちません。

1
言うまでもなく、そのようなものに依存することは実装の詳細に依存することになるため、壊れやすく柔軟性に欠けるため、知ることは役に立たないでしょう。
Gareth Latty 2013年

2

id()ロギングでの値を使用するアイデアがあります。
入手するのが安くて、かなり短いです。
私の場合、トルネードを使用id()しており、ファイルに分散されて混合されたメッセージをWebソケットごとにグループ化するアンカーが必要です。


0

Python 3では、IDは変数ではなく値に割り当てられます。つまり、以下のように2つの関数を作成すると、3つのIDはすべて同じになります。

>>> def xyz():
...     q=123
...     print(id(q))
...
>>> def iop():
...     w=123
...     print(id(w))
>>> xyz()
1650376736
>>> iop()
1650376736
>>> id(123)
1650376736

これは以前の説明と矛盾していますが、それは起こっているようであり、理由はわかりません。説明はありますか?たとえば、x [0] = "abc" x [1] = "def" q = ["abc"、 "def"]です。Id(x)== Id(q)はTrueです。一致?
VMMF

0

少し遅れて、Python3についてお話します。id()とは何か、そしてそれ(およびPython)がどのように機能するかを理解するには、次の例を検討してください。

>>> x=1000
>>> y=1000
>>> id(x)==id(y)
False
>>> id(x)
4312240944
>>> id(y)
4312240912
>>> id(1000)
4312241104
>>> x=1000
>>> id(x)
4312241104
>>> y=1000
>>> id(y)
4312241200

右側のすべてのものをオブジェクトと考える必要があります。割り当てを行うたびに、新しいオブジェクトが作成され、それは新しいIDを意味します。中央には、id(1000)という関数に対してのみ作成される「ワイルド」オブジェクトが表示されます。つまり、その寿命はそのコード行のみです。次の行を確認すると、新しい変数xを作成すると、そのワイルドオブジェクトと同じIDを持つことがわかります。ほとんどメモリアドレスのように機能します。


0

注意してください(すぐ下の答えについて)... 123は-5から256の間なので、これは真実です...

In [111]: q = 257                                                         

In [112]: id(q)                                                            
Out[112]: 140020248465168

In [113]: w = 257                                                         

In [114]: id(w)                                                           
Out[114]: 140020274622544

In [115]: id(257)                                                         
Out[115]: 140020274622768
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.