装饰器可以在python中包装setter和getter吗?

时间:2016-11-25 19:04:20

标签: python python-decorators

我想建立各种setter和getter。 Fot没有复制和粘贴代码,我想到了解决它的问题。装饰师能做到吗?

@property
def !!variable_name!!(self):
    return self.__!!variable_name!!

@!!variable_name!!.setter
def !!variable_name!!(self, input):
    self.__!!variable_name!! = input

是否可能像C中的宏一样?

2 个答案:

答案 0 :(得分:0)

简单回答:是的,可以使用描述符协议。例如,您希望使用前导下划线保存变量并访问它们而不使用前导下划线,这样的描述符将起作用:

from six import string_types

class DescriptorSingleLeadingUnderscore(object):
    def __init__(self, attr, doc=""):
        if not isinstance(attr, string_types):
            # Not a string so take the documentation (if avaiable) and name
            # from the method.
            if attr.__doc__:
                doc = attr.__doc__
            attr = attr.__name__

        self.__doc__ = doc      # Set the documentation of the instance.
        self.attr = '_' + attr  # Add leading underscore to the attribute name

    def __get__(self, instance, owner=None):
        if instance is None:
            return self
        return getattr(instance, self.attr, None)

    def __set__(self, instance, value):
        setattr(instance, self.attr, value)

    def __delete__(self, instance):
        delattr(instance, self.attr)

class X(object):
    someproperty = DescriptorSingleLeadingUnderscore('someproperty')
    someproperty1 = DescriptorSingleLeadingUnderscore('someproperty1')
    someproperty2 = DescriptorSingleLeadingUnderscore('someproperty2')
    someproperty3 = DescriptorSingleLeadingUnderscore('someproperty3')

    @DescriptorSingleLeadingUnderscore
    def it_also_works_as_decorator(self):
        pass # this code is never executed!

一个测试用例:

>>> x = X()

>>> x.someproperty = 100
>>> x.someproperty
100
>>> x._someproperty
100

>>> x.it_also_works_as_decorator = 100
>>> x.it_also_works_as_decorator
100
>>> x._it_also_works_as_decorator
100

答案 1 :(得分:0)

目前还不清楚你为什么要这样做 - 用setter创建一个忽略其值参数的属性 - 但答案是“是”,你可以通过创建一个函数来实现返回自定义property对象:

但是,您无法使用@语法来应用它。相反,你必须如图所示使用它:

def attribute_property(name, input_value):
    STORAGE_NAME = '_' + name

    @property
    def prop(self):
        return getattr(self, STORAGE_NAME)

    @prop.setter
    def prop(self, ignored):
        setattr(self, STORAGE_NAME, input_value)

    return prop

# EXAMPLE USAGE
class Person(object):
    name = attribute_property('name', 'Monty')

    def __init__(self, name, age):
        self.name = name  # ignores value of passed "name" argument!
        self.age = age

user = Person('Rodrigo', 42)
print('user.name: {!r}'.format(user.name))
print('user.age: {!r}'.format(user.age))

输出:

user.name: 'Monty'
user.age: 42