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.xdnf.cn/news/14602.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

VLC-QT----Linux编译并运行示例

linux:ubuntu 16.04 qt:5.13.2 总体安装步骤 下载安装,编译 下载源码仓库,下载cmake,新建一个build文件夹,cd进去,执行代码 cmake .. -DCMAKE_BUILD_TYPEDebug 遇到报错,没有qt5Coreconfig,运行 sudo apt-get install qtdeclarative5-dev进行安装 遇到报错 Could not fi…

机器学习:XGBoost模型——高效且强大的树形模型

XGBoost(Extreme Gradient Boosting,极端梯度提升树)是一种强大的梯度提升算法,在现实中被广泛用于分类和回归任务。它通过集成多个简单的基学习器(通常是决策树)来构建一个强大的预测模型。 基本原理步骤…

爬虫开发工具与环境搭建——开发工具介绍

第二章:爬虫开发工具与环境搭建 第一节 开发工具介绍 爬虫开发需要一些合适的工具和框架来高效地抓取网页数据。在这节中,我们将介绍常用的开发工具,帮助开发者快速搭建爬虫开发环境。 1. Python与爬虫框架选择 Python因其简洁、易学的语法…

python高级之面向对象编程

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

通过Docker实现openGauss的快速容器化安装

容器安装 本章节主要介绍通过 Docker 安装 openGauss,方便 DevOps 用户的安装、配置和环境设置。 支持的架构和操作系统版本 x86-64 CentOS 7.6 ARM64 openEuler 20.03 LTS 配置准备 使用 buildDockerImage.sh 脚本构建 docker 镜像,buildDockerIm…

康谋分享 | 确保AD/ADAS系统的安全:避免数据泛滥的关键

为确保AD/ADAS系统的安全性,各大车企通常需要收集、处理和分析来自于摄像头、激光雷达等传感器的数据,以找出提高系统安全性和性能的方法。然而在数据收集过程中,不可避免地会出现大量无价值数据,造成数据泛滥的情况,进…

电工电子原理笔记

这一篇手记会记录我硬件开发过程中遇到的一些底层电学原理,并且结合实际场景作为“例题”(出于篇幅和保密考虑会进行部分简化)。 叠加定理 基本介绍 在线性电路中,任一支路的电流(或电压)可以看成是电路…

【赵渝强老师】MySQL InnoDB的段、区和页

MySQL的InnoDB存储引擎的逻辑存储结构和Oracle大致相同,所有数据都被逻辑地存放在一个空间中,我们称之为表空间(tablespace)。表空间又由段(segment)、区(extent)、页(pa…

Python 继承笔记

知识点: 1.has a 一个类中使用了另外一种自定义类的类型 student 使用computer book 2.类型 系统类型 str,int,float,list,tuple,dic,set 自定义类型 算是自定义的类,都可以将其当成一种类型 student是一种类型 sStudent() s是Student的类型 class Stud…

Vue3 -- 项目配置之husky【企业级项目配置保姆级教程4】

引言: eslint:代码规范校验prettier:代码格式化stylelint:CSS代码校验 上述三篇文章集成配置完成代码校验工具,当时需要每次手动的去执行命令才会格式化我们的代码。。如果有人没有格式化就提交了远程仓库&#xff0…

万字长文分析函数式编程

目录 一.认识函数式编程 一、函数式编程的定义 二、函数式编程的思想 三、函数式编程的特点 四、函数式编程的应用 二.Lambda表达式 三.Stream流 3.1 创建流对象 3.2 注意事项 3.3 Stream流的中间操作 filter map distinct sorted limit skip flatMap 3.4 St…

移植 AWTK 到 纯血鸿蒙 (HarmonyOS NEXT) 系统 (8) - 原生输入法

AWTK 在嵌入式平台使用内置的输入法,在移动设备上使用系统的原生输入法。在 AWTK-Android 和 AWTK-IOS 中,使用的是 SDL 封装之后的系统原生输入法。在 AWTK-HarmonyOS 中,要使用系统的原生输入法。需要实现 input_method 接口: 1…

【解决】Layout 下创建槽位后,执行 Image 同步槽位位置后表现错误的问题。

开发平台:Unity 6.0 编程语言:CSharp 编程平台:Visual Studio 2022   一、问题背景 | 开发库存系统 图1 位置同步失败问题 图2 位置正常同步效果表现 黑框 作用于 UnityEngine.UI.GridLayoutGruop,形成 4x6 布局,如…

【Jenkins实战】Windows安装服务启动失败

写此篇短文,望告诫后人。 如果你之前装过Jenkins,出于换域账号/本地帐号的原因想重新安装,你大概率会遇上一次Jenkins服务启动失败提示: Jenkins failed to start - Verify that you have sufficient privileges to start system…

免费,WPS Office教育考试专用版

WPS Office教育考试专用版,不仅满足了考试需求,更为教育信息化注入新动力。 https://pan.quark.cn/s/609ef85ae6d4

94个属于一区且接受医工交叉领域投稿的期刊汇总|个人观点·24-11-13

小罗碎碎念 继汇总病理AI的基础模型、病理组学&影像组学的公开数据集以后,我们再来盘一盘医工交叉领域有哪些热门期刊可以投稿。我会分区进行介绍,每个区则会进一步划分学科种类,方便大家选择适合自己的投稿期刊。 这期推文先分享大类属…

【插件】重复执行 pytest-repeat

安装 pip3 install pytest-repeat 用法 1.命令行 pytest --count num pytest --count 32.装饰器 pytest.mark.repeat(num) #num运行次数 pytest.mark.repeat(5)#执行结果如下:

el-table合并单元格之后,再进行隔行换色的且覆盖表格行鼠标移入的背景色的实现

el-table 中有现成的隔行换色功能,只要增加 stripe 属性即可。但是如果有单元格合并的话,这个属性就不可用了。这时候我们就需要动点小心思了。 基于相同字段进行合并 单元格合并:基于表头中的某一列,具有相同值的个数相加进行合…

【小白玩NAS】PVE硬盘直通

简介 在DAS架构中,硬盘(NvMe除外)通过硬盘控制器连接并由其管理。因此,如果将硬盘控制器直通到虚拟机,控制器下的所有硬盘也会间接直通至虚拟机。这样一来,虚拟机内会将这些硬盘视为物理磁盘,并…

IBM 开源的文档转化利器「GitHub 热点速览」

上周的热门开源项目,Star 数增长犹如坐上了火箭,一飞冲天。短短一周就飙升了 6k Star 的多格式文档解析和导出神器 Docling,支持库和命令行的使用方式。全新的可视化爬虫平台 Maxun,则在刚开源时便轻松斩获了 4k Star。而本地优先…