python装饰器的使用以及私有化

@classmethod

  • 功能:用于定义类方法。类方法的第一个参数是类本身(通常约定为cls),而不是类的实例。这使得类方法可以在不创建类实例的情况下被调用,并且可以访问和修改类级别的属性和方法。
  • 使用场景示例
class MyClass:count = 0@classmethoddef increment_count(cls):cls.count += 1MyClass.increment_count()
print(MyClass.count)  

@staticmethod

  • 功能:用于定义静态方法。静态方法不需要传递类或实例的引用作为第一个参数,它与普通函数类似,但在逻辑上属于类的范围。静态方法主要用于将与类相关的实用函数组织在类的命名空间中,提高代码的可读性和可维护性,同时避免在全局命名空间中定义过多的函数。
  • 使用场景示例
class MathUtils:@staticmethoddef add(x, y):return x + yresult = MathUtils.add(3, 5)
print(result)  

@property

  • 功能:将一个方法转换为一个属性,使得可以像访问属性一样调用该方法,而不需要显式地使用括号。这提供了一种更简洁、自然的方式来访问类的属性,同时可以在获取属性值或设置属性值时添加额外的逻辑,例如数据验证、计算属性值等。
  • 使用场景示例
class Circle:def __init__(self, radius):self._radius = radius@propertydef radius(self):return self._radius@radius.setterdef radius(self, value):if value >= 0:self._radius = valueelse:raise ValueError("Radius cannot be negative.")c = Circle(5)
print(c.radius)  
c.radius = 7
print(c.radius)  

@abstractmethod(在abc模块中)

  • 功能:用于定义抽象方法,抽象方法是在抽象类中声明但不实现的方法,要求子类必须实现这些方法。这有助于实现抽象类和接口的概念,强制子类遵循特定的接口规范,提供统一的接口定义,增强代码的规范性和可扩展性。
  • 使用场景示例
from abc import ABC, abstractmethodclass Shape(ABC):@abstractmethoddef area(self):passclass Rectangle(Shape):def __init__(self, width, height):self.width = widthself.height = heightdef area(self):return self.width * self.heightr = Rectangle(3, 4)
print(r.area())  

@property

@property装饰器在Python中有以下重要作用:

1. 将方法转换为属性

  • 允许你像访问普通属性一样调用方法,而无需显式地使用括号。这使得代码在语法上更加简洁和自然,提高了代码的可读性。例如,对于一个表示矩形的类,你可以使用@property装饰器来定义获取矩形面积的方法,使其看起来像一个普通属性:
class Rectangle:def __init__(self, width, height):self.width = widthself.height = height@propertydef area(self):return self.width * self.heightr = Rectangle(3, 4)
print(r.area)  # 直接访问area属性,而不是r.area()

2. 提供属性访问控制

  • 隐藏实现细节:可以隐藏属性的实际存储方式和计算过程,只对外暴露属性的访问接口。例如,上述Rectangle类中,area属性的计算逻辑被封装在方法内部,外部使用者不需要了解其计算细节,只关心获取面积的值。
  • 增加额外逻辑:在获取属性值时,可以添加额外的逻辑处理,比如数据验证、日志记录、动态计算等。例如,在一个表示温度的类中,可以使用@property装饰器来获取摄氏温度,并在内部将其转换为华氏温度:
class Temperature:def __init__(self, celsius):self._celsius = celsius@propertydef celsius(self):return self._celsius@propertydef fahrenheit(self):return (self._celsius * 9/5) + 32t = Temperature(25)
print(t.celsius)  
print(t.fahrenheit)  

3. 支持属性的读写控制

  • 只读属性:通过只定义@property装饰的获取方法(getter),可以创建只读属性,防止外部对属性进行意外修改。例如,在一个表示学生信息的类中,学生的学号通常是只读的:
class Student:def __init__(self, student_id, name):self._student_id = student_idself.name = name@propertydef student_id(self):return self._student_ids = Student(12345, "Alice")
print(s.student_id)
# s.student_id = 67890  # 这将引发错误,因为student_id是只读属性
  • 读写属性:除了获取方法,还可以通过定义属性的设置方法(setter)来实现读写属性。在设置属性值时,可以进行数据验证等操作,确保属性值的合法性。例如,在上述Rectangle类中,如果要允许修改矩形的宽度和高度,可以添加相应的设置方法:
