python语言(七)面向对象、异常处理

时间:2022-12-14 23:56:08

一、异常处理

python解释器检测到错误,触发异常(也允许程序员自己触发异常)。程序员编写特定的代码,专门用来捕捉这个异常(这段代码与程序逻辑无关,与异常处理有关)。如果捕捉成功则进入另外一个处理分支,执行你为其定制的逻辑,使程序不会崩溃,这就是异常处理。

  python解释器去执行程序,检测到了一个错误时,触发异常,异常触发后且没被处理的情况下,程序就在当前异常处终止,后面的代码不会运行,谁会去用一个运行着突然就崩溃的软件。所以你必须提供一种异常处理机制来增强你程序的健壮性与容错性。良好的容错能力,能够有效的提高用户体验,维持业务的稳定性。

  程序运行中的异常可以分为两类:语法错误和逻辑错误。首先,我们必须知道,语法错误跟异常处理无关,所以我们在处理异常之前,必须避免语法上的错误。

异常就是程序运行时发生错误的信号,在python中,错误触发的异常如下

python语言(七)面向对象、异常处理

1.1 异常处理方式

1.1.1 使用if判断式

# 我们平时用if做的一些简单的异常处理
num1 = input('>>: ')  # 输入一个字符串试试
if num1.isdigit():
    int(num1)  # 我们的正统程序放到了这里,其余的都属于异常处理范畴
elif num1.isspace():
    print('输入的是空格,就执行我这里的逻辑')
elif len(num1) == 0:
    print('输入的是空,就执行我这里的逻辑')
else:
    print('其他情情况,执行我这里的逻辑')
# 这些if,跟代码逻辑并无关系,显得可读性极差,如果类似的逻辑多,那么每一次都需要判断这些内容,就会倒置我们的代码特别冗长。

使用if判断式可以异常处理,但是if判断式的异常处理只能针对某一段代码,对于不同的代码段的相同类型的错误你需要写重复的if来进行处理。而且在你的程序中频繁的写与程序本身无关,与异常处理有关的if,会使得你的代码可读性极其的差

1.1.2 python提供的特定的语法结构

part1:基本语法

 try:
      被检测的代码块
 except 异常类型:
      try中一旦检测到异常,就执行这个位置的逻辑

part2:单分支

 a = [1,2,3]
 d = {}
 try:
     a[3]
     print(d['name'])
 except IndexError as e:
     print('下标越界',e)
 except KeyError as e:
     print('字典key不存在')
 else:
     print('正常运行')
下标越界 list index out of range

 

finally: 有没有出现异常都走这

 a = [1,2,3]
 d = {}
 try:
     a[3]
     print(d['name'])
 except Exception as e:  # 所有异常都能捕捉到
     print('出异常了',e)
 else:
     print('正常运行')
 finally:
     print('有没有出现异常都走这')
出异常了 list index out of range
有没有出现异常都走这

异常处理try except用法中,如果使用了return就不需要使用else

 try:
     cur.execute(sql)
 except Exception as e:
     print('mysql连接失败,%s' %sql)
     # result = False # 如果使用了return 就不需要使用else
 else:
     ...

part3:多分支

 l1 = [('电脑',16998),('鼠标',59),('手机',8998)]
 while 1:
     for key,value in enumerate(l1,1):
         print(key,value[0])
     try:
         num = input('>>>')
         price = l1[int(num)-1][1]
     except ValueError:
         print('请输入一个数字')
     except IndexError:
         print('请输入一个有效数字')
 #这样通过异常处理可以使得代码更人性化,用户体验感更好。

part4:万能异常

  在python的异常中,有一个万能异常:Exception,他可以捕获任意异常。它是一把双刃剑,有利有弊,我们要视情况使用

  如果你想要的效果是,无论出现什么异常,我们统一丢弃,或者使用同一段代码逻辑去处理他们,那么只有一个Exception就足够了。

  如果你想要的效果是,对于不同的异常我们需要定制不同的处理逻辑,那就需要用到多分支了。我们可以使用多分支+万能异常来处理异常。使用多分支优先处理一些能预料到的错误类型,一些预料不到的错误类型应该被最终的万能异常捕获。需要注意的是,万能异常一定要放在最后,否则就没有意义了。

