0

次のようなクラスがあるとしましょう:

class Test(object):
    prop = property(lambda self: "property")

にアクセスしようとすると、記述子が優先されますTest().prop。だからそれは戻り'property'ます。オブジェクトのインスタンス ストレージにアクセスする場合は、次のようにします。

x = Test()
x.__dict__["prop"] = 12
print(x.__dict__["prop"])

ただし、クラスを次のように変更すると:

class Test(object):
    __slots__ = ("prop",)
    prop = property(lambda self: "property")

xもう存在しないので、同じことを行い、 の内部ストレージにアクセスして書き込み12と読み取りを行うにはどうすればよいx.__dict__ですか?

私は Python にかなり慣れていませんが、Python の哲学は完全な制御を与えることであることを理解しています。

Python には、インスタンスの内部ストレージから読み取ることができる組み込み関数がありませんか?

instance_vars(x)["prop"] = 12
print(instance_vars(x)["prop"])

、および?を持たない組み込み型でvarsも機能することを除いて、これは のように機能します。__slots____dict__

4

3 に答える 3

3

短い答え、あなたはできません

問題は、スロット自体が記述子の観点から実装されていることです。与えられた:

class Test(object):
    __slots__ = ("prop",)

t = Test()

表現:

t.prop

おおよそ次のように翻訳されます。

Test.prop.__get__(t, Test)

whereTest.propは、特にインスタンスの予約済みスペースから値<type 'member_descriptor'>をロードするために、ランタイムによって作成されます。propTest

クラス本体の定義に別の記述子を追加するmember_descriptorと、スロット属性にアクセスできるようになる がマスクされます。それを求める方法はありません。もうそこにはありません。それは事実上、次のように言っているようなものです:

class Test(object):
    @property
    def prop(self):
        return self.__dict__['prop']

    @property
    def prop(self):
        return "property"

あなたはそれを2回定義しました。prop最初の定義に「到達」する方法はありません。


しかし:

長い答え、一般的な方法ではできませんあなたはできる

Python 型システムを悪用して、別のクラス定義を使用することもできます。まったく同じクラス レイアウトを持っている限り、Python オブジェクトの型を変更することができます。これは、大まかに同じスロットをすべて持っていることを意味します。

>>> class Test1(object):
...     __slots__ = ["prop"]
...     prop = property(lambda self: "property")
... 
>>> class Test2(object):
...     __slots__ = ["prop"]
... 
>>> t = Test1()
>>> t.prop
'property'
>>> t.__class__ = Test2
>>> t.prop = 5
>>> t.prop
5
>>> t.__class__ = Test1
>>> t.prop
'property'

しかし、インスタンスをイントロスペクトしてそのクラス レイアウトを解決する一般的な方法はありません。コンテキストから知る必要があります。そのクラス属性を見ることはできますが__slots__、スーパークラスで提供されているスロット (存在する場合) についてはわかりません。また、クラスが定義された後に何らかの理由でその属性が変更された場合、ヒントも得られません。

于 2012-05-15T13:30:45.010 に答える
1

何をなぜこれをしたいのかよくわかりませんが、これは役に立ちますか?

>>> class Test(object):
    __slots__ = ("prop",)
    prop = property(lambda self: "property")


>>> a = Test()
>>> b = Test()
>>> a.prop
'property'
>>> tmp = Test.prop
>>> Test.prop = 23
>>> a.prop
23
>>> Test.prop = tmp; del tmp
>>> b.prop
'property'

もちろん、インスタンスごとにプロパティを上書きすることはできません。これがスロット記述子の要点です。

を手動で定義しない限り__slots__、クラス with のサブクラスには a があることに注意してください。__dict____slots__

>>> class Test2(Test):pass

>>> t = Test2()
>>> t.prop
'property'
>>> t.__dict__['prop'] = 5
>>> t.__dict__['prop']
5
>>> Test2.prop
<property object at 0x00000000032C4278>

それでも:

>>> t.prop
'property'

これは のせいではなく、__slots__記述子の仕組みです。

属性ルックアップでバイパスされます__dict__。状態を保存するためにたまたまそこにあるデータ構造として悪用しているだけです。これを行うことは同等です:

>>> class Test(object):
    __slots__ = ("prop", "state")
    prop = property(lambda self: "property")
    state = {"prop": prop}


>>> t.prop
'property'
>>> t.state["prop"] = 5
>>> t.state["prop"]
5
>>> t.prop
'property'
于 2012-05-15T13:00:07.627 に答える
0

あなたが本当にそのようなことをしたいと思ったことがあり、そのようなことが本当に本当に必要な場合は、いつでもオーバーライドできます__getattribute__and __setattribute__、それは同じくらい愚かです...これはあなたにそれを証明するためです:

class Test(object):
    __slots__ = ("prop",)
    prop = property(lambda self: "property")
    __internal__ = {}

    def __getattribute__(self, k):
        if k == "__dict__":
            return self.__internal__
        else:
            try:
                return object.__getattribute__(self, k)
            except AttributeError, e:
                try:
                    return self.__internal__[k]
                except KeyError:
                    raise e

    def __setattribute__(self, k, v):
        self.__internal__[k] = v
        object.__setattribute__(self, k, v)

t = Test()

print t.prop

t.__dict__["prop"] = "test"
print "from dict", t.__dict__["prop"]
print "from getattr", t.prop

import traceback
# These won't work: raise AttributeError
try:
    t.prop2 = "something"
except AttributeError:
    print "see? I told you!"
    traceback.print_exc()

try:
    print t.prop2
except AttributeError:
    print "Haha! Again!"
    traceback.print_exc()

(Python 2.7 で試してみました) それはまさにあなたが私が推測するものです。これをしないでください、それは無駄です。

于 2012-05-15T13:25:30.340 に答える