class Rectangle:def __init__(self, width, height):self._width = widthself._height = height@propertydef width(self):return self._width@width.setterdef width(self, value):if value > 0:self._width = valueelse:raise ValueError("Width must be positive.")@propertydef height(self):return self._height@height.setterdef height(self, value):if value > 0:self._height = valueelse:raise ValueError("Height must be positive.")r = Rectangle(3, 4)
print(r.width, r.height)
r.width = 5
r.height = 6
print(r.width, r.height)

4. 与其他特性协同工作

  • 可以与继承、描述符等Python特性结合使用,进一步扩展其功能。例如,在子类中可以重写父类中使用@property装饰的属性,以满足子类的特定需求;或者可以自定义描述符类,与@property一起实现更复杂的属性访问控制逻辑。

5. 提高代码的可维护性和可扩展性

  • 当需要修改属性的实现方式或添加额外功能时,只需要在@property装饰的方法内部进行修改,而不需要在所有使用该属性的地方进行更改。这符合面向对象编程的开闭原则(对扩展开放,对修改封闭),使得代码更容易维护和扩展。例如,如果要在上述Temperature类中更改摄氏温度和华氏温度之间的转换公式,只需要修改fahrenheit属性的获取方法即可,而不会影响到其他使用该类的代码。

python私有化在底层是如何完成的

在Python中,私有化是通过一种命名约定来实现的,而不是真正意义上的访问限制机制(如其他一些编程语言中的private关键字)。其底层原理主要涉及以下方面:

1. 名称改写(Name Mangling)

  • 当在类中定义一个以双下划线__开头(但不以双下划线结尾)的属性或方法时,Python解释器会自动将其名称进行改写。改写规则是在名称前面加上_类名,例如,对于类MyClass中的属性__private_attr,其实际存储的名称会变为_MyClass__private_attr
  • 这种名称改写的目的是为了避免在子类或外部代码中意外访问到这些被视为“私有”的成员。虽然从技术上讲,仍然可以通过改写后的名称访问这些成员,但这并不是一种推荐的做法,并且这种间接访问方式可以提醒开发者该成员被设计为内部使用。

2. 访问控制的实现方式

  • 类内部访问:在类的方法中,可以直接使用原始的私有属性名称(如__private_attr)来访问和修改这些属性,因为Python解释器在类定义时已经知道了这种命名约定,并且在编译字节码时会进行相应的处理,使得类内部的代码能够正确地访问这些“私有”成员。
  • 子类访问:在子类中,如果试图使用原始的私有属性名称(如__private_attr)来访问父类的私有属性,将会引发AttributeError异常,因为子类并不知道父类中私有属性的实际名称(已经被改写)。然而,如果子类知道名称改写的规则,也可以通过_父类名__private_attr的方式来访问父类的私有属性,但这违背了封装的原则,不应该被常规使用。
  • 外部访问:从类的外部直接访问以双下划线开头的私有属性(如obj.__private_attr,其中obj是类的实例)同样会引发AttributeError异常,因为外部代码不知道名称已经被改写。

3. 为什么使用这种方式

  • 灵活性与简洁性:Python的设计哲学强调简洁性和灵活性,这种基于命名约定的私有化方式相对简单,避免了引入复杂的访问控制语法(如在一些其他编程语言中)。同时,它给予开发者一定的自由度,在需要时可以绕过这种“伪私有”限制(虽然不鼓励这样做),例如在进行调试或在某些特定的框架内部实现中可能会需要这种灵活性。
  • 历史和文化原因:Python在发展过程中形成了这种约定俗成的编程规范,社区广泛接受并遵循这种方式来表示私有成员。这有助于提高代码的可读性,使其他开发者能够快速理解代码中哪些成员是被设计为内部使用的,从而遵循良好的编程习惯,减少不必要的外部依赖和干扰。

4. 示例

