Python面向对象编程:封装和私有属性④

news2025/1/13 7:56:56

在这里插入图片描述

文章目录

    • 1. 引言
    • 2. 什么是封装?
    • 3. 公有属性和方法
    • 4. 私有属性和方法
    • 5. 属性访问器(Getters 和 Setters)
    • 6. 使用 `property` 函数
    • 7. 综合示例
      • 7.1 项目结构
      • 7.2 模块代码
        • __init__.py
        • student.py
        • course.py
        • manager.py
      • 7.3 主程序代码
        • main.py
      • 7.4 运行结果
    • 8. 结论

1. 引言

面向对象编程(OOP)是一种基于“对象”的编程范式,这些对象是数据和功能的集合。Python 是一种强大的编程语言,支持面向对象编程。在 OOP 中,封装是一个重要的概念,它允许我们将数据和方法封装在类中,从而保护数据不被外部代码直接访问和修改。本文将详细探讨 Python 中的封装和私有属性,并通过一个综合示例进行说明。

2. 什么是封装?

封装是指将数据和方法捆绑在一起,并隐藏对象的内部实现细节的一种技术。在 Python 中,通过将属性和方法定义在类中,可以实现封装。封装的主要目的是:

  1. 数据保护:防止对象的内部状态被外部直接访问和修改。
  2. 简化接口:对外提供简单的接口,而隐藏复杂的实现细节。
  3. 提高代码可维护性:将相关的数据和方法封装在一起,使代码更加模块化和可维护。

3. 公有属性和方法

在 Python 中,默认情况下,类的属性和方法都是公有的,可以被外部访问和修改。例如:

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def display(self):
        print(f"Name: {self.name}, Age: {self.age}")

# 创建对象
person = Person("Alice", 30)

# 访问公有属性
print(person.name)  # 输出:Alice
print(person.age)   # 输出:30

# 调用公有方法
person.display()    # 输出:Name: Alice, Age: 30

在上述代码中,nameage 是公有属性,display 是公有方法,它们可以被外部代码直接访问和调用。

4. 私有属性和方法

为了实现封装,可以将类的属性和方法定义为私有的,这样它们就不能被外部代码直接访问。在 Python 中,通过在属性或方法前面加上双下划线(__)来将其定义为私有。例如:

class Person:
    def __init__(self, name, age):
        self.__name = name
        self.__age = age

    def __display(self):
        print(f"Name: {self.__name}, Age: {self.__age}")

    def show(self):
        self.__display()

# 创建对象
person = Person("Alice", 30)

# 尝试访问私有属性(会报错)
# print(person.__name)  # AttributeError
# print(person.__age)   # AttributeError

# 尝试调用私有方法(会报错)
# person.__display()    # AttributeError

# 通过公有方法访问私有属性和方法
person.show()  # 输出:Name: Alice, Age: 30

在上述代码中,__name__age 是私有属性,__display 是私有方法,它们不能被外部代码直接访问。通过 show 方法可以访问私有属性和方法。

5. 属性访问器(Getters 和 Setters)

虽然私有属性不能被外部代码直接访问,但可以通过定义属性访问器(Getters 和 Setters)来访问和修改私有属性。通常,我们使用“getter”方法来访问属性的值,使用“setter”方法来修改属性的值。

class Person:
    def __init__(self, name, age):
        self.__name = name
        self.__age = age

    # getter方法
    def get_name(self):
        return self.__name

    def get_age(self):
        return self.__age

    # setter方法
    def set_name(self, name):
        self.__name = name

    def set_age(self, age):
        if age > 0:
            self.__age = age
        else:
            raise ValueError("年龄必须是正数")

# 创建对象
person = Person("Alice", 30)

# 通过getter方法访问私有属性
print(person.get_name())  # 输出:Alice
print(person.get_age())   # 输出:30

# 通过setter方法修改私有属性
person.set_name("Bob")
person.set_age(35)

print(person.get_name())  # 输出:Bob
print(person.get_age())   # 输出:35

通过使用 getter 和 setter 方法,我们可以在不直接访问私有属性的情况下,安全地获取和修改它们的值。

6. 使用 property 函数

Python 提供了 property 函数来简化属性访问器的定义。property 函数可以将方法转换为属性,从而使得属性访问看起来更自然。例如:

