6

この質問は、(少なくとも) CPython 2.7.2 および 3.2.2 に関するものです。

と を次のように定義するClassobjします。

class Class(object):

    def m(self):
        pass

    @property
    def p(self):
        return None

    @staticmethod
    def s():
        pass

obj = Class()

短縮版

False次のコードがそれぞれに対して出力されるのはなぜprint()ですか?

print(Class.__dict__ is Class.__dict__)
print(Class.__subclasshook__ is Class.__subclasshook__)
print(Class.m is Class.m)

print(obj.__delattr__ is obj.__delattr__)
print(obj.__format__ is obj.__format__)
print(obj.__getattribute__ is obj.__getattribute__)
print(obj.__hash__ is obj.__hash__)
print(obj.__init__ is obj.__init__)
print(obj.__reduce__ is obj.__reduce__)
print(obj.__reduce_ex__ is obj.__reduce_ex__)
print(obj.__repr__ is obj.__repr__)
print(obj.__setattr__ is obj.__setattr__)
print(obj.__sizeof__ is obj.__sizeof__)
print(obj.__str__ is obj.__str__)
print(obj.__subclasshook__ is obj.__subclasshook__)
print(obj.m is obj.m)

(これは Python 2 の場合です。Python 3 の場合は、print()forを省略して、、、、、およびに同様の s をClass.m追加します)print()obj.__eq__obj.__ge__obj.__gt__obj.__le__obj.__lt__obj.__ne__

一方、次のコードTrueがそれぞれに対して出力されるのはなぜprint()ですか?

print(Class.__class__ is Class.__class__)
print(Class.__delattr__ is Class.__delattr__)
print(Class.__doc__ is Class.__doc__)
print(Class.__format__ is Class.__format__)
print(Class.__getattribute__ is Class.__getattribute__)
print(Class.__hash__ is Class.__hash__)
print(Class.__init__ is Class.__init__)
print(Class.__module__ is Class.__module__)
print(Class.__new__ is Class.__new__)
print(Class.__reduce__ is Class.__reduce__)
print(Class.__reduce_ex__ is Class.__reduce_ex__)
print(Class.__repr__ is Class.__repr__)
print(Class.__setattr__ is Class.__setattr__)
print(Class.__sizeof__ is Class.__sizeof__)
print(Class.__str__ is Class.__str__)
print(Class.__weakref__ is Class.__weakref__)
print(Class.p is Class.p)
print(Class.s is Class.s)

print(obj.__class__ is obj.__class__)
print(obj.__dict__ is obj.__dict__)
print(obj.__doc__ is obj.__doc__)
print(obj.__module__ is obj.__module__)
print(obj.__new__ is obj.__new__)
print(obj.__weakref__ is obj.__weakref__)
print(obj.p is obj.p)
print(obj.s is obj.s)

(これは Python 2 の場合です。Python 3の場合は、 、 、 、、、、およびに同様print()の s を追加します)Class.__eq__Class.__ge__Class.__gt__Class.__le__Class.__lt__Class.__ne__Class.m

ロングバージョン

2 回続けて要求するとid(obj.m)、(当然のことながら) 同じオブジェクト ID が 2 回取得されます。

>>> id(obj.m)
139675714789856
>>> id(obj.m)
139675714789856

ただし、 を要求しid(obj.m)、 を参照するいくつかの式を評価してから再度obj.m要求するid(obj.m)と、(常にではありませんが) オブジェクト ID が変更されていることがわかります。変化する状況の中には、id(obj.m)もう一度要求すると ID が元の値に戻るものもあります。元に戻らない場合、id(obj.m)呼び出し間で式を繰り返すと、明らかに ID が 2 つの観測値の間で交互に表示されます。

オブジェクト ID が変更されない例を次に示します。

>>> print(obj.m); id(obj.m)
<bound method Class.m of <__main__.Class object at 0x7f08c96058d0>>
139675714789856
>>> obj.m is None; id(obj.m)
False
139675714789856
>>> obj.m.__func__.__name__; id(obj.m)
'm'
139675714789856
>>> obj.m(); id(obj.m)
139675714789856

以下は、オブジェクト ID が変更されてから元に戻る例です。