class MyClass:def __init__(self):self.__private_attr = 42def get_private_attr(self):return self.__private_attrdef set_private_attr(self, value):self.__private_attr = valueobj = MyClass()
print(obj.get_private_attr())  
# 以下访问方式将引发AttributeError异常
# print(obj.__private_attr)  
# obj.__private_attr = 100  
obj.set_private_attr(100)
print(obj.get_private_attr())  

在上述代码中,__private_attr被视为私有属性,通过类内部的get_private_attrset_private_attr方法来间接访问和修改。从外部直接访问__private_attr会失败,体现了Python中私有化的基本行为。需要注意的是,虽然Python的私有化机制不是绝对严格的访问限制,但在正常的编程实践中,应该尊重这种约定,以确保代码的良好结构和可维护性。

私有化的赋值和取值

在Python中,私有化属性(通过双下划线开头命名约定实现)的赋值和取值通常通过定义公有的方法来间接进行,这遵循了面向对象编程中的封装原则,以控制对内部数据的访问。以下是具体的方式:

1. 取值(访问私有属性)

  • 定义getter方法:在类中定义一个以@property装饰器修饰的方法,用于获取私有属性的值。这个方法的名称通常与私有属性的名称相关,以便在代码中直观地表示其功能。例如,如果有一个私有属性__private_value,可以定义如下的getter方法:
class MyClass:def __init__(self):self.__private_value = 42@propertydef private_value(self):return self.__private_value
  • 使用getter方法:在类的外部或其他方法中,可以像访问普通属性一样使用这个getter方法来获取私有属性的值:
obj = MyClass()
print(obj.private_value)  

2. 赋值(修改私有属性)

  • 定义setter方法:除了getter方法,还需要定义一个setter方法来允许对私有属性进行赋值操作。setter方法的名称与getter方法的名称相同,但需要使用@属性名.setter装饰器进行修饰(这里的属性名是getter方法的名称去掉@property装饰器后的部分)。在setter方法中,可以添加一些逻辑来验证或处理赋值操作,例如数据类型检查、范围限制等。例如,对于上述的__private_value属性,可以定义如下的setter方法:
class MyClass:def __init__(self):self.__private_value = 42@propertydef private_value(self):return self.__private_value@private_value.setterdef private_value(self, value):if isinstance(value, int):self.__private_value = valueelse:print("Error: 只能赋值整数类型。")
  • 使用setter方法:在类的外部或其他方法中,可以通过赋值语句来调用setter方法,从而修改私有属性的值:
obj = MyClass()
obj.private_value = 100  
print(obj.private_value)  
obj.private_value = "hello"  

以下是使用@property装饰器实现私有化属性的getset方法的详细步骤及示例:

1. 定义类和私有属性

首先,定义一个类,并在类中定义一个私有属性(以双下划线__开头)。例如:

class MyClass:def __init__(self):self.__private_value = 0

2. 定义getter方法(使用@property装饰器)

使用@property装饰器定义一个方法,用于获取私有属性的值。方法的名称通常与私有属性的名称相关,但去掉双下划线前缀。在这个方法中,直接返回私有属性的值。例如:

class MyClass:def __init__(self):self.__private_value = 0@propertydef private_value(self):return self.__private_value

3. 定义setter方法(使用@属性名.setter装饰器)

定义一个与getter方法同名的方法,但在方法上使用@属性名.setter装饰器(这里的属性名是getter方法的名称去掉@property装饰器后的部分,即private_value)。在setter方法中,接收一个参数用于赋值,并可以添加一些逻辑来验证或处理赋值操作,然后将值赋给私有属性。例如:

class MyClass:def __init__(self):self.__private_value = 0@propertydef private_value(self):return self.__private_value@private_value.setterdef private_value(self, value):if isinstance(value, int):self.__private_value = valueelse:print("Error: 只能赋值整数类型。")

如何使用@property实现对于私有化的get和set

使用示例

现在可以创建类的实例,并通过属性的方式来获取和修改私有属性的值,就像访问普通属性一样:

obj = MyClass()
print(obj.private_value)  # 调用getter方法获取私有属性的值obj.private_value = 10  # 调用setter方法修改私有属性的值
print(obj.private_value)obj.private_value = "hello"  # 尝试赋值非整数类型,会触发setter方法中的验证逻辑