class Person:
    def __init__(self, name, age):
        self.__name = name
        self.__age = age

    # getter方法
    @property
    def name(self):
        return self.__name

    @property
    def age(self):
        return self.__age

    # setter方法
    @name.setter
    def name(self, name):
        self.__name = name

    @age.setter
    def age(self, age):
        if age > 0:
            self.__age = age
        else:
            raise ValueError("年龄必须是正数")

# 创建对象
person = Person("Alice", 30)

# 通过属性访问器访问私有属性
print(person.name)  # 输出:Alice
print(person.age)   # 输出:30

# 通过属性访问器修改私有属性
person.name = "Bob"
person.age = 35

print(person.name)  # 输出:Bob
print(person.age)   # 输出:35

通过 property 函数,可以将方法转换为属性,从而使得属性访问和修改更加简洁和自然。

7. 综合示例

为了更好地理解封装和私有属性的概念,我们来看一个综合示例。这个示例包含一个学生管理系统,能够管理学生的基本信息、课程和成绩。

7.1 项目结构

student_management/
    __init__.py
    student.py
    course.py
    manager.py
main.py

7.2 模块代码

init.py
# student_management/__init__.py

from .student import Student
from .course import Course
from .manager import StudentManager

__all__ = ["Student", "Course", "StudentManager"]
student.py
# student_management/student.py

class Student:
    def __init__(self, name, student_id):
        self.__name = name
        self.__student_id = student_id
        self.__courses = {}

    @property
    def name(self):
        return self.__name

    @name.setter
    def name(self, name):
        self.__name = name

    @property
    def student_id(self):
        return self.__student_id

    def add_course(self, course):
        self.__courses[course.course_id] = course

    def get_courses(self):
        return self.__courses

    def __str__(self):
        return f"Student(name={self.__name}, student_id={self.__student_id})"
course.py
# student_management/course.py

class Course:
    def __init__(self, course_id, course_name):
        self.__course_id = course_id
        self.__course_name = course_name
        self.__grades = {}

    @property
    def course_id(self):
        return self.__course_id

    @property
    def course_name(self):
        return self.__course_name

    def add_grade(self, student_id, grade):
        self.__grades[student_id] = grade

    def get_grades(self):
        return self.__grades

    def __str__(self):
        return f"Course(course_id={self.__course_id}, course_name={self.__course_name})"
manager.py
# student_management/manager.py

from .student import Student
from .course import Course

class StudentManager:
    def __init__(self):
        self.__students = {}
        self.__courses = {}

    def add_student(self, name, student_id):
        student = Student(name, student_id)
        self.__students[student_id] = student

    def add_course(self, course_id, course_name):
        course = Course(course_id, course_name)
        self.__courses[course_id] = course

    def enroll_student_in_course(self, student_id, course_id):
        student = self.__students.get(student_id)
        course = self.__courses.get(course_id)
        if student and course:
            student.add_course(course)
        else:
            raise ValueError("学生或课程不存在")

    def add_grade(self, student_id, course_id, grade):
        course = self.__courses.get(course_id)
        if course:
            course.add_grade(student_id, grade)
        else:
            raise ValueError("课程不存在")

    def get_student_grades(self, student_id):
        student = self.__students.get(student_id)
        if student:
            courses = student.get_courses()
            grades = {course_id: course.get_grades().get(student_id) for course_id, course in courses.items()}
            return

 grades
        else:
            raise ValueError("学生不存在")

    def __str__(self):
        students_str = ", ".join(str(student) for student in self.__students.values())
        courses_str = ", ".join(str(course) for student in self.__courses.values())
        return f"StudentManager(students=[{students_str}], courses=[{courses_str}])"

7.3 主程序代码

main.py
# main.py

from student_management import StudentManager

def main():
    manager = StudentManager()

    # 添加学生
    manager.add_student("Alice", 1)
    manager.add_student("Bob", 2)

    # 添加课程
    manager.add_course(101, "Mathematics")
    manager.add_course(102, "Science")

    # 学生注册课程
    manager.enroll_student_in_course(1, 101)
    manager.enroll_student_in_course(2, 102)

    # 添加成绩
    manager.add_grade(1, 101, 95)
    manager.add_grade(2, 102, 88)

    # 获取学生成绩
    alice_grades = manager.get_student_grades(1)
    bob_grades = manager.get_student_grades(2)

    print("Alice's Grades:", alice_grades)
    print("Bob's Grades:", bob_grades)

    print(manager)

