Python, 理解下面这个装饰器(based on class), 有哪几个关键点 ?
怪我咯
怪我咯 2017-04-18 10:33:42
0
2
464
class memoized_property(object):
    """A read-only @property that is only evaluated once."""

    def __init__(self, fget, doc=None):
        self.fget = fget
        self.__doc__ = doc or fget.__doc__
        self.__name__ = fget.__name__

    # 这个方法应该是这个缓存装饰器的关键
    # 因此, 我组织关键字如下
    #     * python __get__
    #     * how python __get__ works
    #     # python descript tools
    def __get__(self, obj, cls):
        if obj is None:
            return self
        obj.__dict__[self.__name__] = result = self.fget(obj)
        return result

    def _reset(self, obj):
        memoized_property.reset(obj, self.__name__)

    @classmethod
    def reset(cls, obj, name):
        obj.__dict__.pop(name, None)
怪我咯
怪我咯

走同样的路,发现不同的人生

全員に返信(2)
洪涛

memoized_propertyの実装方法によれば、以下の回答はいずれもクラス関数のデコレータとして使用することを前提としています。現時点では、このクラスはプロパティ デコレータの修正版とみなすことができます。 属性へのアクセスはPythonが優先されるためキャッシュ効果が得られます

a.val の場合、Python は次のように処理します。 a.val,Python进行如下处理:

  1. 先访问对象的__dict__,即a.__dict__['val']

  2. 如果没有再访问类的A.__dict__['val'],此时会沿着继承关系一直向上寻找;

  3. 如果找到A.__dict__['val'],返回的是值的话,那么就获得该值;如果返回的是一个描述器,则会调用描述器的__get__方法;

对于这里的memoized_property来说:

比如这个类封装了A类的val函数:

class A(object):
    ...
    
    @memoized_property
    def val(self):
        ...

a = A()
a.val

在第一次访问val的时候,根据上面的查找顺序:对象里面没有,跳到第二步;在类的字典里发现了,但发现是描述器,因此会进入到描述器中的__get__方法中。在这里,使用self.fget(obj)调用装饰的val函数并计算结果后,在返回结果的同时,将结果也存储在obj.__dict__['val']中。下次再访问a.val的时候,由于对象的__dict__中有val了,就会先查找obj.__dict__['val'],而不会大动干戈的去找__get__。这样就实现缓存一个属性的效果。而一般的__get__是不会设置obj.__dict__['xxx']的,所以每次都是重新计算。

明白了这些以后,reset就很清楚了,只不过把上一个优先级的途径去掉。然后Python就不得不沿着优先级一步步找下去,发现__get__可用,于是又在其中调用a.val方法重新计算了一遍。

__get__

  • 最初にオブジェクトの __dict__、つまり a.__dict__['val'] にアクセスします 🎜
  • 🎜クラスの A.__dict__['val'] が再度アクセスされない場合、継承関係に沿って上方向に検索されます 🎜
  • 🎜A.__dict__['val'] が見つかって値が返された場合は、記述子が返された場合はその値が取得され、記述子の __get__ が返されます。メソッド;🎜
  • 🎜memoized_property についてはこちら: 🎜 🎜たとえば、このクラスはクラス A の val 関数をカプセル化します。 🎜 リーリー 🎜初めて val にアクセスするときは、上記の検索シーケンスに従います。オブジェクト内に見つからない場合は、2 番目のステップにジャンプします。クラス ディクショナリ内に見つかります。記述子であるため、記述子の __get__ メソッドに移動します。ここでは、self.fget(obj) を使用して装飾された val 関数を呼び出し、結果を計算します。結果は obj にも格納されます。 __dict__['val']。次回 a.val にアクセスするときは、オブジェクトの __dict__val があるため、最初に obj.__dict__ を検索します。 ['val']__get__ を見つけるために戦争に行く代わりに。これにより、属性をキャッシュする効果が得られます。一般的な __get__obj.__dict__['xxx'] を設定しないため、毎回再計算されます。 🎜 🎜これを理解すると、reset は非常に明確になり、以前の優先パスを削除するだけです。次に、Python は優先度に沿って段階的に検索する必要があり、__get__ が利用可能であることが判明したため、a.val メソッドを呼び出して再計算しました。 🎜 🎜そして、__get__ の内部は、さらに良く言えます。 。 。 。 🎜
    いいねを押す +0
    Ty80

    クラスメソッドとは、クラスをインスタンス化せずに直接呼び出すことができるメソッドです

    いいねを押す +0
    人気のチュートリアル
    詳細>
    最新のダウンロード
    詳細>
    ウェブエフェクト
    公式サイト
    サイト素材
    フロントエンドテンプレート
    私たちについて 免責事項 Sitemap
    PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!