总结

  • 通过@property装饰器和其对应的setter装饰器,可以为私有属性提供一种安全、可控的访问方式。这种方式遵循了数据封装的原则,隐藏了属性的内部实现细节,同时允许在获取和设置属性值时添加额外的逻辑,如数据验证、计算等。
  • 当属性的访问和修改需要更复杂的逻辑处理,或者需要对外部访问进行限制和控制时,使用@property实现getset方法是一种非常有效的方式,有助于提高代码的健壮性和可维护性。

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

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

相关文章

ArcGIS Pro属性表乱码与字段名3个汉字解决方案大总结

01 背景 我们之前在使用ArcGIS出现导出Excel中文乱码及shp添加字段3个字被截断的情况,我们有以下应对策略: 推荐阅读:ArcGIS导出Excel中文乱码及shp添加字段3个字被截断? 那如果我们使用ArGIS Pro出现上述问题,该如何…

图论-代码随想录刷题记录[JAVA]

文章目录 前言Floyd 算法dijkstra(朴素版) 前言 新手小白记录第一次刷代码随想录 1.自用 抽取精简的解题思路 方便复盘 2.代码尽量多加注释 3.记录踩坑 4.边刷边记录,更有成就感! 5.解题思路绝大部分来自代码随想录 Floyd 算法 【…

anzocapital 昂首资本:外汇机器人趋势判断秘籍

再盲目交易而不借助像 anzocapital 昂首资本所了解的外汇机器人趋势判断方法,投资者在外汇市场将面临亏损的风险,anzocapital 昂首资本深知交易策略的重要性,就像外汇机器人确定趋势方向的方法,对投资者有着非凡的意义。 在外汇交…

【划分型DP-约束划分个数】【hard】力扣410. 分割数组的最大值

给定一个非负整数数组 nums 和一个整数 k ,你需要将这个数组分成 k 个非空的连续子数组,使得这 k 个子数组各自和的最大值 最小。 返回分割后最小的和的最大值。 子数组 是数组中连续的部份。 示例 1: 输入:nums [7,2,5,10,8]…

python高级之面向对象编程

一、面向过程与面向对象 面向过程和面向对象都是一种编程方式,只不过再设计上有区别。 1、面向过程pop: 举例:孩子上学 1. 妈妈起床 2. 妈妈洗漱 3. 妈妈做饭 4. 妈妈把孩子叫起来 5. 孩子起床 6. 孩子洗漱 7. 孩子吃饭 8. 妈妈给孩子送学校…

shell脚本(1)

免责声明 学习视频来自B 站up主泷羽sec,如涉及侵权马上删除文章。 笔记的只是方便各位师傅学习知识,以下代码、网站只涉及学习内容,其他的都与本人无关,切莫逾越法律红线,否则后果自负。 Shell脚本 建立一个sh脚本…

《DiffusionDet: Diffusion Model for Object Detection》ICCV2023

摘要 本文提出了一种新的框架DiffusionDet,它将目标检测任务表述为从带噪声的边界框到目标边界框的去噪扩散过程(如图一所示)。在训练阶段,目标边界框逐渐扩散到随机分布,模型学习逆转这一加噪过程。在推理阶段&#…

ISAAC SIM踩坑记录--ROS2相机影像发布

其实这个例子官方和大佬NVIDIA Omniverse和Isaac Sim笔记5:Isaac Sim的ROS接口与相机影像、位姿真值发布/保存都已经有详细介绍了,但是都是基于ROS的,现在最新的已经是ROS2,这里把不同的地方简单记录一下。 搭建一个简单的场景&a…

outlook邮箱关闭垃圾邮件——PowerAutomate自动化任务

微软邮箱反垃圾已经很强大了非常敏感,自家的域名的邮件都能给扔到垃圾邮箱里,但还是在本地增加了一层垃圾邮箱功能,然后垃圾邮箱并没有提示,导致错过很多通知,本身并没有提供关闭的功能,但微软有个Microsof…

「Py」Python基础篇 之 Python都可以做哪些自动化?