if __name__ == "__main__":
    main()

7.4 运行结果

Alice's Grades: {101: 95}
Bob's Grades: {102: 88}
StudentManager(students=[Student(name=Alice, student_id=1), Student(name=Bob, student_id=2)], courses=[Course(course_id=101, course_name=Mathematics), Course(course_id=102, course_name=Science)])

8. 结论

封装是面向对象编程中的一个重要概念,通过将数据和方法封装在类中,并隐藏对象的内部实现细节,我们可以提高代码的安全性和可维护性。通过使用私有属性和方法,我们可以防止对象的内部状态被外部直接访问和修改,并通过属性访问器和 property 函数提供安全的访问和修改接口。希望本文能够帮助你更好地理解 Python 中的封装和私有属性。

这个综合示例展示了如何使用封装和私有属性来创建一个学生管理系统,通过这种方式,我们实现了数据保护和接口简化,使得代码更加模块化和可维护。


欢迎点赞|关注|收藏|评论,您的肯定是我创作的动力

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

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

相关文章

cmake模板-支持编译动态/静态文件

代码链接:代码仓库 git clone https://gitee.com/etsuyou/cmake-template.git模板 模板截图 如何使用 在src和inc中写代码 此处用我默认提供的代码 ./go.sh cmake 生成Makefile ./go.sh make 生成bin文件和.a以及.so ./go.sh run app 运行 ./go.sh clean 以…

Tomcat服务部署及优化

一、Tomcat的基本介绍 1. tomcat是什么? Tomcat服务器是一个免费的开放源代码的Web应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP程序的首选。一般来说,T…

QT QML 练习8-Simple Transformations

简单的转换(Simple Transformations) 转换操作改变了一个对象的几何状态。QML元素对象通常能够被平移,旋转,缩放。下面我们将讲解这些简单的操作和一些更高级的用法。 我们先从一个简单的转换开始。用下面的场景作为我们学习的开始…

Python学习100天第9天之面向对象进阶

1 前言 在前面的章节我们已经了解了面向对象的入门知识,知道了如何定义类,如何创建对象以及如何给对象发消息。为了能够更好的使用面向对象编程思想进行程序开发,我们还需要对Python中的面向对象编程进行更为深入的了解。 2 property装饰器…

AVLTree 旋转笔记(根据平衡因子插入的公式,贼好理解)

平衡因子 avltree是一棵每个节点的左右子树的高度差不超过1的二叉树搜索树,对于avltree最重要的就是对平衡因子的控制。 对于旋转我们重点要注意的是三个节点,以左旋举例,需要注意的就是parent,subr,subrl。而旋转的方…

MYSQL架构、执行过程和顺序

MYSQL架构、执行过程和顺序 一、前言 1.1、说明 就MySQL的架构,以及执行过程、sql执行顺序,以及一些相关学习分享内容。 在参考文章的基础上,会增加自己的理解、看法,希望本文章能够在您的学习中提供帮助。 如有错误的地方&a…

Dokcer如何容器部署及常见问题

本文讲解通过Docker部署Jenkins过程及遇到的问题。 通过 Docker 部署 Jenkins 使用 Docker 来部署 Jenkins 是一个快速且高效的方式。以下是使用 Docker 部署 Jenkins 的分步骤指南: 1. 安装 Docker 如果你的系统上还没有安装 Docker,请根据操作系统…

春日技术问答:Spring Boot课程答疑

3系统分析 3.1可行性分析 通过对本课程答疑系统实行的目的初步调查和分析,提出可行性方案并对其一一进行论证。我们在这里主要从技术可行性、经济可行性、操作可行性等方面进行分析。 3.1.1技术可行性 本课程答疑系统采用JAVA作为开发语言,Spring Boot框…

【2D/3D-Lidar-SLAM】 Cartographer详细解读

【2D/3D-Lidar-SLAM】 Cartographer详细解读 1. 摘要 2. Cartographer系统数据处理流程2.1. 数据获取(Input Sensor Data)2.2 姿态外推器(PoseExtrapolator)2.3 局部建图(Local SLAM) 3. 关键模块实现 3.1 …

5、springboot-基础入门

