如何理解python中的@property属性和@setter属性

@property 装饰器使一个方法可以像属性一样被使用,而不需要在调用的时候带上() 接下来我们会深入了解一下我们什么时候需要使用它,并且在什么场景下需要用到它以及如何很好的使用它
一、@property简介
你在看review别人代码的时候,可能看到过在方法上添加property 装饰器的场景。不过在深入了解之前,你需要对python中的class 有一定的了解,因为通常我们使用property 装饰器就用在类中。
二、 @property做了什么
之前我们说过@property 可以使类中的方法,可以像类中属性一样的方式被调用
首先我们创建一个person 类,类中包含first,last 和 fullname 属性,并且包含一个email() 方法,可以提供一个人的email

class Person():

    def __init__(self, firstname, lastname):
        self.first = firstname
        self.last = lastname
        self.fullname = self.first + ' ' + self.last

    def email(self):
        return '{}.{}@email.com'.format(self.first, self.last)

person = Person('zhang', 'san')
print(person.first)
print(person.last)
print(person.fullname)
print(person.email())

输出的结果为

zhang
san
zhang san
zhang.san@email.com

将其中的一个修改一下之后发现

person.last = 'si'
print(person.first)
print(person.last)
print(person.fullname)
print(person.email())

输出的结果为

zhang
si
zhang san
zhang.si@email.com
三、什么时候使用property
突然zhang san 改名为zhang si了,你也需要更改zhang san 这个对象的属性,但是这个时候你就会发现,你在更改zhang san的名字之后,它其他的属性并没有自动的改变。
比如,当你修改self.last 的时候,你会希望self.fullname 会随着self.last 的改变而自动更新。但是self.fullname 并没有更新,这个属性的值就可能误导使用者。
但是email() 方法输出的内容就可以随着self.last 的更改而更新
这时候,作为大聪明的你就可能会相当,我们把self.fullname 属性改为fullname() 方法,我们不就可以正常使用了嘛,比如:

class Person():
    def __init__(self, first_name, last_name):
        self.first = first_name
        self.last = last_name
    def fullname(self):
        return self.first + ' ' + self.last
    def email(self):
        return '{}.{}@email.com'.format(self.first, self.last)

person = Person('zhang', 'san')
print(person.fullname())

person.last = 'si'
print(person.fullname())

我们发现使用这种方式来促使fullname自动进行更新是没有问题的
但是我们通过使用person.fullname() 这种带有() 括号的方式来调用,而不是像调用属性那样,直接使用person.fullname 来获得属性,这就会使之前使用person.fullname 来获得属性的方式全部失效。如果你这个属性是放在一个工具类中,你的同事使用你写的工具类进行开发,当你将这个属性改为方法时,之前所有导入你写的工具类的代码都将不能正常工作。
所以,将一个属性,转化为一个方法时,我们最好加上一个@property 装饰器来解决这个问题。在方法定义上面加一个@property 装饰器,可以在不改变原有调用方式的同时,来将一个属性改为一个方法。

添加@property属性,可以在不改变原有调用规则的基础上,获得正确的fullname

class Person():
    def __init__(self, first_name, last_name):
        self.first = first_name
        self.last = last_name

    @property
    def fullname(self):
        return self.first + ' ' + self.last

    def email(self):
        return '{}.{}@email.com'.format(self.first, self.last)

初始化一个Person对象

person = Person('zhang', 'san')
print(person.first)
print(person.last)
print(person.fullname)
print(person.email())

person.last = 'si'
print(person.first)
print(person.last)
print(person.fullname)
print(person.email())

四、setter方法-什么时候使用它并且如何写一个setter方法
现在你可以像调用属性一样,来使用person.fullname 方法。
但是另一个问题出现了,有时候我想直接更改fullname,并且更改fullname 的同时,我希望我的first 和 last 可以跟着一起变。
但是当我们尝试设置fullname时,却报错了

class Person():
    def __init__(self, first_name, last_name):
        self.first = first_name
        self.last = last_name

    @property
    def fullname(self):
        return self.first + ' ' + self.last

    def email(self):
        return '{}.{}@email.com'.format(self.first, self.last)


person = Person('zhang', 'san')
person.fullname = 'zhang wu'

在这里插入图片描述

那现在我们如何解决这个问题呢?
我们可以定义一个setter 方法,每当为这个属性设置值时都用被调用
在setter 方法中,当fullname 被修改后,对应的变量也会随着改变
当你使用setter 方法时,你需要遵循以下规则:
● setter 方法需要和@property 修饰的方法具有相同的名字
● 它会将用户传给property的值,作为参数
● 最后你需要在方法定义上添加@{methodname}.setter 装饰器
当你添加@{methodname}.setter 去装饰一个方法时,这个方法就会在(本例中为fullname)属性被赋值时所调用。比如:

class Person():
    def __init__(self, first_name, last_name):
        self.first = first_name
        self.last = last_name

    @property
    def fullname(self):
        return self.first + ' ' + self.last

    @fullname.setter
    def fullname(self, name):
        first_name, last_name = name.split()
        self.first = first_name
        self.last = last_name

    def email(self):
        return '{}.{}@email.com'.format(self.first, self.last)


person = Person('zhang', 'san')
print(person.fullname)
print(person.last)
print(person.first)

person.fullname = 'li si'
print(person.fullname)
print(person.last)
print(person.first)

结果为:
在这里插入图片描述

我们发现,当我们给fullname 一个新值的时候,last 和first 也会随之改变。现在我们的Person 类就可以自动的更新属性,当其中属性变化时。
五、deleter方法
和setter 方法类似,当我们需要删除一个属性时,我们会使用deleter 方法。
你可以像定义setter 方法一样来定义一个setter 方法,使用相同的方法名,并在方法上添加@{methodname}.deleter 装饰器 。

class Person():
    def __init__(self, first_name, last_name):
        self.first = first_name
        self.last = last_name

    @property
    def fullname(self):
        return self.first + ' ' + self.last

    @fullname.setter
    def fullname(self, name):
        first_name, last_name = name.split()
        self.first = first_name
        self.last = last_name

    @fullname.deleter
    def fullname(self):
        self.first = None
        self.last = None

    def email(self):
        return '{}.{}@email.com'.format(self.first, self.last)


person = Person('zhang', 'san')
print(person.fullname)
print(person.last)
print(person.first)

del person.fullname

print(person.last)
print(person.first)

输出结果:
在这里插入图片描述

看上面的输出结果,我们不难发现,当删除fullname 后,first 和 last 都被设置为空了
六、总结

  1. 什么时候使用@property 装饰器呢?
    当一个B属性的值,是通过另一个A属性得来的。并且这个B属性会随着初始A属性得值得改变而更新
  2. 如何创建一个@property
    我们通过在方法定义上面添加@property 来使一个方法可以像调用属性那样调用
  3. 我们什么时候对具有property特性得方法,添加setter ?
    当设置B属性的值时,并且你想同时更新A属性,这个就可以通过添加setter 来实现
  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值