✨博客主页何曾参静谧的博客📌文章专栏「Py」Python程序设计📚全部专栏「Win」Windows程序设计「IDE」集成开发环境「UG/NX」BlockUI集合「C/C」C/C程序设计「DSA」数据结构与算法「UG/NX」NX二次开发「QT」QT5程序设计「File」数据文件格式「UG/NX」NX定…

candence: 原理图生成网表时报错:Duplicate Pin name “xxx“

原理图生成网表时报错:Duplicate Pin name “xxx” 这个错误的意思是,原理图中管脚命名重复 解决这个问题的方法: 1、绘制元件的时候不要用相同的管脚名,比如GND等的,就稍加个后缀做区分2、就是将管脚属性修改为 &qu…

Diffusion Policy——斯坦福机器人UMI所用的扩散策略:从原理到其编码实现(含Diff-Control、ControlNet详解)

前言 本文一开始是属于此文《UMI——斯坦福刷盘机器人:从手持夹持器到动作预测Diffusion Policy(含代码解读)》的第三部分,考虑后Diffusion Policy的重要性很高,加之后续还有一系列基于其的改进工作 故独立成本文,且写的过程中 …

计算机网络学习笔记-3.2介质访问控制

文章目录 介质访问控制静态划分信道 动态分配信道轮询访问介质访问控制随机访问介质访问控制ALOHA协议简介ALOHA协议的工作原理 介质访问控制 介质访问控制(MAC,Medium Access Control),质访问控制的目的是确保多个设备能够高效、…

GitCode光引计划有奖征文大赛

一、活动介绍 GitCode平台汇聚了众多杰出的G-Star项目,它们犹如璀璨星辰,用各自的故事和成就,为后来者照亮前行的道路。我们诚邀广大开发者、项目维护者及爱好者,共同撰写并分享项目在GitCode平台上托管的体验,挖掘平…

深入理解接口测试:实用指南与最佳实践5.0(三)

✨博客主页: https://blog.csdn.net/m0_63815035?typeblog 💗《博客内容》:.NET、Java.测试开发、Python、Android、Go、Node、Android前端小程序等相关领域知识 📢博客专栏: https://blog.csdn.net/m0_63815035/cat…

使用electron-egg把vue项目在linux Ubuntu环境下打包并安装运行

electron-egg一个入门简单、跨平台、企业级桌面软件开发框架https://www.kaka996.com/electron-egg 跳转地址 1,使用 git下载代码到本地,如果没有git需要进行安装 # gitee git clone https://gitee.com/dromara/electron-egg.git # github git clone https://github.com/dro…

DAY112代码审计PHP开发框架POP链利用Yii反序列化POP利用链

一、pop1链的跟踪 1、路由关系 2、漏洞触发口unserialize(base64_decode($data)); 2、__destruct(),魔术法方法调用close函数方法 3、未找到利用链,尝试__call魔术方法 4、逆推找call_user_func 函数 第一部分 namespace yii\db; class BatchQueryResu…

Maven 构建项目

Maven 是一个项目管理和构建工具,主要用于 Java 项目。它简化了项目的构建、依赖管理、报告生成、发布等一系列工作。 构建自动化:Maven 提供了一套标准化的构建生命周期,包括编译、测试、打包、部署等步骤,通过简单的命令就可以执…

任务调度中心-XXL-JOB使用详解

目录 详解 调度中心 执行器 原理 快速入门 源码仓库地址 1.初始化数据库 2.配置调度中心 1.解压源码 2.需改配置文件 3.启动调度中心 3.配置执行器 1.引入pom依赖 2.修改配置文件 3.执行器组件配置 4.部署执行器项目 4.开发第一个任务 BEAN模式(类…

ROM修改进阶教程------安卓14 安卓15去除app签名验证的几种操作步骤 详细图文解析

在安卓14 安卓15的固件中。如果修改了系统级别的app。那么就会触发安卓14 15的应用签名验证。要么会导致修改的固件会进不去系统,或者进入系统有bug。博文将从几方面来解析去除安卓14 15应用签名验证的几种方法。 💝💝💝通过博文了解: 1💝💝💝-----安卓14去除…