1

コーディングの過程で、オブジェクトのプロパティの動作を変更する必要に直面しました (ただし、クラス プロパティではありません)。そして、すでに初期化されているオブジェクトに記述子をパッチできないことがわかりました。なぜ?

コード例

class A(object):
    pass

class D(object):
    def __init__(self, fget=None, fset=None, fdel=None, doc=None):
        pass
    def __get__(self, obj, objtype=None):
        return 5

A.x = D()
A.x
Out[12]: 5 # work!
a = A()
a.y = D()
a.y
Out[14]: <__main__.D at 0x13a8d90> # not work!
4

1 に答える 1

2

ドキュメントから。

オブジェクトの場合、機械は にobject.__getattribute__()変換b.xされtype(b).__dict__['x'].__get__(b, type(b))ます。

つまり、インスタンス( ) の属性検索は、クラス( )bの記述子呼び出しに変換されます。記述子は、クラス レベルで動作します。type(b)

なぜこれが正しいのかというと、記述子は基本的に、属性ルックアップでメソッドのような作業 (つまり、メソッドを呼び出す) を行う方法だからです。また、メソッドは基本的にクラス レベルの動作です。一般に、クラスで必要なメソッドを定義し、個々のインスタンスに余分なメソッドを追加しません。インスタンスで記述子ルックアップを行うことは、インスタンスでメソッドを定義するようなものです。

現在、インスタンスに新しいメソッドを割り当てることが可能であり、特定のクラスのインスタンスで機能する記述子を取得することも可能です。余分な作業を行うだけです。上記のドキュメントの引用にあるように、機械は にあるため、クラスobject.__getattribute__にカスタムを定義することでオーバーライドできます。__getattribute__

class Foo(object):
    def __getattribute__(self, attr):
        myDict = object.__getattribute__(self, '__dict__')
        if attr in myDict and hasattr(myDict[attr], '__get__'):
            return myDict[attr].__get__(self, type(self))
        else:
            return super(Foo, self).__getattribute__(attr)

class D(object):
    def __init__(self, fget=None, fset=None, fdel=None, doc=None):
        pass
    def __get__(self, obj, objtype=None):
        return 5

その後:

>>> f = Foo()
>>> f.x = D()
>>> f.x
5

したがって、これを行う必要があると感じた場合は、それを実現できます。これは、記述子が設計されたものではないという理由だけで、デフォルトの動作ではありません。

于 2013-02-25T07:16:35.820 に答える