Python 中的@property装饰器
@property是 python 语言中内置的装饰器,用于使类中的 getters 和 setters 等函数表现为类属性。
为了更好地理解这个概念,让我们举个例子。
下面我们有一个类Student,它有 3 个属性,即fname、lname和fullname,其中全称是前两个属性的串联。
我们还有一个功能,email()功能,使用学生的名字和姓氏为其生成一个电子邮件地址。
class Student:
def __init__(self, fname, lname):
self.fname = fname
self.lname = lname
self.fullname = self.fname +' '+ self.lname
# generate email using first and last name
def email(self):
return '{}.{}@studytonight.com'.format(self.fname, self.lname)
现在让我们创建几个对象并调用函数email(),这样做可以尝试一些事情,
# student s1
s1 = Student('Tony', 'Stark')
print('Fullname of s1 is ', s1.fullname)
print('And email address = ', s1.email())
# now updating the s1 object's first name
s1.first = 'Steve'
print('Fullname of s1 is ', s1.fullname)
print('And email address = ', s1.email())
s1 的全名是托尼·斯塔克,电子邮件地址= Tony.Stark@studytonight.com
现在参考上面的代码,在类Student中, fname (名字)和 lname (姓氏)是简单属性(不从任何其他属性派生出来),而全称和email()是派生属性。
这里全称被声明为变量,email被声明为函数。
现在进入输出,我们可以看到,对于学生来说,当名字改变时,电子邮件会自动改变,但全名不会改变,因为email()是一个函数,当我们希望电子邮件被返回时调用,而fullname是在对象初始化时设置的。
如果你想解决全称的问题,可以通过类似于电子邮件的功能来获得全称。但是,这将导致在所有使用了Student类的 python 文件中更改对全名的所有访问的开销。
此外,创建函数不是解决这个问题的 pythonic 方式。但那是什么呢?
使用@property装饰器
现在我们将使用上面程序中的@property通过为全名创建一个 getter 函数来解决全名(我们在上面看到的)的问题,这将允许它被用作一个简单的变量,并且将总是返回全名属性的更新值。
让我们看看如何做到这一点,
class Student:
def __init__(self, fname, lname):
self.fname = fname
self.lname = lname
@property
def fullname(self):
return self.fname +' '+ self.lname
# generate email using first and last name
def email(self):
return '{}.{}@studytonight.com'.format(self.fname, self.lname)
s1 = Student('Tony', 'Stark')
print('Fullname of s1 is ', s1.fullname)
print('And email address = ', s1.email())
# now updating the s1 object's first name
s1.first = 'Steve'
print('Fullname of s1 is ', s1.fullname)
print('And email address = ', s1.email())
Output:-
s1 的全名是托尼·斯塔克,电子邮件地址= Tony.Stark@studytonight.com
在上例中,@property装饰器用于名为fullname()的函数。现在,这个函数将作为一个全名属性工作,也可以作为一个 getter 工作,因为它附带了@property装饰器。
用@property装饰器定义setter和deleter方法
类似于 getter 方法(我们在前面的例子中已经定义过),我们也可以为 Python 中使用@property的任何属性定义 setter 和 deleter 方法。
设置器方法将设置属性的值,删除器方法将从内存中删除属性。
让我们为我们的全名属性实现一个 setter 和 deleter 方法。对于定义设置器和删除器方法,对于在其获取器方法上设置了@property装饰器的属性,我们使用一种特殊的语法,其中我们将@ATTRIBUTE_NAME.setter和@ATTRIBUTE_NAME.deleter装饰器放在与 ATTRIBUTE_NAME 同名的函数上。这在下面的示例中显示,
class Student:
def __init__(self, fname, lname):
self.fname = fname
self.lname = lname
@property
def fullname(self):
return self.fname +' '+ self.lname
#setter for the fullname
@fullname.setter
def fullname(self, name):
# split the name from space
fname, lname = name.split(" ")
self.first = fname
self.last = lname
#deleter for fullname
@fullname.deleter
def fullname(self):
self.first = None
self.last = None
print('Deleted the fullname')
# generate email using first and last name
def email(self):
return '{}.{}@studytonight.com'.format(self.fname, self.lname)
s1 = Student('Tony', 'Stark')
print('Fullname of s1 is ', s1.fullname)
print('And email address = ', s1.email())
# now updating the s1 object's first name
s1.first = 'Steve'
print('Fullname of s1 is ', s1.fullname)
print('And email address = ', s1.email())
#setting new value of fullname
s1.fullname = 'Berry Banner'
print('New Fullname of s1 is ', s1.fullname)
#deleting the fullname
del s1.fullname
s1 的全名是托尼·斯塔克和电子邮件地址= Tony.Stark@studytonight.com S1 的全名是史蒂夫·斯塔克和电子邮件地址= Steve.Stark@studytonight.com S1 的新全名是贝里·班纳删除了全名。
在上面的例子中,我们已经使用@property装饰器成功地创建了 getter 、 setter 和 deleter 。
创建 setter 和 deleter 的简单语法是:
@attribute_name.(setter/getter/deleter)
property()功能
不使用@property装饰器,我们可以使用 python 中的property()函数在 python 中创建 getters、setters 和 deleters。
语法: property(fget, fset, fdel, doc)
其中参数表示:
fget():用于获取属性值
fset():用于设置属性的值
fdel() :用于删除属性值
doc():包含属性文档(docstring)的字符串
返回:从给定的 getter、setter 和 deleter 返回一个属性属性。
下面是一个例子,展示了对相同的Student类使用property()函数,该类具有定义为 getter、setter 和 deleter 的相同函数。
class Student:
def __init__(self, fname, lname):
self.fname = fname
self.lname = lname
self.fullname = fname+' '+lname
def fullname_getter(self):
return self.fname +' '+ self.lname
def fullname_setter(self,name):
firstname, lastname = name.split()
self.fname = firstname
self.lname = lastname
def fullname_deleter(self):
self.fname = None
self.lname = None
print('Deleted the fullname.')
def email(self):
return '{}.{}@email.com'.format(self.fname, self.lname)
fullname = property()
fullname = fullname.getter(fullname_getter)
fullname = fullname.setter(fullname_setter)
fullname = fullname.deleter(fullname_deleter)
# this can be done in a single line too
# fullname = property(fullname_getter, fullname_setter, fullname_deleter)
s1 = Student('Tony', 'Stark')
print('Fullname of s1 is ', s1.fullname)
print('And email address = ', s1.email())
# now updating the s1 object's first name
s1.first = 'Steve'
print('Fullname of s1 is ', s1.fullname)
print('And email address = ', s1.email())
#setting new value of fullname
s1.fullname = 'Berry Banner'
print('New Fullname of s1 is ', s1.fullname)
#deleting the fullname
del s1.fullname
s1 的全名是托尼·斯塔克和电子邮件地址= Tony.Stark@studytonight.com S1 的全名是史蒂夫·斯塔克和电子邮件地址= Steve.Stark@studytonight.com S1 的新全名是贝里·班纳删除了全名。
在这个例子中,我们可以使用property()函数,并使用上面描述的语法或在多个代码行中一次性指定所有 getter、setter 和 deleter 函数作为参数。