1、系统要求 Java 8 & 兼容java14 .Maven 3.3idea 2019.1.2 1.1、maven设置 修改maven的settings.xml文件中的镜像&#xff0c;如下 <mirrors><mirror><id>nexus-aliyun</id><mirrorOf>central</mirrorOf><name>Nexus aliyu…

vue3 在store的index.js

导入vuex&#xff0c;在store的index.js创建store对象 在main.js挂载store import store from ./storenew Vue ({/* 将store对象实例挂载到vue实例中 所有组件就可以直接从store中获取全局数据了*/ store, render: h > h(App) }).$mount(#app) 在store中的index.js进行声明…

【IPv6】IPv6 NAT66介绍

参考链接 IPv6-to-IPv6 Network Address Translation (NAT66) (ietf.org)https://datatracker.ietf.org/doc/id/draft-mrw-nat66-00.html IPv6 NAT66 NAT66&#xff0c;全称为Network Address Translation for IPv6 to IPv6&#xff0c;是一种用于IPv6网络的地址转换技术。在…

FPGA基于SRIO Auraro 三速以太网 IIC SPI等多协议的高速传输处理项目

高速传输处理项目 此项目涉及较多协议和接口&#xff0c;有较复杂的系统顶层框图设计。在涉及设备较多的应用场景中&#xff0c;需要涉及一款PCI-E板卡&#xff0c;将多个子系统的数据汇总上传到PC或服务器上。在此项目中有3路数据源&#xff0c;分别是:srio数据&#xff0c; …

数据结构与算法:动态规划的深度探讨

目录 12.1 动态规划的核心思想 12.2 经典动态规划问题 12.3 动态规划在图中的应用 12.4 高级动态规划技术 总结 数据结构与算法&#xff1a;动态规划的深度探讨 动态规划&#xff08;Dynamic Programming, DP&#xff09;是一种解决复杂问题的有效方法&#xff0c;特别适…

Nuxt3部署-Ubuntu系统(Node 服务 + pm2 + Nginx 反向代理)

Nuxt3部署-Ubuntu系统&#xff08;Node 服务 pm2 Nginx 反向代理&#xff09; 文章目录 Nuxt3部署-Ubuntu系统&#xff08;Node 服务 pm2 Nginx 反向代理&#xff09;一、安装 Nodejs 环境二、安装 Nginx三、安装 pm2四、本地项目打包1️⃣&#xff1a;打包2️⃣&#xff1…

【截流软件】采集短视频关键词笔记下的筛选评论

用python开发的dy采集工具【爬抖Y搜索评论软件】&#xff0c;可用于引流截流等。 支持2种模式的评论采集&#xff1a; 根据关键词采集评论&#xff0c;爬取思路&#xff1a;作品关键词->作品链接->评论根据作品链接采集评论&#xff0c;爬取思路&#xff1a;作品链接-&g…

aws(学习笔记第六课) AWS的虚拟私有,共有子网以及ACL,定义公网碉堡主机子网以及varnish反向代理

aws(学习笔记第六课) AWS的虚拟私有&#xff0c;共有子网以及ACL&#xff0c;定义公网碉堡主机子网以及varnish反向代理 学习内容&#xff1a; AWS的虚拟私有&#xff0c;共有子网以及ACL定义公网碉堡主机子网&#xff0c;私有子网和共有子网以及varnish反向代理 1. AWS的虚拟…

分享一个中国行政区划多边形2024版(含有十段线)

全国省市县三级行政区划分类 全国有省市县界限数据 十段线 有需要自取

[Linux系统编程] 线程同步(互斥锁,读写锁,死锁,条件变量,信号量)

一.线程同步概念 线程同步&#xff1a; 协同步调&#xff0c;对公共区域数据按序互斥访问。防止数据混乱&#xff0c;产生与时间有关的错误。 数据混乱的原因&#xff1a; 1.资源共享(独享资源则不会) 2.调度随机(意味着数据访问会出现竞争)—线程间竞争 3.线程间缺乏必要同步…

一篇闪击常用放大器电路(学习笔记)

文章目录 声明概念名词经典电路分析反向放大器同向放大器加法器减法器积分电路微分电路差分放大电路电流->电压转换电路电压->电流转换电路 虚短与虚断一、虚短二、虚断 一些碎碎念 声明 ​ 本文是主要基于以下两篇博客所做的笔记&#xff1a; 模电四&#xff1a;基本放…