Python学习之-Property详解

前言:

在Python中,property 是一种内置的装饰器,它可以将类的方法转换为属性,让你在不改变类接口的情况下添加额外的逻辑,如输入值的验证、取值的计算等。property 可以作为一种方式让你的类接口保持清晰且易于使用。
property 装饰器最常见的应用场景是将类的属性封装起来,提供getter 和 setter 方法。这种方式的原因是,你可以对属性赋值或者取值的代码进行控制,而不是直接暴露属性。
property 通常会按照下面这样的模式使用:
@property 装饰一个方法,定义属性名,该方法为属性的 “getter” 方法。
@<property_name>.setter 装饰一个方法,将其定义为同名属性的 “setter” 方法。
@<property_name>.deleter 装饰一个方法,将其定义为同名属性的 “deleter” 方法。

1 应用场景:

1.1 数据封装与保护

#!/usr/bin/env python
# coding=utf-8
"""
# @Time    : 2024/4/12 23:00
# @Author  : Summer
# @File    : property_test.py
# @describe:
"""class BankAccount:def __init__(self, initial_balance=0.0):self._balance = initial_balance  # 初始化时将_balance设为初识余额@propertydef balance(self):"""获取账户余额。"""return self._balance@balance.setterdef balance(self, value):"""设置账户余额,拒绝直接设置。"""raise ValueError("Cannot directly set balance; please use deposit() or withdraw() methods.")def deposit(self, amount):"""存款方法,只有金额是正数时才接受该交易。"""if amount <= 0:raise ValueError("Deposit amount must be positive.")self._balance += amountdef withdraw(self, amount):"""取款方法,只有余额充足且金额是正数时才接受该交易。"""if amount <= 0:raise ValueError("Withdrawal amount must be positive.")if amount > self._balance:raise ValueError("Insufficient balance.")self._balance -= amount# 使用
account = BankAccount(1000)   # 初始余额为1000
print(account.balance)        # 输出余额account.deposit(500)          # 存款500
print(account.balance)        # 输出新余额try:account.balance = 1500    # 尝试直接设置余额,将引发异常
except ValueError as e:print(e)account.withdraw(200)         # 取款200
print(account.balance)        # 输出新余额try:account.withdraw(2000)    # 尝试取款超过余额的金额,将引发异常
except ValueError as e:print(e)

在这个例子中,BankAccount类有一个私有属性_balance,这意味着我们不想让外部直接修改它。我们提供了一个balance属性的getter来获取余额,但我们故意没有提供setter去允许直接修改余额,反而提供了deposit和withdraw方法来合理地修改余额。
当尝试直接设置account.balance时,由于没有适当的setter,property装饰器会引发一个ValueError异常。而当通过deposit和withdraw方法修改余额时,可以在方法内部加入一定的验证逻辑,比如只接受正数金额,以及在取款时确保余额充足等。
通过这种方式,我们可以确保账户余额不会被非法修改,并且所有余额的变化都是通过安全的方法进行的。这就是使用property装饰器进行数据封装和保护的一个典型例子。

1.2 属性计算与逻辑处理

#!/usr/bin/env python
# coding=utf-8
"""
# @Time    : 2024/4/12 23:00
# @Author  : Summer
# @File    : property_test.py
# @describe:
"""class Rectangle:def __init__(self, width, height):self.width = widthself.height = height@propertydef area(self):"""计算矩形的面积。"""return self.width * self.height@propertydef perimeter(self):"""计算矩形的周长。"""return 2 * (self.width + self.height)def resize(self, new_width, new_height):"""修改矩形的尺寸,并自动更新计算属性。"""if new_width <= 0 or new_height <= 0:raise ValueError("Width and height must be positive.")self.width = new_widthself.height = new_height# 使用
rectangle = Rectangle(3, 4)
print(rectangle.area)       # 输出面积:12
print(rectangle.perimeter)  # 输出周长:14rectangle.resize(5, 6)
print(rectangle.area)       # 输出新面积:30
print(rectangle.perimeter)  # 输出新周长:22try:rectangle.resize(-3, 6)
except ValueError as e:print(e)  # 尺寸必须为正数,否则抛出异常

