112

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

13 に答える 13

165

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

関数から返される数値は?

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

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

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

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

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

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

めったに。ID を比較することで 2 つの参照が同じかどうかをテストできますが、is演算子は常に推奨される方法です。id( )デバッグ状況でのみ本当に役立ちます。

于 2013-03-27T19:05:37.130 に答える
55

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

この例は、概念をもう少し理解するのに役立つかもしれません。

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そのメモリ ロケーションを参照します。

于 2013-03-27T18:59:55.300 に答える
11

ロブの答え(上で最も投票された)は正しいです。オブジェクトを比較し、どのオブジェクトがあなたのオブジェクトを参照しているかを見つけることができるので、場合によっては 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 つです。

于 2015-03-16T21:11:41.710 に答える
10

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]);

つまり、リストが保存されている場所に関連するアドレスではなく、参照からアドレスを印刷しています。

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

于 2013-03-27T19:04:33.313 に答える
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 を持つその前後の他のすべての数字とは異なります。-5からまでの番号は、 256ID が昇順であり、 によって異なります16

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

于 2014-09-20T02:31:11.797 に答える
5

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

すべての値は ID であり、コンピューターのメモリ内の格納場所に関連する一意の番号です。

于 2013-03-27T19:16:29.020 に答える
3

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

于 2013-03-27T19:04:22.853 に答える
2

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

于 2016-04-14T19:32:34.057 に答える
2

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

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

于 2013-03-27T19:01:48.157 に答える
2

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

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

于 2013-03-27T19:06:00.250 に答える