property的使用

本质上说,本文提到的 @property 和上一篇文章提到的 @classmethod、@staticmethod 都是装饰器,都是对函数定义进行补充使之具有特殊功能。

正文

一、

设想:当我定义了一个用户类:

class User(Model):
    ...
    password = db.Column(db.String(64))
    ...

在上例中,很明显,password 是可以显式调用的属性,这在网站设计中绝不可以出现,会造成用户数据泄露的极大风险。那么,要将其变为私有属性,需要修改如下:

class User(Model):
    ...
    __password = db.Column(db.String(64))

这样,当创建实例变量后,再访问此属性会抛出 AttributeError 异常:

AttributeError: 'User' object has no attribute '__password'

这是一种解决办法,可是,当我们需要获取或者修改这个属性的值时,该怎么办呢?

只能通过为类增加实例方法来实现,方法中还可以加入参数检查的功能:

class User(Model):
    
    def __init__(self, name, score):
        self.__name = name
        self.__score = score

    def get_score(self):
        return self.__score

    def set_score(self, score):
    if 0 <= score <= 100:
        self.__score = score
    else:
        rasie ValueError('bad score')

但上面的方法略显复杂,python 提供了 @property 装饰器,可以轻松实现上述功能。

二、

创建一个只读属性:

class User(object):
    ...
    @property
    def score():
        return __score
    ...

使用 @property 可以将一个方法变为属性,无 @property 时,需要 u.score();使用之后,直接调用 u.score即可。

对于网站设计来说,常采用的做法是:将密码设置为只写属性,存储时,只存储其与其他用户属性生成的散列值(如用户密码+用户邮箱):

class User:
    
    @property
    def password(self):
        raise AttributeError('Password is not accessable.')

    @password.setter
    def password(self, password):
        self.password_hash = generate_password_hash(password)

当我们设置密码时,就可以使用 u.password = 'xxxx' 了。

在这个过程中,@property 又产生了另一个装饰器 @password.setter 将 password 方法变成属性赋值。

在 Python 的官方文档中,除了 gettersetter 外,还有一个 deleter

class User:
    
    @property
    def score():
        return __score

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

顾名思义,这个派生出来的装饰器可以用来删除用户属性。

三、

在官方文档中,@property 装饰器还被这样使用:

class C:
    def __init__(self):
        self._x = None

    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.")

这样,u 是 C 的实例,当访问 u.x 时,将调用 u.getx() 方法。

u.x = value 将调用 u.setx(value) 方法。

del u.x 将调用 u.delx() 方法。

四、

@property 能将方法变成属性,又可在方法中加入参数检查的功能,这将它可普通属性区别开来,同时比定义额外的 get/set 方法清晰明了。将方法变成属性,这是 @property 的精髓。

参考链接


  • 使用@property,by 廖雪峰

你可能感兴趣的:(property的使用)