Python 中的@property装饰器

原文:https://www.studytonight.com/python/property-in-python

@property是 python 语言中内置的装饰器,用于使类中的 getters 和 setters 等函数表现为类属性。

为了更好地理解这个概念,让我们举个例子。

下面我们有一个类Student,它有 3 个属性,即fnamelnamefullname,其中全称是前两个属性的串联。

我们还有一个功能,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装饰器定义setterdeleter方法

类似于 getter 方法(我们在前面的例子中已经定义过),我们也可以为 Python 中使用@property的任何属性定义 setterdeleter 方法。

设置器方法将设置属性的值,删除器方法将从内存中删除属性。

让我们为我们的全名属性实现一个 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装饰器成功地创建了 gettersetterdeleter

创建 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 函数作为参数。