当前位置: 首页 > article >正文

Python小白学习教程从入门到入坑------第二十三课 封装(语法进阶)

面向对象的三大特征:封装、继承、多态

一、封装

1.1 何为封装

封装:在Python中指的是隐藏对象中一些不希望被外部所访问到的属性或者方法。将复杂的信息、流程给包起来,内部处理,让使用者只需要通过简单的操作步骤,就能实现。

在Python中,封装(Encapsulation)是面向对象编程(OOP)的一个核心概念。

规范的说法:封装指的是将对象的属性和方法结合在一起,并隐藏对象的内部实现细节,只通过公开的接口(通常是方法)与外部进行交互。封装的目的在于保护对象的内部状态,防止外部代码直接访问和修改,从而确保对象的完整性和安全性。

当不使用封装时,类里面的属性可以被看见甚至可以被修改

eg:

class Person:
    name = 'junjun'    # 类属性
pe = Person()
print(pe.name)      # 输出内容:junjun
Person.name = 'yuyu'
print(Person.name)  # 输出内容:yuyu
print(pe.name)      # 输出内容:yuyu

这种不封装的代码很容易被篡改,会带来一系列的安全问题,为了解决安全性这一问题,我们要对类进行封装操作

1.2 隐藏属性(私有权限)

隐藏属性:只允许在类的内部使用,无法通过对象访问

在属性名或者方法名前面加上两个下划线__

class Person:
    name = "junjun"   # 类属性
    __age = 18        # 隐藏属性
pe = Person()
print(pe.name)
print(pe.__age)    #报错: __age被隐藏,不可以在类的外部访问类的隐藏属性

但如果类的隐藏属性已经被定义好了,我们又需要从外边访问它的值该怎么做呢?

这里有两种方法:

第一种: (了解即可,不太正规)

注意:隐藏属性实际上是将名字修改为:_类名__属性名,上面例子中的__age 就被修改为_Person__age

eg:

class Person:
    name = "junjun"   # 类属性
    __age = 28        # 隐藏属性
pe = Person()
print(pe.name)
# print(pe.__age)    #报错: __age被隐藏,不可以在类的外部访问类的隐藏属性
print(pe._Person__age)
# 输出结果:
# junjun
# 28

此种方法也可以对隐藏属性进行修改

class Person:
    name = "junjun"   # 类属性
    __age = 28       # 隐藏属性
pe = Person()
print(pe.name)
# print(pe.__age)    #报错: __age被隐藏,不可以在类的外部访问类的隐藏属性
print(pe._Person__age)
pe._Person__age = 18
print(pe._Person__age)
# 输出结果:
# junjun
# 28
# 18

 第二种:在类的内部访问——推荐使用,正规手段

eg:

class Person:
    name = "junjun"   # 类属性
    __age = 28       # 隐藏属性
    def introduce(self):   # 实例方法
        Person.__age = 16    # 可以对隐藏属性进行更改
        print(f"{Person.name}的年龄是{Person.__age}")  # 在实例方法中访问类属性和隐藏属性
pe = Person()
pe.introduce()
# 输出结果:junjun的年龄是16

1.3 私有属性/方法

1. xxx:普通属性/方法,如果是类中定义的,则类可以在任何地方使用

2. _xxx: 单下划线开头,声明私有属性/方法,如果定义在类中,外部可以使用,子类也可以继承,但是在另一个py文件中通过 from  xxx   import  *  导入时,无法导入。此种命名方法一般是为了避免与Python关键字冲突而采用的命名方法

3. __xxx: 双下划线开头,隐藏属性,如果定义在类中,无法在外部直接访问,子类不会继承,要访问只能通过间接的方式,另一个py文件中通过 from  xxx  import  *导入时,也无法导入 。这种命名方法一般是Python中的魔法方法或属性,都是有特殊含义或者功能的,自己不要轻易定义

eg:

class Person:
    name = "junjun"   # 类属性
    __age = 28       # 隐藏属性(双下划线)
    _sex = "女"      # 私有属性(单下划线)
pe = Person()
# print(pe.sex)  报错
# 使用对象名._属性名调用
print(pe._sex)
# 使用对象._类名__属性名访问隐藏属性
print(pe._Person__age)
# 输出结果:
# 女
# 28

1.4 隐藏方法 

在Python中,没有严格意义上的“隐藏方法”的概念,因为Python是一种动态类型语言,并且其访问控制机制相对宽松

然而,有一些约定俗成的命名和编码规范,可以让开发者通过命名来暗示方法的可见性和使用意图 

