Как использовать @property decorator в качестве атрибута модуля? - PullRequest
0 голосов
/ 19 октября 2019

После PEP-562:

https://www.python.org/dev/peps/pep-0562/

теперь можно определить атрибут для модуля. К сожалению, некоторые из встроенных компонентов еще не адаптировались к этой новой функции. В следующем коде:

@property
def lazyFn():
    return 3

v = lazyFn

v

В идеале v должно иметь значение атрибута 3. К сожалению, текущая реализация @property дает только следующий результат:

<property at 0x7f3e703eae30>

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

1 Ответ

0 голосов
/ 20 октября 2019

Я не могу поверить, насколько простым может быть ответ (и как он не является встроенным или незакрепленным), нет необходимости в рефлексии, модуле, setattr или PEP-562. Все, что мне нужно, это определить декоратор:


def lazy(fn):
    if fn.__name__ == fn.__qualname__:
        # not a property
        result = fn()
        return result
    else:
        return LazyProperty(fn)

# the following are from PyPI lazy library
class LazyProperty(object):
    """lazy descriptor
    Used as a decorator to create lazy attributes. Lazy attributes
    are evaluated on first use.
    """

    def __init__(self, func):
        self.__func = func
        functools.wraps(self.__func)(self)

    def __get__(self, inst, inst_cls):
        if inst is None:
            return self

        if not hasattr(inst, '__dict__'):
            raise AttributeError("'%s' object has no attribute '__dict__'" % (inst_cls.__name__,))

        name = self.__name__
        if name.startswith('__') and not name.endswith('__'):
            name = '_%s%s' % (inst_cls.__name__, name)

        value = self.__func(inst)
        inst.__dict__[name] = value
        return value

, чтобы проверить его:

nn = 0


@lazy
def fn1():
    global nn
    nn = nn + 1
    return nn


@dataclass
class HasFn2(object):
    nn = 0

    @lazy
    def fn2(self):
        self.nn = self.nn + 1
        return self.nn


def test_lazy():

    vs1 = [fn1 for i in range(0, 5)]
    assert vs1 == [1, 1, 1, 1, 1]

    c = HasFn2()
    vs2 = [c.fn2 for i in range(0, 5)]
    assert (vs2 == [1, 1, 1, 1, 1])

Пожалуйста, исправьте меня, если эта реализация неисправна

...