Pythonic способ выполнять работу только при первом вызове переменной

StackOverflow https://stackoverflow.com/questions/1598174

Вопрос

в моем классе Python есть некоторые переменные, которые требуют работы для расчета при первом вызове.Последующие вызовы должны просто возвращать заранее вычисленное значение.

Я не хочу тратить время на эту работу, если она действительно не нужна пользователю.Итак, существует ли чистый Pythonic-способ реализации этого варианта использования?

Моя первоначальная мысль заключалась в том, чтобы использовать свойство() для первого вызова функции, а затем переопределить переменную:

class myclass(object):
    def get_age(self):
        self.age = 21 # raise an AttributeError here
        return self.age

    age = property(get_age)

Спасибо

Это было полезно?

Решение

class myclass(object):
    def __init__(self):
        self.__age=None
    @property
    def age(self):
        if self.__age is None:
            self.__age=21  #This can be a long computation
        return self.__age

Алекс упомянул, что вы можете использовать __getattr__, Вот как это работает

class myclass(object):
    def __getattr__(self, attr):
        if attr=="age":
            self.age=21   #This can be a long computation
        return super(myclass, self).__getattribute__(attr)

__getattr__() вызывается, когда атрибут не существует в объекте, т.е.при первой попытке доступа age.Каждый раз после этого, age существует так __getattr__ не звонят

Другие советы

property, как вы видели, не позволит вам его переопределить.Вам нужно использовать немного другой подход, например:

class myclass(object):

    @property
    def age(self):
      if not hasattr(self, '_age'):
        self._age = self._big_long_computation()
      return self._age

Существуют и другие подходы, например __getattr__ или собственный класс дескриптора, но этот проще!-)

Здесь декоратор из Поваренная книга Python для этой проблемы:

class CachedAttribute(object):
    ''' Computes attribute value and caches it in the instance. '''
    def __init__(self, method, name=None):
        # record the unbound-method and the name
        self.method = method
        self.name = name or method.__name__
    def __get__(self, inst, cls):
        if inst is None:
            # instance attribute accessed on class, return self
            return self
        # compute, cache and return the instance's attribute value
        result = self.method(inst)
        setattr(inst, self.name, result)
        return result

Да, вы можете использовать свойства, хотя ленивая оценка также часто выполняется с использованием дескрипторов, см., например:

http://blog.pythonisito.com/2008/08/lazy-descriptors.html

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top