Python 面向对象——6.封装 1

本章学习链接如下:

Python 面向对象——1.基本概念

Python 面向对象——2.类与对象实例属性补充解释,self的作用等

Python 面向对象——3.实例方法,类方法与静态方法

Python 面向对象——4.继承

Python 面向对象——5.多态

1. 封装的基本概念

封装是将属性和方法结合在一起的机制,同时限制对对象内部实现的直接访问。在Python中,封装通常是通过定义类和使用私有变量(以双下划线开头)来实现的。封装的主要目的是隐藏对象的内部状态和复杂性,只暴露出一个清晰和简洁的接口供外部代码使用。

(1)私有变量

私有变量是一种访问限制机制,用于限制类外部对类内部属性或方法的直接访问。

命名约定:在Python中,私有变量通常以两个下划线(_ _)开头。例如:_ _my_variable。那这是怎样做到的呢?源于Python中的名称重整机制。

(2)名称重整规则 

  1. 如果属性名以双下划线开头,但不以下划线结尾(_ _name),那么在名称重整时,会将属性名中的双下划线替换为类名,然后再加上一个单下划线。例如,对于类MyClass中的属性_ _my_variable,重整后的名称将是_MyClass_ _my_variable

  2. 如果属性名以双下划线开头,并且以下划线结尾(_ _my_variable_ _),那么在名称重整时,会保留一个下划线在属性名的开头和结尾。例如,对于类MyClass中的属性_ _my_variable_ _,重整后的名称将是 _MyClass_ _my_variable_ _

我们看下面这个代码示例,self._ _salary 是一个私有属性,它被声明为私有的,因为它的名称以双下划线开头。根据名称重整规则,这个属性在类外部的名称将变为 _Employee_ _salary。self._ _top_secret() 是一个私有方法,同样因为以双下划线开头,它在类外部的名称将变为 _Employee_ _top_secret。当我们尝试直接访问这些私有成员时,Python解释器会抛出一个 AttributeError,因为它找不到这些属性或方法。然而,如果我们知道了名称重整后的名称,我们仍然可以访问到这些私有成员,但这违反了封装的原则,因此通常不推荐这样做。

请注意,尽管我们可以通过名称重整后的名称访问私有成员,但这并不是Python推崇的做法。更好的做法是通过类的公有接口(如方法)来访问或修改私有成员,以保持类的封装性。

class Employee:
    def __init__(self, name):
        self.name = name  # 公开属性
        self.__salary = 50000  # 私有属性,使用双下划线开头

    def give_raise(self, amount):
        self.__salary += amount
        print(f"{self.name}'s new salary is: ${self.__salary}")

    def __top_secret(self):
        pass  # 私有方法,使用双下划线开头

# 创建Employee类的实例
emp = Employee("Alice")

# 尝试直接访问私有属性(这将不会成功)
try:
    print(emp.__salary)  # 错误:__salary不是Employee的属性
except AttributeError as e:
    print(e)

# 尝试调用私有方法(这也将不会成功)
try:
    emp.__top_secret()  # 错误:__top_secret不是Employee的方法
except AttributeError as e:
    print(e)

# 使用公开方法访问私有属性
print(f"{emp.name}'s salary is: ${emp._Employee__salary}")

请注意,名称重整并不是真正的私有化,而是一种约定。它通过名称改写来减少属性被外部访问的可能性,但并不阻止有经验的程序员绕过这个机制。在Python中,如果你想要完全私有的属性,可以使用单下划线开头的属性名(_my_variable),但这只是一种约定,表示该属性不应该被外部直接访问。

(3)try:

tryexcept语句用于异常处理。当你执行一个可能会抛出异常的代码段时,可以将该段代码放在try块中。如果在try块中的代码执行过程中发生了异常,程序的执行将不会立即停止,而是会跳转到except块中,这允许你捕获并处理异常。

在这段代码示例中,try块用于尝试访问Employee类的私有属性_ _salary和调用私有方法_ _top_secret。根据Python的命名规则,以双下划线开头的属性和方法对外部是不可访问的,因为它们被视为私有的(尽管这不是一种真正的私有机制,只是一种命名约定)。

代码中的两个try块尝试执行如下操作:

  1. 尝试直接访问emp实例的私有属性_ _salary。由于_ _salary是私有的,这个尝试会抛出AttributeError,因为_ _salary不是Employee实例的公开属性。

  2. 尝试调用emp实例的私有方法_ _top_secret。同样,由于_ _top_secret是私有的,这个尝试也会抛出AttributeError

2.错误捕获

(1)背后的原理

except AttributeError as e:
    print(e)

 当AttributeError被捕获时,变量e是一个异常对象。这个对象包含了异常的详细信息,当你打印e时,实际上是调用了该对象的__str__()方法,它返回异常的描述性字符串。

当你打印一个异常对象时,背后实际上是调用了该对象的__str__()方法。这是Python对象的内置特殊方法(也称为"dunder"方法,即双下划线前缀和后缀的方法),用于返回对象的字符串表示形式。即使在给定的类定义中没有显式地看到__str__()方法,它也是隐式存在的,因为所有的Python对象默认继承自object类,而object类提供了一个默认的__str__()实现。

异常类(如AttributeError)通常会重写__str__()方法,以返回一个描述错误的字符串。当你执行print(e),Python首先查找对象e__str__()方法,并调用它来获取字符串表示,然后打印出来。

这是Python中所有异常对象的标准行为,所以即使你在类定义中没有看到显式的__str__()方法,当你打印异常对象时,它也是可用的。

下面是一个简单的示例,展示如何自定义一个类并重写__str__()方法:

在上面的代码中,我们创建了一个自定义异常MyError,它继承自Python的基类Exception。我们重写了__str__()方法来返回一个自定义的错误信息。当异常被捕获并打印时,会显示我们提供的信息。

class MyError(Exception):
    def __str__(self):
        return "自定义错误信息"

try:
    raise MyError()
except MyError as e:
    print(e)  # 输出: 自定义错误信息

(2)Exception

Python的Exception类是所有内置和用户定义的异常的基类。它位于异常类继承层次结构的顶端,提供了处理异常时的默认行为。在Python中,异常是用于错误处理的一种机制,允许程序在发生错误时从代码的某个部分“跳出”,并提供一种方式来响应或恢复。

  • 25
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

林采采学编程+

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值