В Python один объект может «существовать» - но его внутреннее значение будет известно внешнему миру только в тот момент, когда он используется с одним из операторов - поскольку операторы определяются в классе волшебными именами с двойное подчеркивание: если класс пишет соответствующий код для выполнения отложенного кода при вызове оператора, это нормально.
Это означает, что, если значение объекта, например, будет использоваться как строка, любая часть программы, которая будет использовать объект, в какой-то момент вызовет метод приведения "__str__".
Например, давайте создадим объект, который ведет себя как строка, но сообщает текущее время. Строки можно объединять с другими строками (__ add__), запрашивать их длину (__len__) и т. Д. Если мы хотим, чтобы он идеально подходил вместо строки, нам пришлось бы переопределить все методы. Идея состоит в том, чтобы получить фактическое значение только при вызове одного из операторов - в противном случае фактический объект можно свободно назначать переменным и передавать вокруг. Он будет оцениваться только тогда, когда необходимо его значение
Тогда можно получить такой код:
class timestr(object):
def __init__(self):
self.value = None
def __str__(self):
self._getvalue()
return self.value
def __len__(self):
self._getvalue()
return len(self.value)
def __add__(self, other):
self._getvalue()
return self.value + other
def _getvalue(self):
timet = time.localtime()
self.value = " %s:%s:%s " % (timet.tm_hour, timet.tm_min, timet.tm_sec)
И используя его на консоли, вы можете иметь:
>>> a = timestr()
>>> b = timestr()
>>> print b
17:16:22
>>> print a
17:16:25
Если значение, для которого вы хотите ленивую оценку, является атрибутом вашего объекта (например, Peson.name) вместо того, как фактически ведет себя ваш объект - это еще проще. Поскольку Python позволяет всем атрибутам объекта иметь специальный тип - называемый дескриптором, - который фактически имеет метод, вызываемый каждый раз, когда к атрибуту обращаются. Следовательно, нужно просто создать класс с подходящим методом с именем __get__
, чтобы получить действительное значение. Этот метод будет вызываться только тогда, когда атрибут необходим.
В Python даже есть утилита для простого создания дескриптора - ключевое слово «property», которое делает это еще проще - вы передаете метод, который является кодом для генерации атрибута, в качестве первого параметра для свойства.
Таким образом, наличие класса Event с ленивым (и живым) оцененным временем - просто вопрос записи:
import time
class Event(object):
@property
def time(self):
timet = time.localtime()
return " %s:%s:%s " % (timet.tm_hour, timet.tm_min, timet.tm_sec)
И используйте это как:
>>> e= Event()
>>> e.time
' 17:25:8 '
>>> e.time
' 17:25:10 '