在这个例子中,Rectangle类有width和height两个属性,以及两个由这两个属性计算得出的只读属性area和perimeter。area属性返回矩形的面积,perimeter属性返回矩形的周长。这两个属性都没有setter方法,因为它们取决于width和height的值,而不是直接设置的。
此外,如果需要修改矩形的尺寸,我们定义了一个名为resize的方法来同时更新width和height。这时,由于area和perimeter的计算依赖于这两个属性,它们也会自动更新,因此我们无需手动同步这些计算属性。
通过使用property,我们可以将计算和逻辑封装在类内部,使得外部接口简洁并易于使用,同时保持内部数据的一致性。这也使得我们能够在未来改变计算属性的内部实现而不影响调用方的代码。

1.3 高级getter和setter用法

#!/usr/bin/env python
# coding=utf-8
"""
# @Time    : 2024/4/12 23:00
# @Author  : Summer
# @File    : property_test.py
# @describe:
""""""使用@property装饰器来定义属性的getter和setter方法,并使用@name.setter和@price.setter来分别定义name和price属性的setter方法。在setter方法中,我们检查传入的值的类型和值是否满足要求,如果满足要求,则将值赋给对应的属性,否则引发异常。
"""class Product:def __init__(self, name, price):self.name = nameself.price = price@propertydef name(self):return self._name@name.setterdef name(self, value):if not isinstance(value, str):raise TypeError("Name must be a string")if not value.strip():raise ValueError("Name cannot be empty")self._name = value@propertydef price(self):return self._price@price.setterdef price(self, value):if not isinstance(value, (int, float)):raise TypeError("Price must be a number")if value <= 0:raise ValueError("Price must be positive")self._price = round(value, 2)  # 注意:在此处我们将价格四舍五入到两位小数# 使用
product = Product("Coffee", 3.99)
print(product.name)  # 输出商品名称
print(product.price) # 输出商品价格try:product.name = ""  # 尝试设置一个空的商品名称,将引发异常
except ValueError as e:print(e)try:product.price = "Free"  # 尝试设置一个非数字的价格,将引发异常
except TypeError as e:print(e)product.price = 5.98765  # 此时会自动四舍五入价格
print(product.price)

在这个例子中,Product类有两个属性:name和price。每个属性都有一个getter和setter,而setter方法中包含了输入的验证和转换。
对于name属性,setter方法确保传入的值是字符串,并且非空;
对于price属性,setter方法检查值是否是一个正数 (可以是整数或浮点数) 并且将其四舍五入到两位小数。
这些额外的验证确保了:
商品名称不为空且为文本类型。
商品价格总是正数,并且为了表示金钱它总是以两位小数显示。
通过在setter中包含这些逻辑,我们可以确保Product类的实例始终维持在有效和合理的状态。如果尝试为这些属性赋值无效的数据,类会引发异常,阻止这样做,并且可以为异常处理提供更多上下文。这种模式帮助保持数据的完整性,并可以在属性被错误地设置时立即发现问题。

使用property的好处:

property() 函数是 Python 中用于创建可管理属性的重要工具,它可以实现数据封装、访问控制、属性计算等功能。
封装:property允许开发者隐藏(封装)内部实现的细节,提供一个干净的API。内部变量往往以下划线(如_variable或__variable)作为前缀命名,表示它们不应直接访问。
数据验证:通过使用setter方法,开发者可以轻松加入数据验证逻辑,确保类的状态总是有效的。例如,可以检查属性值是否在预期范围内,或者是否是正确的类型。
计算属性:有些属性的值是基于对象的状态计算得到的。使用getter方法,可以轻松地根据其他属性动态生成这些值。这些属性通常被认为是只读属性。
延迟计算和缓存(惰性计算):对于计算成本较高的属性值,可以在首次访问时进行计算并缓存结果,而不是在对象创建时就计算。这样做可以提高性能,尤其是在该属性不一定会被每个对象使用的情况下。
观察者模式:通过使用property装饰器的setter方法,可以在一个属性被修改时触发某些额外的操作,例如日志记录、通知或是其它形式的状态同步。
保持向后兼容性:如果你的类曾经公开了一个属性,并且你想添加一些对其访问控制而不破坏现有代码,那么你可以将它转变为一个用property装饰器实现的方法,这样做不需要修改对这个属性的引用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/811904.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring Boot | SpringBoot 对 SpringMVC的 “整合支持“

