Каков правильный шаблон в Python для реализации ленивых получателей? - PullRequest
6 голосов
/ 12 марта 2012

Иногда мне нравится писать атрибуты получателя для объекта таким образом, чтобы при первом вызове тяжелая работа выполнялась один раз, а это значение сохранялось и возвращалось при будущих вызовах.В target-c я бы использовал ивар или статическую переменную для хранения этого значения.Что-то вроде:

- (id)foo
{
    if ( _foo == nil )
    {
        _foo = // hard work to figure out foo
    }
    return _foo
}

Этот же шаблон хорошо работает в Python или есть более приемлемый способ сделать это?У меня до сих пор в основном то же самое.Что мне не нравится в моем решении, так это то, что мой объект загроможден значениями и получателями этих значений:

def foo(self):
    if not hasattr(self, "mFoo":
        self.mFoo = # heavy lifting to compute foo
    return self.mFoo

Ответы [ 4 ]

7 голосов
/ 12 марта 2012

Используйте взамен ленивое свойство .Геттеры , поэтому 1990-е .

3 голосов
/ 12 марта 2012

Вместо того, чтобы делать явный тест "hasattr" каждый раз, пусть среда выполнения Python сделает это за вас.Определите __getattr__ в своем классе, который вызывается только при ссылке на неопределенный атрибут.

class Sth(object):
    @property
    def a(self):
        print "property a"
        return self._a

    def _a_compute(self):
        # put expensive computation code here
        print "_a_compute"
        return 1000

    def __getattr__(self, attr):
        print "__getattr__"
        if attr == '_a':
            self._a = self._a_compute()
            return self._a


ss = Sth()
print "first time"
print ss.a
print
print "second time"
print ss.a

Печатает следующее:

first time
property a
__getattr__
_a_compute
1000

second time
property a
1000

Вы можете опустить свойство и иметь __getattr__ проверить на «а» напрямую, но тогда у вас не будет видимости «а» как атрибута в dir для таких вещей, как самоанализ или автозаполнение IDE.

1 голос
/ 12 марта 2012

Я бы сделал что-то вроде этого:

@property
def foo(self):
    return self._foo_value if hasattr(self, '_foo_value') else calculate_foo()

def calculate_foo(self):
    self._foo_value = # heavy foo calculation
    return self._foo_value

Теперь вы можете получить доступ к "foo", если он уже рассчитан или нет, используя:

object.foo
1 голос
/ 12 марта 2012

Вы можете использовать точно такой же шаблон в Python.Вы, кажется, беспокоитесь о том, является ли необходимость делать my_object.get_foo() все время Pythonic.К счастью, Python предоставляет вам хороший инструмент для работы здесь в виде properties :

class my_class(object):

     @property
     def foo(self):
       # calculate if needed
       return self._foo

Это позволяет вам иметь то, что используется в качестве атрибута,даже если это реализовано как функция.т. е. пользователи будут делать my_object.foo, и не заботятся о том, чтобы запускать их за кулисами.

Еще одна вещь, на которую следует обратить внимание, это то, что соглашение Python гласит, что частные атрибуты пишутся _foo, а не mFoo.

...