class Man:
    def __play(self):     # 隐藏方法
        print("玩手机")
    def funa(self):       # 平平无奇的实例方法
        print("平平无奇的实例方法")
        Man.__play(self)   # 在实例方法中调用私有方法   ————不推荐
        self.__play()     # 推荐使用,更简便
ma = Man()
ma.funa()

1.5 私有方法

在Python中,尽管没有像其他某些编程语言(例如Java)那样的严格访问修饰符来定义私有方法,但Python有一种约定俗成的方式来暗示某个方法是私有的

这种方式主要是通过在方法名前添加一个下划线前缀(_)来实现的。需要注意的是,这仅仅是一种约定,而不是Python语言本身的强制规则

私有方法通常被设计为仅在类的内部使用,而不应被类的外部代码直接调用

尽管从技术上讲,外部代码仍然可以访问这些以单下划线开头的方法,但按照Python的社区规范,这样的访问是不被推荐的,因为它违背了封装的原则

eg:

class MyClass:  
    def __init__(self, value):  
        self._private_value = value  # 私有属性  
  
    def _private_method(self):  
        # 这是一个私有方法,它应该只在类的内部被调用  
        print(f"Private value is: {self._private_value}")  
  
    def public_method(self):  
        # 这是一个公共方法,它可以被类的外部代码调用  
        self._private_method()  # 在类的内部调用私有方法  
  
# 创建类的实例  
obj = MyClass(42)  
  
# 调用公共方法,它会间接调用私有方法  
obj.public_method()  # 输出: Private value is: 42  
  
# 直接调用私有方法(虽然技术上可行,但不符合Python的封装原则)  
# obj._private_method()  # 这行代码在技术上是可行的,但通常不建议这样做

在上面的示例中,_private_method 是一个私有方法,它应该只在 MyClass 类的内部被调用

public_method 是一个公共方法,它可以被类的外部代码调用,并且它内部调用了私有方法 _private_method

尽管可以通过 obj._private_method() 直接调用私有方法,但这样做违背了封装的原则,并可能导致代码的可维护性和可读性降低

因此,建议遵循Python的社区规范,不要直接访问以单下划线开头的私有方法和属性

需要注意的是,双下划线前缀(__)会导致Python进行名称改写(name mangling),但这通常用于避免子类意外覆盖父类的方法或属性,而不是用于定义私有方法

使用双下划线前缀的方法名会在类定义时被改写为 _ClassName__methodName 的形式,但仍然可以通过这个改写后的名称在外部访问

因此,双下划线前缀也不是严格意义上的私有方法定义

今天的分享就到这里了,希望能帮助到大家~


http://www.kler.cn/a/379758.html

相关文章:

  • vue2和vue3在html中引用组件component方式不一样
  • Rust 力扣 - 1423. 可获得的最大点数
  • LeetCode //C - 447. Number of Boomerangs
  • Java | Leetcode Java题解之第526题优美的排列
  • 打包IPA包上传,报错“您的可执行文件包含不受支持的体系结构(×86 _64 i386)”
  • 适用于 c++ 的 wxWidgets框架源码编译SDK-windows篇
  • 【STM32】STM32G431RBT6单片机的BOOT引脚位置及功能
  • 华为HarmonyOS打造开放、合规的广告生态 - 贴片广告
  • 关于wordpress instagram feed 插件 (现更名为Smash Balloon Social Photo Feed)
  • 使用OCC,输入一个三维的曲面body,和一个平面plane,如果平面plane与body有相交,输出相交结果左右两部分
  • 多线程和线程同步基础篇学习笔记(Linux)
  • 数据结构---链表实现双端队列
  • 小程序跳转另一个小程序
  • WiFi一直获取不到IP地址是怎么回事?
  • Spark中的宽窄依赖
  • 【6G 需求与定义】ITU(国际电联)对全球6G标准的愿景
  • 【工具变量】大数据管理机构改革DID(2007-2023年)
  • el-table 滚动条重置 手动控制滚动条
  • 鸿蒙OS带来前端的机遇:ArkTS与Typescript+ArkUI与SwiftUI的简单对比你就知道了
  • 【编程语言】Kotlin快速入门 - 泛型
  • 深入解密 K 均值聚类:从理论基础到 Python 实践
  • 72页PPT高效协同:SOP运营变革规划核心框架
  • VMware虚拟机Debian扩展磁盘
  • IO 多路复用技术:原理、类型及 Go 实现
  • 助力风力发电风机设备智能化巡检,基于YOLOv8全系列【n/s/m/l/x】参数模型开发构建无人机巡检场景下风机叶片缺陷问题智能化检测预警模型
  • 初级社会工作者试题