except Exception as e: 所有异常都能捕捉到

1 a = [1,2,3]
2 d = {}
3 try:
4     a[3]
5     print(d['name'])
6 except Exception as e:  # 所有异常都能捕捉到
7     print('出异常了',e)
8 else:
9     print('正常运行')
出异常了 list index out of range

part5:try...else语句

 try:
     for i in range(10):
         int(i)
 except IndexError as e:
     print(e)
 else:
     print('***********')   #***********   执行了此处
     #当try语句中的代码没有异常,被完整地执行完,就执行else中的代码

小结

 try:
     # 可能发生异常的代码
 except 异常类型1 as 变量名:
     print(变量名) # 变量名存储的是具体的错误信息
 except 异常类型2 as 变量名:
     print(变量名) # 变量名存储的是具体的错误信息
 except Exception as 变量名:
     print(变量名) # 变量名存储的是具体的错误信息
 else:
     print('如果以上代码没有发生异常以及异常处理工作就执行这里的代码')
     print('一般情况下else中的代码用来下结论')
     # logging模块
 finally:
     print('不管代码是否有异常都会执行,且在函数中遇到return仍然会执行')
     print('一般情况下用于这个函数中资源的回收')

1.2 断言

assert断言是声明其布尔值必须为真的判定,如果发生异常就说明表达示为假。可以理解assert断言语句为raise-if-not,用来测试表示式,其返回值为假,就会触发异常

assert的异常参数,其实就是在断言表达式后添加字符串信息,用来解释断言并更好的知道是哪里出了问题。格式如下:
assert expression [, arguments]
assert 表达式 [, 参数]

assert len(lists) >=5,'列表元素个数小于5'
assert 2==1,'2不等于1'

备注:格式:assert  条件  , 条件为false时的错误信息            结果为raise一个AssertionError出来

 # assert 条件

 assert 1 == 1

 assert 1 == 2

二、面向对象

概述

面向对象:核心对象二字,对象是特征与技能的结合体

基于该思想编写程序就好比是在创造一个世界,你就是这个世界的上帝,是一种上帝式的思维方式

2.1 类

面向对象技术简介

  • 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
  • 类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
  • 数据成员:类变量或者实例变量, 用于处理类及其实例对象的相关的数据。
  • 方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
  • 局部变量:定义在方法中的变量,只作用于当前实例的类。
  • 实例变量:在类的声明中,属性是用变量来表示的。这种变量就称为实例变量,是在类声明的内部但是在类的其他成员方法之外声明的。
  • 继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟"是一个(is-a)"关系(例图,Dog是一个Animal)。
  • 实例化:创建一个类的实例,类的具体对象。
  • 方法:类中定义的函数。
  • 对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。

类:一个模型,一个图纸

:种类、分类、类别
    对象是特征与技能的结合体,类是一系列对象相似的特征与技能的结合体
    强调:站的角度不同,总结出的类是截然不同的

    在现实世界中:先有的一个个具体存在的对象,然后随着人类文明的发展才有了分类的概念
    在程序中:必须先定义类,后调用类来产生对象

现实世界中对对象==》总结出现实世界中的类==》定义程序中的类==》调用类产生程序中的对象
站在老男孩选课系统的角度,先总结现实世界中的老男孩的学生对象(这些对象有相似的特征和技能)
    对象1:
        特征:
            学校='oldboy'
            姓名='耗哥'
            年龄=18
            性别='male'
        技能:
            选课

    对象2:
        特征:
            学校='oldboy'
            姓名='猪哥'
            年龄=17
            性别='male'
        技能:
            选课

    对象3:
        特征:
            学校='oldboy'
            姓名='帅翔'
            年龄=19
            性别='female'
        技能:
            选课

站在老男孩选课系统的角度,先总结现实世界中的老男孩学生类
    老男孩学生类:
        相似的特征:
            学校='oldboy'
        相似的技能
            选课