>>> obj.m; id(obj.m); id(obj.m)
<bound method Class.m of <__main__.Class object at 0x7f08c96058d0>>
139675715407536
139675714789856

オブジェクト ID が変更された後、元に戻らない例を次に示します。

>>> obj.m is obj.m; id(obj.m); id(obj.m)
False
139675715407536
139675715407536

以下は同じ例で、交互の動作を示すためにオペラント式が数回繰り返されています。

>>> obj.m is obj.m; id(obj.m); id(obj.m)
False
139675714789856
139675714789856
>>> obj.m is obj.m; id(obj.m); id(obj.m)
False
139675715407536
139675715407536
>>> obj.m is obj.m; id(obj.m); id(obj.m)
False
139675714789856
139675714789856

したがって、質問全体は次の部分で構成されます。

  • それらの属性を変更しない式の副作用として、どのような種類の属性がアイデンティティを変更する可能性がありますか?

  • その変化のきっかけとなる表情とは?

  • このような変化をもたらすメカニズムとは?

  • 過去のアイデンティティはどのような条件下でリサイクルされるのか?

  • 最初の ID が無期限にリサイクルされないのはなぜでしょうか?

  • これは文書化されていますか?

4

2 に答える 2

5

それらの属性を変更しない式の副作用として、どのような種類の属性がそのアイデンティティを変更する可能性がありますか?

プロパティ、より正確には記述子プロトコルを実装するオブジェクト。たとえば、Class.__dict__は adictではなくdictproxyです。明らかに、このオブジェクトは要求されるたびに新しく生成されます。なんで?おそらく、必要になるまでオブジェクトを作成するオーバーヘッドを削減するためです。ただし、これは実装の詳細です。重要なことは、__dict__ドキュメントどおりに機能することです。

通常のインスタンス メソッドでさえ記述子を使用して処理されるため、その理由が説明されていますobj.m is not obj.m。興味深いことに、そのメソッド ラッパーをインスタンスに永続的に保存してobj.m = obj.mからobj.m is obj.m . :-)

どのような表現がそのような変化を引き起こしますか?

属性へのアクセス__get__()は記述子のメソッドをトリガーでき、このメソッドは常に同じオブジェクトを返すことも、毎回異なるオブジェクトを返すこともできます。

そのような変化を引き起こすメカニズムは何ですか?

プロパティ/記述子。

過去のアイデンティティはどのような条件下でリサイクルされるのか?

「リサイクル」の意味がわかりません。「廃棄」または「再利用」という意味ですか?CPython では、idオブジェクトの はそのメモリ ロケーションです。2 つのオブジェクトが異なる時間に同じメモリ位置にある場合、それらは同じid. id したがって、異なる時点で同じものを持つ 2 つの参照(単一のステートメント内であっても) は、必ずしも同じオブジェクトではありません。他の Python 実装では、 の生成に異なる規則が使用されますid。たとえば、Jython はインクリメントする整数を使用していると思います。これにより、オブジェクトの識別がより明確になります。

最初の ID が無期限にリサイクルされないのはなぜですか?

おそらく、記述子を使用することにはいくつかの利点がありました。Python インタープリターのソース コードが利用可能です。詳細を知りたい場合は、それを見てください。

これは文書化されていますか?

いいえ。これらは CPython インタープリターの実装固有の詳細であり、依存するべきではありません。他の Python 実装 (CPython の将来のバージョンを含む) は異なる動作をする可能性があり、おそらくそうなるでしょう。たとえば、2.x と 3.x の CPython には大きな違いがあります。

于 2012-04-18T23:59:27.703 に答える
2

xy と書くと、バインドされたメソッドまたはバインドされていないメソッドが作成されます。これは新しいオブジェクトです。メモリ内のどこにでも移動できます。xy を書き、結果を使用しない場合、その refcnt がゼロになって収集される可能性があります。これは、メモリが利用可能であり、おそらく同じ場所にある次の xy で使用できることを意味しますが、必ずしもそうとは限りません。

CPython は、オブジェクトの同一性についてほとんど保証しないことに注意してください (つまり、Noneのインスタンスが 1 つだけ存在することが保証されます)。それ以外の場合、表示されるものの多くは、変更される可能性のある任意の実装の選択です。

于 2012-04-19T03:07:06.670 に答える