Pythonic способ выполнять работу только при первом вызове переменной
-
22-09-2019 - |
Вопрос
в моем классе 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
Да, вы можете использовать свойства, хотя ленивая оценка также часто выполняется с использованием дескрипторов, см., например: