Python的property属性详细讲解


Posted in Python onApril 11, 2022

前言

Python 动态属性的概念可能会被面试问到,在项目当中也非常实用,但是在一般的编程教程中不会提到,可以进修一下。

先看一个简单的例子。创建一个 Student 类,我希望通过实例来获取每个学生的一些情况,包括名字,成绩等。成绩只有等到考试结束以后才会有,所以实例化的时候不会给它赋值。

class Student:
    def __init__(self, name):
        self.name = name
        self.score = None

mike = Student('mike')

考试完以后,准备给 mike 打分:

mike.score = 999

在这里,老师一不小心多打了个 9 ,通常来说打分都是 100 分值,999 是一个非法数据,不应该赋值成功。学生一多,老师打分出现手误的情况肯定会越来越多,所以我们必须想办法修改程序,限制 score 的值必须在 0-100 分。

限制值

我们定义一个方法,如果输入的不是 0-100 的整数,就让程序报错,数据合法,我们就把 score 属性修改成功。

def set_score(self, new_score):
    if not isinstance(new_score, int):
        raise ValueError('score must be int')

    if 0 <= new_score <= 100:
        self.score = new_score
        return self.score
    else:
        raise ValueError('score invalid')

这样我们每次需要获取成绩的时候使用 self.score 获取,修改成绩的时候调用函数来修改:

mike.set_score(999)

调用以后会报错,因为 999 是非法数据。注意,这个时候我使用 self.score 还是可以进行设置,而且不报错:

self.score = 999

这显然是不行的。所以我们要提供一种机制,把 score 变成私有属性,不能让外部访问。很遗憾,python 的私有属性是伪私有。通常我们把 _ 开头的属性叫私有属性,但是这只是一种协议和规定,你看到下划线开头的属性,不要去访问了。你硬要访问,是可以的,python 并不会禁止。

使用 @property 的方式代替。

上面的方法虽然实现了功能,但是改变了属性的使用方式。平常是这样使用的:

# 获取属性
a = mike.score
# 设置属性
mike.score = 99

@property
def score(self):
    return self._score

@score.setter
def score(self, new_score):
    if not isinstance(new_score, int):
        raise ValueError('score must be int')

        if 0 <= new_score <= 100:
            self._score = new_score
            return self._score
        else:
            raise ValueError('score invalid')

动态属性的好处

  • 统一了调用方式。self.score = 99 的方式,而不是函数调用的方式。
  • _score 我们就不直接去使用了。你要用也可以,不建议。
  • 如果我们一个属性只可以读,把 setter 部分注释掉就可以了。

现在我们来完善这个类,添加 birth 属性和年龄属性:

from datetime import datetime

class Student:
    def __init__(self, name, birth=1920):
        self.name = name
        self._score = None
        self.birth = birth
        self.age = datetime.now().year - self.birth

mike = Student('mike')
print(mike.birth)
print(mike.age)
  • birth 和 age 这两个是可以根据一个求出另外一个的。存在数据冗余问题。

  • age 属性这样是有问题的。mike 初始化的时候,age 已经被求出来了,如果我在下一年再去访问 age 属性,那他就是个错误的值。可以通过把 age 设成现在的秒数来验证:

    self.age = datetime.now().second
    
    mike = Student('mike')
    time.sleep(5)
    print(mike.age)
    print(datetime.now().second)

动态显示

@property
def age(self):
    return datetime.now().year - self.birth

注意,这里不要去设置 @age.setter ,因为他是动态变化的,你修改了会造成数据不一致,它只能作为一个只读属性。

@property 作用和应用场景:

  • @property 优化了属性读取和设置的可读性
  • 需要限制属性的特征;
  • 只读属性。如果属性只可以读,不可以写,用起来很方便。
  • 这个属性根据一个变化的环境动态改变。

附:用property代替getter和setter方法

>>>class Watermelon():
       def __init__(self,price):
           self._price = price                  #私有属性,外部无法修改和访问

       def get_price(self):
           return self._price

       def set_price(self,new_price):
           if new_price > 0:
               self._price = new_price
           else:
               raise 'error:价格必须大于零'

用property代替getter和setter

>>>class Watermelon():
       def __init__(self,price):
           self._price = price

       @property                          #使用@property装饰price方法
       def price(self):
           return self._price

       @price.setter                      #使用@property装饰方法,当对price赋值时,调用装饰方法
       def price(self,new_price):
           if new_price > 0:
               self._price = new_price
           else:
               raise 'error:价格必须大于零'
 
>>> watermelon = Watermelon(4)
>>> 
>>> watermelon.price
4
>>> 
>>> watermelon.price = 7
>>> 
>>> watermelon.price
7
Python 相关文章推荐
Python程序中使用SQLAlchemy时出现乱码的解决方案
Apr 24 Python
Python循环语句中else的用法总结
Sep 11 Python
Python使用迭代器捕获Generator返回值的方法
Apr 05 Python
简单了解什么是神经网络
Dec 23 Python
python寻找list中最大值、最小值并返回其所在位置的方法
Jun 27 Python
Python实现查找字符串数组最长公共前缀示例
Mar 27 Python
不归路系列:Python入门之旅-一定要注意缩进!!!(推荐)
Apr 16 Python
Python爬取网页信息的示例
Sep 24 Python
Python threading模块condition原理及运行流程详解
Oct 05 Python
Scrapy-Redis之RedisSpider与RedisCrawlSpider详解
Nov 18 Python
python-地图可视化组件folium的操作
Dec 14 Python
python中xlutils库用法浅析
Dec 29 Python
OpenCV项目实践之停车场车位实时检测
Python进程池与进程锁之语法学习
Python进程间的通信之语法学习
Python+Matplotlib图像上指定坐标的位置添加文本标签与注释
浅析Python OpenCV三种滤镜效果
实战Python爬虫爬取酷我音乐
用PYTHON去计算88键钢琴的琴键频率和音高
You might like
索尼SONY SRF-S83/84电路分析和打磨
2021/03/02 无线电
PHP新手上路(六)
2006/10/09 PHP
PHP+Ajax异步通讯实现用户名邮箱验证是否已注册( 2种方法实现)
2011/12/28 PHP
PHP使用CURL获取302跳转后的地址实例
2014/05/04 PHP
基于jquery的滑动样例代码
2010/11/20 Javascript
jquery判断RadioButtonList和RadioButton中是否有选中项示例
2013/09/29 Javascript
关于Javascript作用域链的八点总结
2013/12/06 Javascript
详谈jQuery中的this和$(this)
2014/11/13 Javascript
原生javascript实现隔行换色
2015/01/04 Javascript
JS或jQuery获取ASP.NET服务器控件ID的方法
2015/06/08 Javascript
jQuery手机拨号界面特效代码分享
2015/08/27 Javascript
node.js require() 源码解读
2015/12/13 Javascript
对angularjs框架下controller间的传值方法详解
2018/10/08 Javascript
[38:51]2014 DOTA2国际邀请赛中国区预选赛 Orenda VS LGD-CDEC
2014/05/22 DOTA
Python读取sqlite数据库文件的方法分析
2017/08/07 Python
python使用opencv读取图片的实例
2017/08/17 Python
详解Python3.6安装psutil模块和功能简介
2018/05/30 Python
Python实现将数据写入netCDF4中的方法示例
2018/08/30 Python
python常用数据重复项处理方法
2019/11/22 Python
Django 解决由save方法引发的错误
2020/05/21 Python
为你的html5网页添加音效示例
2014/04/03 HTML / CSS
IE9对HTML5中部分属性不支持的原因分析
2014/10/15 HTML / CSS
俄罗斯优惠券网站:BIGLION
2017/05/21 全球购物
欧缇丽加拿大官方网站:Caudalie加拿大
2019/07/18 全球购物
Jacadi Paris英国官网:法国童装品牌
2019/08/09 全球购物
英国奢侈品在线精品店:Hervia
2020/09/03 全球购物
介绍一下linux文件系统分配策略
2013/02/25 面试题
应届专科生个人的自我评价
2014/01/05 职场文书
入党积极分子介绍信
2014/01/17 职场文书
师范生自荐信模板
2014/05/28 职场文书
读群众路线的心得体会
2014/09/03 职场文书
软件测试专业推荐信
2014/09/18 职场文书
医院党的群众路线教育实践活动学习心得体会
2014/10/30 职场文书
民主生活会主持词
2015/07/01 职场文书
2016孝老爱亲模范事迹材料
2016/02/26 职场文书
Netty结合Protobuf进行编解码的方法
2021/06/26 Java/Android