python @property setter/deleter

获取/更新对象属性:getattr/setattr,但是没有办法检查检查参数,导致可以任意设置对象属性.
为了解决这个问题,引入property:
Python内置的@property装饰器就是负责把一个方法变成属性调用
用property来获取/更新/删除属性


class property(object):
    """
    Property attribute.
    
      fget
        function to be used for getting an attribute value
      fset
        function to be used for setting an attribute value
      fdel
        function to be used for del'ing an attribute
      doc
        docstring
    
    Typical use is to define a managed attribute x:
    
    class C(object):
        def getx(self): return self._x
        def setx(self, value): self._x = value
        def delx(self): del self._x
        x = property(getx, setx, delx, "I'm the 'x' property.")
    
    Decorators make defining new properties or modifying existing ones easy:
    
    class C(object):
        @property
        def x(self):
            "I am the 'x' property."
            return self._x
        @x.setter
        def x(self, value):
            self._x = value
        @x.deleter
        def x(self):
            del self._x
    """
    def deleter(self, *args, **kwargs): # real signature unknown
        """ Descriptor to change the deleter on a property. """
        pass

    def getter(self, *args, **kwargs): # real signature unknown
        """ Descriptor to change the getter on a property. """
        pass

    def setter(self, *args, **kwargs): # real signature unknown
        """ Descriptor to change the setter on a property. """
        pass

使用@property装饰器来创建只读属性,@property装饰器会将方法转换为相同名称的只读属性,可以与所定义的属性配合使用,这样可以防止属性被修改。
由于python进行属性的定义时,没办法设置私有属性,因此要通过@property的方法来进行设置。这样可以隐藏属性名,让用户进行使用的时候无法随意修改。

class DataSet(object):
    def __init__(self):
        self._images = 1
        self._labels = 2  # 定义属性的名称

    @property
    def images(self):  # 方法加入@property后,这个方法相当于一个属性,这个属性可以让用户进行使用,而且用户没办法随意修改。
        return self._images

    @property
    def labels(self):
        return self._labels


l = DataSet()
# 用户进行属性调用的时候,直接调用images即可,而不用知道属性名_images,因此用户无法更改属性,从而保护了类的属性。
print(l.images)  # 加了@property后,可以用调用属性的形式来调用方法,后面不需要加()

注意事项:
1.定义的方法名称必须要是变量名(如属性名是name,那函数名称就为name,不能为其他的)
2.属性的方法名不要和实例变量重名

错误示例1:方法名和实例变量重名

class Test(object):

    @property
    def name(self):
        return self.name

    @name.setter
    def name(self, value):
        print("seting")
        if len(value) > 4:
            print("value error")
            exit(1)
        else:
            self.name = value

    @name.deleter
    def name(self):
        del self.name


if __name__ == '__main__':
    tes = Test()
    print(getattr(tes, "name", None))
    tes.name = "Lisa"
    print(getattr(tes, "name", None))
    del tes.name
    print(getattr(tes, "name", None))
    tes.name = "LisaA"
# RecursionError: maximum recursion depth exceeded

这是因为在 name 属性的 setter 方法中,对属性 self.name 进行了赋值,这会再次调用 setter 方法,从而陷入无限循环递归调用的状态,最终导致了栈溢出,报错RecursionError
修改代码:

class Test(object):

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, value):
        print("seting")
        if len(value) > 4:
            print("value error")
            exit(1)
        else:
            self._name = value

    @name.deleter
    def name(self):
        del self._name


if __name__ == '__main__':
    tes = Test()
    print(getattr(tes, "name", None))
    tes.name = "Lisa"
    print(getattr(tes, "name", None))
    del tes.name
    print(getattr(tes, "name", None))
    tes.name = "LisaA"


# None
# seting
# Lisa
# None
# seting
# value error

错误示例2:要修改的变量名和方法名不一致,在执行修改操作的时候,并没有调用 @get_value.setter,get_value 方法只有一个 getter,但在代码中使用了 setter 和 deleter 装饰器来定义它们,应该将它们的名称修改为 get_value

class Test(object):
    def __init__(self):
        self.name = "Tom"
        self.age = 20

    @property
    def get_value(self):
        return self.name, self.age

    @get_value.setter
    def set_value(self, age):
        print("seting")
        print(age < 100)
        if age > 0 or age < 100:
            self.age = age
        else:
            raise ValueError('age must between 0 and 100!')

    @get_value.deleter
    def del_value(self, value):
        print("deleting")
        if getattr(self, value, None):
            delattr(self, value)


if __name__ == '__main__':
    tes = Test()
    print(tes.get_value)
    tes.name = "Lisa"
    tes.age = 130
    print(tes.get_value)
    del tes.name
    print(getattr(tes, "name", None), getattr(tes, "age", 0))

# ('Tom', 20)
# ('Lisa', 130)
# None 130

修改代码:

class Test(object):
    def __init__(self):
        self.name = "Tom"
        self.age = 20

    @property
    def get_value(self):
        return self.name, self.age

    @get_value.setter
    def get_value(self, age):
        print("setting")
        if age >= 0 and age <= 100:
            self.age = age
        else:
            raise ValueError('age must be between 0 and 100!')

    @get_value.deleter
    def get_value(self):
        print("deleting")
        if getattr(self, 'name', None):
            delattr(self, 'name')
        if getattr(self, 'age', None):
            delattr(self, 'age')


if __name__ == '__main__':
    tes = Test()
    print(tes.get_value)
    tes.name = "Lisa"
    tes.age = 130
    print(tes.get_value)
    del tes.name
    print(getattr(tes, "name", None), getattr(tes, "age", 0))

设置多个参数值:

class Test(object):
    def __init__(self):
        self._value1 = "Tom"
        self._value2 = "Lisa"

    @property
    def values(self):
        return self._value1, self._value2

    @values.setter
    def values(self, values):
        print("seting")
        if len(values) == 2:
            self._value1, self._value2 = values
        else:
            raise ValueError('Two parameters are required.!')

    @values.deleter
    def values(self):
        print("deleting")
        del self._value1
        del self._value2


if __name__ == '__main__':
    tes = Test()
    print(tes.values)
    tes.values = "KS1", "KS2"
    print(tes.values)
    del tes.values
    print(getattr(tes, "_value1", None), getattr(tes, "_value1", 0))
    tes.values = "A1", "A2", "A3"
    print(tes.values)

# ('Tom', 'Lisa')
# seting
# ('KS1', 'KS2')
# deleting
# None 0
# seting
# ValueError: Two parameters are required.!


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值