简单例子

 class Car:  #定义一个类,执行类体代码
     def run(self):
         pass
     def driver(self,name):  #在类的名称空间产生一个函数属性的名字(技能)
         print("%s在开车" %name)

 bmw= Car() # 实例化(调用类)产生一个空对象,对象就是一个名称名称空间,就是用来存放一堆自己独有的数据属性的
 #对象本质也就是一个名称空间而已,对象名称空间(容器)是用存放对象自己------独有的名字/属性,而
 #类中存放的是对象们---------------------------------------------------共有的属性

 定义一个连接mysql的类

 import pymysql

 class Db:
     # 第一个方法-连mysql
     def connect(self):
         db_info = {', 'host': '118.24.3.40',
                    'db': 'jxz', 'port': 3306, 'charset': 'utf8', 'autocommit': True}
         self.conn = pymysql.connect(**db_info)  # 建立连接
         self.cur = self.conn.cursor()

     def excute_many(self, sql):
         self.cur.execute(sql)
         return self.cur.fetchmany()

     def excute_one(self, sql):
         self.cur.execute(sql)
         return self.cur.fetchone()

     def excute_all(self, sql):
         self.cur.execute(sql)
         return self.cur.fetchall()

     def close(self):
         self.close()
         self.cur.close()

     def export_excel(self, table_name):
         pass

 mysql = Db()

2.2 python中的self (本类对象)

首先,对于python,只有针对类来说的self才有意义,所以python中的self,说的即是python类中的self。

以下我将结合python类的相关概念叙述,必须明确的是,self只能用在python类的方法(即函数)中。
 
self:本类对象
 # class Student(object):
 #     pass

 class Person:  # 经典类
     # 属性就是变量
     # 功能就是函数
     def __init__(self, uid, name):
         print('self的内存地址:', id(self))
         self.id = uid
         self.name = name

     def cook(self):
         print('%s 会做鱼香肉丝' % self.name)

     def housework(self):
         print('%s 正在做家务' % self.name)

 xh = Person(1, '小黑')
 xh.housework()

 xb = Person(2, '小白')
 xb.cook()
self的内存地址: 2215143160968
小黑 正在做家务
self的内存地址: 2215143161192
小白 会做鱼香肉丝

2.3 构造函数

构造函数,类在实例化的时候会自动执行构造函数

def __init__(self):

 import pymysql

 class Db:
     # 第一个方法-连mysql
     def __init__(self, host, user, password, db, port=3306, charset='utf8'):
         # 构造函数,类在实例化的时候会自动执行构造函数
         self.db_info = {
             'user': user,
             'password': password,
             'db': db,
             'port': port,
             'charset': charset,
             'autocommit': True,
             'host': host}
         self.connect()

     def check_mysql_connect(self):
         pass

     def connect(self):
         db_info = {', 'host': '118.24.3.40',
                    'db': 'jxz', 'port': 3306, 'charset': 'utf8', 'autocommit': True}
         self.conn = pymysql.connect(**db_info)  # 建立连接
         self.cur = self.conn.cursor()

     def excute_many(self, sql):
         self.cur.execute(sql)
         return self.cur.fetchmany()

     def excute_one(self, sql):
         self.cur.execute(sql)
         return self.cur.fetchone()

     def excute_all(self, sql):
         self.cur.execute(sql)
         return self.cur.fetchall()

     def close(self):
         self.close()
         self.cur.close()

     def export_excel(self, table_name):
         pass

 mysql = Db(', 'jxz')
 result = mysql.excute_one('select * from %s' % table_name)
raise Exception 发现异常时,能通过它返回具体异常提示,方便检查错误
     def connect(self):
         try:
             self.conn = pymysql.connect(**self.db_info)
         except Exception as e:
             print("连接不上数据库")
             raise Exception("连接不上数据库,请检查连接")
         # raise Exception

2.3 面向对象 三大特性

封装、继承、多态

1、封装 也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。

2、继承 是面向对象程序设计方法的一个重要手段,通过继承可以更有效地组织程序结构,明确类间的关系,育雏利用已有的类来完成更复杂、更深入的程序开发。

3、多态 允许以一种统一的风格处理已存在的变量和相关的类,多态性使得向系统增加功能变的容易。