目录: SpringMVC 的 “整合支持” ( 引入"Web依赖启动器"&#xff0c;几乎可以在无任何额外的配置的情况下进行"Web开发")1.SpringMVC "自动配置" 介绍 ( 引入Web依赖启动器"后&#xff0c;SpringBoot会自动进行一些“自动配置”&#xff0…

Linux下mysql的彻底卸载

Linux下mysql的彻底卸载 1、查看mysql的安装情况2、删除上图安装的软件3、都删除成功之后&#xff0c;查找相关的mysql的文件4、删除全部文件5、再次执行命令 1、查看mysql的安装情况 rpm -qa | grep -i mysql2、删除上图安装的软件 rpm -ev mysql-community-libs-5.7.27-1.e…

部署Nginx+keepalived+Tomcat集群架构

部署Nginx+keepalived+Tomcat集群架构 集群架构背景Nginx的高可用负载均衡架构Nginx和LVS对比的总结:搭建Nginx+keepalived+Tomcat的高可用负载均衡架构准备条件: 测试服务器: 系统:centos7.6服务器1: 172.16.2.203 (Nginx+keepalived+Tomcat) 服务器2: 172.16.2.206 (N…

[iOS]协议中如何添加属性?

在 Objective-C 中&#xff0c;协议&#xff08;Protocol&#xff09;本身不直接支持存储属性&#xff0c;因为协议的目的是定义一个接口&#xff0c;即一组方法声明&#xff0c;它们可以被任何类实现。协议主要用于声明方法&#xff08;包括required 和 optional 方法&#xf…

【技术支持】禁止html中referer

如果页面中包含了如下 meta 标签&#xff0c;所有从当前页面中发起的请求将不会携带 referer&#xff1a; <meta name"referrer" content"never"> 如果页面中包含了如下 meta 标签&#xff0c;则从当前页面中发起的 http请求将只携带 origin 部分&a…

蓝桥杯 前一晚总结 模板 新手版

《准备实足&#xff0c;冲冲冲 省一》https://www.yuque.com/lenyan-svokd/hi7hp2/hfka297matrtsxy2?singleDoc# 《准备实足&#xff0c;冲冲冲 省一》 #include<bits/stdc.h> // 包含标准库头文件using namespace std; using ll long long; // 定义 long long 数据类…

【opencv】示例-opencv_version.cpp 输出OpenCV的版本和构建配置的示例

#include <opencv2/core/utility.hpp> // 引入OpenCV核心工具库 #include <iostream> // 引入标准输入输出流库// 定义一个包含命令行参数的字符串 static const std::string keys "{ b build | | print complete build info }" // 定义参数b&#xff…

【数据结构】06图

图 1. 定义1.1 无向图和有向图1.2 度、入度和出度1.3 图的若干定义1.4 几种特殊的图 2. 图的存储2.1 邻接矩阵-顺序存储&#xff08;数组&#xff09;2.2 邻接表-顺序存储链式存储&#xff08;数组链表&#xff09;2.3 十字链表-适用于有向图2.4 邻接多重表-适用于无向图 3. 图…

设计模式代码实战-建造者模式

1、问题描述 小明家新开了一家自行车工厂&#xff0c;用于使用自行车配件&#xff08;车架 frame 和车轮 tires &#xff09;进行组装定制不同的自行车&#xff0c;包括山地车和公路车。 山地车使用的是Aluminum Frame&#xff08;铝制车架&#xff09;和 Knobby Tires&#x…

【随笔】Git 高级篇 -- 管理多分支 git rebase(二十二)

&#x1f48c; 所属专栏&#xff1a;【Git】 &#x1f600; 作  者&#xff1a;我是夜阑的狗&#x1f436; &#x1f680; 个人简介&#xff1a;一个正在努力学技术的CV工程师&#xff0c;专注基础和实战分享 &#xff0c;欢迎咨询&#xff01; &#x1f496; 欢迎大…

vue elementUI form组件动态添加el-form-item rules且支持添加自定义校验方法

vue elementUI form组件动态添加el-form-item rules且支持添加自定义校验方法 组件动态添加el-form-item并且动态添加rules的方法可以参考博客&#xff1a;添加自定义校验方法validatePassFun 组件动态添加el-form-item并且动态添加rules的方法可以参考博客&#xff1a; vue e…

PyTorch环境配置问题

为什么深度学习都是用英伟达的显卡&#xff1f; 首先我们需要了解什么是CUDA&#xff1f; CUDA&#xff08;Compute Unified Device Architecture&#xff09;&#xff0c;是显卡厂商 NVIDIA 推出的运算平台。 CUDA就类似于编程语言&#xff0c;开发者和显卡通过CUDA进行交流…

Android网络抓包--Charles

一、Android抓包方式 对Https降级进行抓包&#xff0c;降级成Http使用抓包工具对Https进行抓包 二、常用的抓包工具 wireshark&#xff1a;侧重于TCP、UDP传输层&#xff0c;HTTP/HTTPS也能抓包&#xff0c;但不能解密HTTPS报文。比较复杂fiddler&#xff1a;支持HTTP/HTTPS…

【SpringBoot】mybatis-plus实现增删改查

mapper继承BaseMapper service 继承ServiceImpl 使用方法新增 save,updateById新增和修改方法返回boolean值,或者使用saveOrUpdate方法有id执行修改操作,没有id 执行新增操作 案例 Service public class UserService extends ServiceImpl<UserMapper,User> {// Au…

用于大规模数据集(大于1TB)的并行运算的MapReduce是怎么实现的?

MapReduce 是一种编程模型&#xff0c;用于处理和生成大数据集。MapReduce 分为两个阶段&#xff1a;Map 阶段和 Reduce 阶段。 Map 阶段&#xff1a;在这个阶段&#xff0c;输入数据被拆分成不同的数据块&#xff0c;这些数据块被分发到各个 Map 任务上。每个 Map 任务对输入的…

Golang | Leetcode Golang题解之第24题两两交换链表中的节点

题目&#xff1a; 题解&#xff1a; func swapPairs(head *ListNode) *ListNode {dummyHead : &ListNode{0, head}temp : dummyHeadfor temp.Next ! nil && temp.Next.Next ! nil {node1 : temp.Nextnode2 : temp.Next.Nexttemp.Next node2node1.Next node2.Nex…

数据结构(算法)

总结&#xff0c;建议看EXCEL的《算法》页签&#xff0c;不然感觉有点乱 备注原理/步骤时间复杂度空间复杂度串的应用模式匹配简单/暴力O(mn) KMP  O(mn) 树的应用树哈夫曼树1、带权路径长度WPL 2、外部排序-最佳归并树1、哈夫曼树的度&#xff0c;只有0和m&#xff08;m叉…

react17+antd4 Menu 点击菜单收起其他展开的所有菜单、页面刷新时设置菜单的选中状态和展开状态

菜单栏展开回收、页面刷新时确保菜单状态与当前页面匹配 1.菜单栏展开和回收事件2. 刷新时默认当前选中项样式的处理2.1 刷新页面菜单保持用户之前的选中状态2.2 配置展开项openKeys的初始值 export const asyncRouterMap [{path: /page1,title: page1,icon: HomeOutlined,}, …

Linux上下载部署zentao v15.5及具体的使用

1.先查询一下Linux的操作系统的位数&#xff0c;确保下载的文件位数与os的一致 [rootlocalhost xiaoming]# uname -m x86_64 [rootlocalhost xiaoming]# getconf LONG_BIT 64 2.下载zentao的Linux压缩包 wget https://www.zentao.net/dl/zentao/15.5/ZenTaoPMS.15.5.zbox…

vue创建一个项目

要创建一个Vue项目&#xff0c;你可以使用Vue CLI&#xff08;命令行界面&#xff09;这个官方工具。以下是使用Vue CLI创建一个新项目的步骤&#xff1a; 步骤 1: 安装 Node.js 和 npm 首先&#xff0c;确保你的计算机上已经安装了Node.js和npm&#xff08;Node.js的包管理器…