如何使用@property装饰器作为模块属性?

时间:2019-10-19 17:58:30

标签: python python-3.x python-decorators

遵循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 :(得分:0)

我不敢相信答案是多么容易(以及它不是内置的或固定的),不需要反射,模块, 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])

如果此实现有缺陷,请纠正我