python:事后更改属性getter

Isa*_*and 0 python performance properties

是否可以在创建python属性后更改其getter?

class A:
    _lookup_str = 'hi'
    @property
    def thing():
        value = some_dictionary[_lookup_str]
        # overwrite self.thing so that it is just value, not a special getter
        return value
Run Code Online (Sandbox Code Playgroud)

我的想法是,一旦我查了一次,我就不必再查一遍了(字典永远不会改变).我可以:

class A:
     _lookup_str = 'hi'
     _thing = None
     @property
     def thing():
         if not value:
             value = some_dictionary[_lookup_str]
         return value
Run Code Online (Sandbox Code Playgroud)

但即使在那里,我正在测试一个条件 - 这比我完全删除吸气剂并用一个值替换它更有效.

Jef*_*ner 7

Werkzeug有一个cached_property装饰器,可以完全满足您的需求.它只是__dict__在第一次函数调用后用第一次调用的输出替换函数的条目.

这是代码(来自github上的werkzeug.utils并略微编辑了长度):

_missing = object()

class cached_property(object):
    """A decorator that converts a function into a lazy property.  The
    function wrapped is called the first time to retrieve the result
    and then that calculated result is used the next time you access
    the value::

        class Foo(object):

            @cached_property
            def foo(self):
                # calculate something important here
                return 42

    The class has to have a `__dict__` in order for this property to
    work.
    """

    # implementation detail: this property is implemented as non-data
    # descriptor.  non-data descriptors are only invoked if there is
    # no entry with the same name in the instance's __dict__.
    # this allows us to completely get rid of the access function call
    # overhead.  If one choses to invoke __get__ by hand the property
    # will still work as expected because the lookup logic is replicated
    # in __get__ for manual invocation.

    def __init__(self, func, name=None, doc=None):
        self.__name__ = name or func.__name__
        self.__module__ = func.__module__
        self.__doc__ = doc or func.__doc__
        self.func = func

    def __get__(self, obj, type=None):
        if obj is None:
            return self
        value = obj.__dict__.get(self.__name__, _missing)
        if value is _missing:
            value = self.func(obj)
            obj.__dict__[self.__name__] = value
        return value
Run Code Online (Sandbox Code Playgroud)

(顺便说一句 - 发布代码或代码链接更好吗?)

如果您想了解有关其工作原理的更多信息,请查看描述符上Python文档.上面的代码创建了一个非数据描述符(不像@property),允许它被覆盖.