Bootstrap

Python教程:面向对象基础和进阶

面向对象基础

【1】类和对象

(1)类和对象的概念

面向对象编程(Object-oriented Programming,简称 OOP)是一种编程范式。

  • 从思想角度讲

面向对象思想来源于对现实世界的认知。现实世界缤纷复杂、种类繁多,难于认识和理解。但是聪明的人们学会了把这些错综复杂的事物进行分类,从而使世界变得井井有条。现实世界中每一个事物都是一个对象,它是一种具体的概念。类是人们抽象出来的一个概念,所有拥有相同属性功能的事物称为一个类;而拥有相同属性和功能的具体事物则成为这个类的实例对象。

比如现实世界中,

狗的属性是有尾巴,有毛,四条腿等,功能是能汪汪叫,能吃骨头,能咬人等。能有这些属性和功能的事物我们就认为属于狗类。

人的属性是两条腿,没有尾巴等,功能是能玩火,能尿炕,能使用工具。能有这些属性和功能的事物我们就认为属于人类。

电脑属性是有CPU,存储器,操作系统等,功能就是能安装APP,能连网等。能有这些属性和功能的事物我们就认为属于电脑类。

汽车的属性是有四个轮子,一个底盘,一个方向盘等,功能是能行驶,能加速,能刹车等。能有这些属性和功能的事物我们就认为属于汽车类。

在这里插入图片描述

面向对象编程提供了一种从现实世界中抽象出概念和实体的方法。通过类和对象的概念,可以将现实世界中的问题和关系转化为代码结构,使得程序更加符合问题域的模型化。

面向对象编程通过采用类的概念,把事物编写成一个个“类”。在类中,用数据表示事物的状态,用函数实现事物的行为,这样就使编程方式和人的思维方式保持一致,极大的降低了思维难度。
在这里插入图片描述

legs_num = 4
has_hair = True
has_tail = True

def bark(self):
    print("狗狂吠")

def bite(self):
    print("狗咬人")

def fetch(self):
    print("狗捡球")
    
legs_nums = 2
has_wings = True
has_teeth = False

def fly(self):
    print("鸟飞翔")

def eat_worms(self):
    print("鸟吃虫子")

def nest(self):
    print("鸟筑巢")

类版本:

# 声明类
class Dog:
    legs_num = 4
    has_hair = True
    has_tail = True

    def bark(self):
        print("狗狂吠")

    def bite(self):
        print("狗咬人")

    def fetch(self):
        print("狗捡球")

# 实例化对象
alex = Dog()
print(alex.legs_num)
alex.bark()
alex.bite()


class Bird:
    legs_nums = 2
    has_wings = True
    has_teeth = False

    def fly(self):
        print("鸟飞翔")

    def eat_worms(self):
        print("鸟吃虫子")

    def nest(self):
        print("鸟筑巢")

# 实例化对象
b1 = Bird()
print(b1.has_wings)
print(b1.has_teeth)
b1.fly()
  • 从封装角度讲

面向对象编程(Object-oriented Programming,简称 OOP),是一种封装代码的方法。其实,在前面章节的学习中,我们已经接触了封装,比如说,将乱七八糟的数据扔进列表中,这就是一种简单的封装,是数据层面的封装;把常用的代码块打包成一个函数,这也是一种封装,是语句层面的封装。

面向对象编程,也是一种封装的思想,不过显然比以上两种封装更先进,它可以更好地模拟真实世界里的事物(将其视为对象),并把描述特征的数据和代码块(函数)封装到一起。

面向对象编程(Object-Oriented Programming,简称OOP)相较于面向过程编程(Procedural Programming)有以下几个优点:

  1. 封装性(Encapsulation):面向对象编程通过将数据和操作封装在一个对象中,使得对象成为一个独立的实体。对象对外部隐藏了内部的实现细节,只暴露出必要的接口,从而提高了代码的可维护性和模块化程度。
  2. 继承性(Inheritance):继承是面向对象编程的重要特性之一。它允许创建一个新的类(子类),从一个现有的类(父类或基类)继承属性和方法。子类可以通过继承获得父类的特性,并可以在此基础上进行扩展或修改。继承提供了代码重用的机制,减少了重复编写代码的工作量。
  3. 多态性(Polymorphism):多态性使得对象可以根据上下文表现出不同的行为。通过多态机制,可以使用统一的接口来处理不同类型的对象,而不需要针对每种类型编写特定的代码。这提高了代码的灵活性和可扩展性。
  4. 代码的可维护性和可扩展性:面向对象编程强调模块化和代码复用,通过将功能划分为独立的对象和类,使得代码更易于理解、测试和维护。当需求变化时,面向对象编程的结构和机制使得代码的修改和扩展更加简洁和可靠。

总的来说,面向对象编程提供了一种更加结构化、可扩展和可维护的编程范式。它通过封装、继承和多态等特性,使得代码更加模块化、灵活和易于理解。这些优点使得面向对象编程成为当今广泛采用的编程范式之一,被广泛应用于软件开发中。

(2)类和实例对象的语法

面向对象最重要的概念就是类(Class)和实例(Instance),必须牢记类是抽象的模板,比如Person类,而实例是根据类创建出来的一个个具体的“对象”。

在这里插入图片描述

# 声明类
class 类名:
    类属性...
    方法...
    
# 类的实例化
实例对象 = 类名() # 开辟一块独立的属于实例空间,将空间地址作为返回值

# 实例对象可以通过句点符号调用类属性和方法
实例对象.类属性
实例对象.方法(实参)
  1. 和变量名一样,类名本质上就是一个标识符,命名遵循变量规范。如果由单词构成类名,建议每个单词的首字母大写,其它字母小写。
  2. 冒号 + 缩进标识类的范围
  3. 无论是类属性还是类方法,对于类来说,它们都不是必需的,可以有也可以没有。另外,Python 类中属性和方法所在的位置是任意的,即它们之间并没有固定的前后次序。

在这里插入图片描述

# 声明类
class Dog:
    legs_num = 4
    has_hair = True
    has_tail = True

    def bark(self):
        print("狗狂吠")

    def bite(self):
        print("狗咬人")

    def fetch(self):
        print("狗捡球")


# 实例化对象
alex = Dog()
print(alex.legs_num)
alex.bark()
alex.bite()
# 实例化对象
peiQi = Dog()
# print(id(alex))
# print(id(peiQi))

print(id(alex.legs_num))
print(id(peiQi.legs_num))

print(id(alex.bark))
print(id(peiQi.bark))

【2】实例属性和实例方法

在这里插入图片描述

(1)实例属性

类变量(类属性)的特点是,所有类的实例化对象都同时共享类变量,也就是说,类变量在所有实例化对象中是作为公用资源存在的。实例属性是属于类的每个实例对象的特定属性。实例属性是在创建对象时赋予的,每个对象可以具有不同的实例属性值。

alex = Dog()
peiQi = Dog()
# 实例属性: 属于实例对象自己的属性
alex.name = "李杰"
alex.age = 10
peiQi.name = "武大郎"
peiQi.age = 20
# 问题1:
print(alex.name)
alex.age = 30
print(alex.age)
# 问题2:
print(peiQi.age)
# 问题3:
alex.bark()
alex.bark = "hello world"
# alex.bark()
peiQi.bark()
(2)实例方法和self

在 Python 的类定义中,self 是一个特殊的参数,用于表示类的实例对象自身。self 参数必须作为第一个参数出现在类的方法定义中,通常被约定为 self,但实际上你可以使用其他名称。

当你调用类的方法时,Python 会自动将调用该方法的实例对象传递给 self 参数。这样,你就可以通过 self 参数来引用和操作实例对象的属性和方法。

class Dog:
    legs_num = 4
    has_hair = True
    has_tail = True

    def eat(self):
        print(f"{self.name}正在吃东西。")

    def run(self):
        print(f"{self.name}正在跑。")

    def sleep(self):
        print(f"{self.name}正在睡觉。")

    def bark(self):
        print(f"{self.name}正在狂吠。")

    def show_info(self):
        print(f"名字:{self.name},品种:{self.breed},颜色:{self.color},年龄:{self.age}")


# 声明对象
bulldog = Dog()
# 赋值实例属性
bulldog.name = "小灰"
bulldog.breed = "斗牛犬"
bulldog.color = "浅灰色"
bulldog.age = 5

# 调用斗牛犬的行为
bulldog.eat()
bulldog.run()
bulldog.sleep()
bulldog.bark()
bulldog.show_info()

【3】构造方法__init__

在上节课的代码中,对象的属性是通过直接赋值给对象的实例属性来实现的,而不是在构造方法中进行初始化。这样做可能会导致以下问题:

  1. 代码冗余:每次创建对象时都需要分别为每个对象赋值实例属性,这会导致代码冗余和重复劳动。
  2. 可维护性差:如果类的属性发生变化或新增属性,需要修改多处代码来适应这些变化,而如果使用构造方法来初始化属性,则只需要在一个地方进行修改。

为了改进这种写法,可以使用构造方法来初始化对象的属性。构造方法在创建对象时自动调用,并可以接受参数来初始化对象的属性。

class Dog:

    def __init__(self, name, breed, color, age):
        self.name = name
        self.breed = breed
        self.color = color
        self.age = age

    def eat(self):
        print(f"{self.name}正在吃东西。")

    def run(self):
        print(f"{self.name}正在跑。")

    def sleep(self):
        print(f"{self.name}正在睡觉。")

    def bark(self):
        print(f"{self.name}正在狂吠。")

    def show_info(self):
        print(f"名字:{self.name},品种:{self.breed},颜色:{self.color},年龄:{self.age}")


# 声明对象
bulldog = Dog("小灰", "斗牛犬", "浅灰色", 5)

# 调用斗牛犬的行为

bulldog.bark()
bulldog.show_info()

# 声明对象
beagle = Dog("小黄", "小猎犬", "橘色", 6)

beagle.bark()
beagle.show_info()

实例化一个类的过程可以分为以下几个步骤:

  1. 创建一个新的对象(即开辟一块独立空间),它是类的实例化结果。
  2. 调用类的__init__方法,将新创建的对象作为第一个参数(通常命名为self),并传递其他参数(如果有的话)。
  3. __init__方法中,对对象进行初始化,可以设置对象的属性和执行其他必要的操作。
  4. 返回新创建的对象,使其成为类的实例。

在这里插入图片描述

在创建类时,我们可以手动添加一个 __init__() 方法,该方法是一个特殊的类实例方法,称为构造方法(或构造函数)。

__init__() 方法可以包含多个参数,但必须包含一个名为 self 的参数,且必须作为第一个参数。除了 self 参数外,还可以自定义一些参数,从而完成初始化的工作。

  1. 注意到__init__方法的第一个参数永远是self,表示创建的实例本身,因此,在__init__方法内部,就可以把各种属性绑定到self,因为self是指向创建的实例本身。
  2. 实例属性,实例变量,实例成员变量都是指的存在实例空间的属性

【4】一切皆对象

在python语言中,一切皆对象!

我们之前学习过的字符串,列表,字典等等数据都是一个个的类,我们用的所有数据都是一个个具体的实例对象。

区别就是,那些类是在解释器级别注册好的,而现在我们学习的是自定义类,但语法使用都是相同的。所以,我们自定义的类实例对象也可以和其他数据对象一样可以进行传参、赋值等操作。

  1. 自定义类对象是可变数据类型,我们可以在创建后对其进行修改,添加或删除属性和方法,而不会改变类对象的身份。
  2. 实例对象也是一等公民

【5】类对象、类属性以及类方法

(1)类对象

类对象是在Python中创建类时生成的对象,它代表了该类的定义和行为,存储着公共的类属性和方法

class Car(object):
    # 类属性
    total_cars = 0
    def __init__(self,make,model):
        self.make = make
        self.model = model

    # 实例方法
    def accelerate(self):
        print(f"一辆{self.make}{self.model}正在加速")

car1 = Car("Toyota", "Camry")

类对象.实例方法会怎么样?

(2)修改类属性
class Car:
    total_cars = 0

    def __init__(self, make, model):
        self.make = make
        self.model = model
        Car.total_cars += 1
        
    # 实例方法
    def accelerate(self):
        print(f"一辆{self.make}{self.model}正在加速")

    def display_total_cars(self):
        # print("Total cars:", self.total_cars)
        print("Total cars:", Car.total_cars)

    
# 创建两辆汽车
car1 = Car("Toyota", "Camry")
car1.display_total_cars()
car2 = Car("Honda", "Accord")
car1.display_total_cars()
(3)类方法

定义:使用装饰器@classmethod。第一个参数必须是当前类对象,该参数名一般约定为cls,通过它来传递类的属性和方法(不能传实例的属性和方法);

调用:类对象或实例对象都可以调用。

class Car:
    total_cars = 0

    def __init__(self, make, model):
        self.make = make
        self.model = model
        Car.total_cars += 1

    @classmethod
    def display_total_cars(cls):
        print(f"Total cars of {cls.__name__}: {cls.total_cars}")

# 创建两辆汽车
car1 = Car("Toyota", "Camry")
car2 = Car("Honda", "Accord")

# 显示车辆总数
Car.display_total_cars()  # 输出: Total cars of Car: 2

# 创建另一辆汽车
car3 = Car("Ford", "Mustang")

# 显示更新后的车辆总数
Car.display_total_cars()  # 输出: Total cars of Car: 3

【6】静态方法

定义:使用装饰器@staticmethod。参数随意,没有selfcls参数,但是方法体中不能使用类或实例的任何属性和方法;

调用:类对象或实例对象都可以调用。

class Cal():

    @staticmethod
    def add(x,y):
        return x+y

    @staticmethod
    def mul(x,y):
        return x*y

cal=Cal()
print(cal.add(1, 4))
or
print(Cal.add(3,4))

【7】练习案例

练习1:游戏案例

函数版本:

hero = {
    "name": "yuan",
    "health": 1000,
    "gold": 100,
    "defense": 10,
    "attack": 90,
    "level": 1,
    "weapon_list": []
}

# 测试攻击敌人
enemy = {
    "name": "alex",
    "health": 500,
    "defense": 5,
    "attack": 50,
    "gold": 100,
    "level": 1,
    "weapon_list": []
}


def attack_enemy(player, enemy):
    damage = player["attack"] - enemy["defense"]
    if damage > 0:
        enemy["health"] -= damage
        print(f"{player['name']}成功攻击了敌人{enemy['name']},造成了{damage}点伤害。")
    else:
        print(f"{player['name']}的攻击被敌人防御了。")


def buy_weapon(player, weapon):
    player["weapon_list"].append(weapon)
    print(f"{player['name']}购买装备{weapon}!")


def level_up(player):
    player["level"] += 1
    player["gold"] += 100
    print(f"{player['name']}升级了,奖励金币100!")


buy_weapon(hero, "屠龙刀")
attack_enemy(hero, enemy)
level_up(hero)

面向对象版本:

class Weapon:
    def __init__(self, name, attack, defense):
        self.name = name
        self.attack = attack
        self.defense = defense

    def upgrade(self):
        self.attack += 50
        self.defense += 50
        print(f"{self.name}的防御力增加了50点。")
        print(f"{self.name}的防御力增加了50点。")


class Player:

    def __init__(self, name, health=100, gold=100, defense=100, attack=100, level=1, weapon_list=[]):
        self.name = name
        self.health = health
        self.gold = gold
        self.defense = defense
        self.attack = attack
        self.level = level
        self.weapon_list = weapon_list

    def attack_enemy(self, enemy, weapon_index=None):
        if weapon_index is None:
            damage = self.attack - enemy.defense
        else:
            damage = self.weapon_list[weapon_index].attack - enemy.defense
        if damage > 0:
            enemy.health -= damage
            print(f"{self.name}成功攻击了敌人{enemy.name},造成了{damage}点伤害。")
        else:
            print(f"{self.name}的攻击被敌人防御了。")

    def buy_weapon(self, weapon):
        self.weapon_list.append(weapon)
        print(f"{self.name}购买装备{weapon.name}!")

    def level_up(self):
        self.level += 1
        self.gold += 100
        print(f"{self.name}升级了,奖励金币100!")


p1 = Player("YUAN")
p2 = Player("ALEX")

p1.attack_enemy(p2)
w1 = Weapon("屠龙刀", 1000, 300)
p1.buy_weapon(w1)
p1.attack_enemy(p2, 0)

案例2:客户关系管理系统
customers = [
    {
        "name": "John Smith",
        "age": 35,
        "contact": "[email protected]"
    },
    {
        "name": "Jane Doe",
        "age": 28,
        "contact": "[email protected]"
    },
    {
        "name": "Michael Johnson",
        "age": 42,
        "contact": "[email protected]"
    }
]


def add_customer():
    print("添加客户")


def delete_customer():
    print("删除客户")


def update_customer():
    print("修改客户")


def query_customer():
    print("查询客户")


class CustomersManager:
    customers = [
        {
            "name": "John Smith",
            "age": 35,
            "contact": "[email protected]"
        },
        {
            "name": "Jane Doe",
            "age": 28,
            "contact": "[email protected]"
        },
        {
            "name": "Michael Johnson",
            "age": 42,
            "contact": "[email protected]"
        }
    ]

    def add_customer(self):
        print("添加客户")

    def delete_customer(self):
        print("删除客户")

    def update_customer(self):
        print("修改客户")

    def query_customer(self):
        print("查询客户")


cm = CustomersManager()
cm.add_customer()
cm.delete_customer()
cm.update_customer()
cm.query_customer()

案例3:购物车案例

函数版本:

def add_to_cart(cart, food):
    cart.append(food)
    print(f"Added {food} to the cart.")

def view_cart(cart):
    if cart:
        print("Cart items:")
        for food in cart:
            print(food)
    else:
        print("Cart is empty.")

def checkout(cart):
    if cart:
        print("Checkout:")
        total_price = 0
        for food in cart:
            # 假设每个食物的价格为 10 元
            total_price += 10
        print(f"Total price: {total_price} yuan")
        print("Thank you for your order!")
        cart.clear()
    else:
        print("Cart is empty. Nothing to checkout.")

# 初始化购物车
cart = []

# 添加食物到购物车
add_to_cart(cart, "Pizza")
add_to_cart(cart, "Burger")
add_to_cart(cart, "Fries")

# 查看购物车
view_cart(cart)

# 结算购物车
checkout(cart)

# 再次查看购物车
view_cart(cart)

面向对象版本:

class ShoppingCart:
    def __init__(self):
        self.cart = []

    def add_to_cart(self, food):
        self.cart.append(food)
        print(f"Added {food} to the cart.")

    def view_cart(self):
        if self.cart:
            print("Cart items:")
            for food in self.cart:
                print(food)
        else:
            print("Cart is empty.")

    def checkout(self):
        if self.cart:
            print("Checkout:")
            total_price = 0
            for food in self.cart:
                # 假设每个食物的价格为 10 元
                total_price += 10
            print(f"Total price: {total_price} yuan")
            print("Thank you for your order!")
            self.cart.clear()
        else:
            print("Cart is empty. Nothing to checkout.")

# 创建购物车实例
cart = ShoppingCart()

# 添加食物到购物车
cart.add_to_cart("Pizza")
cart.add_to_cart("Burger")
cart.add_to_cart("Fries")

# 查看购物车
cart.view_cart()

# 结算购物车
cart.checkout()

# 再次查看购物车
cart.view_cart()

面向对象进阶

一、面向对象之继承

面向对象的编程带来的主要好处之一是代码的重用,实现这种重用的方法之一是通过继承机制。通过继承创建的新类称为子类派生类,被继承的类称为基类父类超类

class 派生类名(基类名)
    ...
【1】继承的基本使用

继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。通过使用继承我们能够非常方便地复用以前的代码,能够大大的提高开发的效率。

实际上继承者是被继承者的特殊化,它除了拥有被继承者的特性外,还拥有自己独有得特性。例如猫有抓老鼠、爬树等其他动物没有的特性。同时在继承关系中,继承者完全可以替换被继承者,反之则不可以,例如我们可以说猫是动物,但不能说动物是猫就是这个道理,其实对于这个我们将其称之为“向上转型”。

诚然,继承定义了类如何相互关联,共享特性。对于若干个相同或者相识的类,我们可以抽象出他们共有的行为或者属相并将其定义成一个父类或者超类,然后用这些类继承该父类,他们不仅可以拥有父类的属性、方法还可以定义自己独有的属性或者方法。

同时在使用继承时需要记住三句话:

1、子类拥有父类非私有化的属性和方法。

2、子类可以拥有自己属性和方法,即子类可以对父类进行扩展。

3、子类可以用自己的方式实现父类的方法。(下面会介绍)。

# 无继承方式

class Dog:

    def eat(self):
        print("eating...")

    def sleep(self):
        print("sleep...")

    def swimming(self):
        print("swimming...")

class Cat:

    def eat(self):
        print("eating...")

    def sleep(self):
        print("sleep...")

    def climb_tree(self):
        print("climb_tree...")


# 继承方式

class Animal:

    def eat(self):
        print("eating...")

    def sleep(self):
        print("sleep...")


class Dog(Animal):

    def swimming(self):
        print("toshetou...")

class Cat(Animal):

    def climb_tree(self):
        print("climb_tree...")


alex = Dog()
alex.run()
【2】重写父类方法和调用父类方法
class Person(object):

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

    def sleep(self):
        print("基类sleep...")


class Emp(Person):

   # def __init__(self,name,age,dep):
   #      self.name = name
   #      self.age = age
   #      self.dep = dep

   def __init__(self, name, age, dep):

       # Person.__init__(self,name,age)
       super().__init__(name,age)
       self.dep = dep


   def sleep(self):

        if "不在公司":
            # print("子类sleep...")
            # 调用父类方法
            # 方式1 :父类对象调用 父类对象.方法(self,其他参数)
            # Person.sleep(self)
            # 方式2: super关键字 super(子类对象,self).方法(参数)or super().方法(参数)
            super().sleep()



yuan = Emp("yuan",18,"教学部")
yuan.sleep()
print(yuan.dep)

# 测试题:

class Base:
    def __init__(self):
        self.func()
    def func(self):
        print('in base')

class Son(Base):
    def func(self):
        print('in son')

s = Son()
【3】多重继承

如果在继承元组中列了一个以上的类,那么它就被称作"多重继承" 。派生类的声明,与他们的父类类似,继承的基类列表跟在类名之后,如下所示:

class SubClassName (ParentClass1[, ParentClass2, ...]):
    ...

多继承有什么意义呢?还拿上面的例子来说,蝙蝠和鹰都可以飞,飞的功能就重复定义了。

class Animal:

    def eat(self):
        print("eating...")

    def sleep(self):
        print("sleep...")

class Eagle(Animal):

    def fly(self):
        print("fly...")

class Bat(Animal):

    def fly(self):
        print("fly...")

有同学肯定想那就放到父类Animal中,可是那样的话其他不会飞的动物还怎么继承Animal呢?所以,这时候多重继承就发挥功能了:

class Fly:
    def fly(self):
        print("fly...")
 
class Eagle(Animal,Fly):
    pass
 
class Bat(Animal,Fly):
    pass
【4】 type 和isinstance方法
class Animal:

    def eat(self):
        print("eating...")

    def sleep(self):
        print("sleep...")


class Dog(Animal):
    def swim(self):
        print("swimming...")

alex = Dog()
mjj = Dog()

print(isinstance(alex,Dog))
print(isinstance(alex,Animal))
print(type(alex))
【4】dir()方法和__dict__属性

dir(obj)可以获得对象的所有属性(包含方法)列表, 而obj.__dict__对象的自定义属性字典

注意事项:

  1. dir(obj)获取的属性列表中,方法也认为属性的一种。返回的是list
  2. obj.__dict__只能获取自己自定义的属性,系统内置属性无法获取。返回是dict
class Student:

    def __init__(self, name, score):
        self.name = name
        self.score = score

    def test(self):
        pass


yuan = Student("yuan", 100)
print("获取所有的属性列表")
print(dir(yuan))

print("获取自定义属性字段")
print(yuan.__dict__)

其中,类似__xx__的属性和方法都是有特殊用途的。如果调用len()函数视图获取一个对象的长度,其实在len()函数内部会自动去调用该对象的__len__()方法

二、面向对象之封装

三、面向对象之多态

四、异常机制

首先我们要理解什么叫做**"异常”**?

  • 在程序运行过程中,总会遇到各种各样的问题和错误。
  • 有些错误是我们编写代码时自己造成的:比如语法错误、调用错误,甚至逻辑错误。
  • 还有一些错误,则是不可预料的错误,但是完全有可能发生的:比如文件不存在、磁盘空间不足、网络堵塞、系统错误等等。

这些导致程序在运行过程中出现异常中断和退出的错误,我们统称为异常。大多数的异常都不会被程序处理,而是以错误信息的形式展现出来。

异常的分类:

  • 异常有很多种类型,Python内置了几十种常见的异常,无需特别导入,直接就可使用。
  • 需要注意的是,所有的异常都是异常类,首字母是大写的!

异常的危害:

  • 如果程序中一旦出现了异常的语句代码,则该异常就会立即中断程序的运行!

  • 因此:为了保证程序的正常运行,提高程序健壮性和可用性。我们应当尽量考虑全面,将可能出现的异常进行处理,而不是留在那里,任由其发生。

【1】基本语法

异常的基本结构:try except

# (1)通用异常
try:
    pass  # 正常执行语句
except Exception as ex:
    pass  # 异常处理语句


# (2)指定异常
try:
     pass  # 正常执行语句
except <异常名>:
     pass  # 异常处理语句
        
#(3) 捕获多个异常
# 捕获多个异常有两种方式,第一种是一个except同时处理多个异常,不区分优先级:
try:
     pass  # 正常执行语句
 
except (<异常名1>, <异常名2>, ...):
 
      pass  # 异常处理语句
    
# 第二种是区分优先级的:    
try:
     pass  # 正常执行语句
except <异常名1>:
      pass  # 异常处理语句1
except <异常名2>:
      pass  # 异常处理语句2
except <异常名3>:
      pass  # 异常处理语句3
    
# 异常嵌套
try:
    try:
        with open("abc") as f:
            pass
    except NameError as e:
        print(e)
except OSError as e:
    print("OSError:",e.strerror)

机制说明:

  • 首先,执行try子句(在关键字try和关键字except之间的语句)
  • 如果没有异常发生,忽略except子句,try子句执行后结束。
  • 如果在执行try子句的过程中发生了异常,那么try子句余下的部分将被忽略。如果异常那么对应的except子句将被执行。
  • 在Python的异常中,有一个通用异常:Exception,它可以捕获任意异常。
【2】finally
try:
    pass  # 正常执行语句
except Exception as e:
    pass  # 异常处理语句
finally:
    pass  # 无论是否发生异常一定要执行的语句,比如关闭文件,数据库或者socket
【3】raise语句

很多时候,我们需要主动抛出一个异常。Python内置了一个关键字raise,可以主动触发异常。

raise可以抛出自定义异常,我们已将在前面看到了python内置的一些常见的异常类型。大多数情况下,内置异常已经够用了。但是有时候你还是需要自定义一些异常:自定义异常应该继承Exception类,直接继承或者间接继承都可以,例如:

# 1.用户自定义异常类型
class TooLongExceptin(Exception):
    "this is user's Exception for check the length of name "

    def __init__(self, len):
        self.len = len

    def __str__(self):
        return "输入姓名长度是" + str(self.len) + ",超过长度了"
try:
    name = input("enter your name:")
    if len(name) > 5:
        raise TooLongExceptin(len(name))
    else:
        print(name)

except TooLongExceptin as error:  # 这里异常类型是用户自定义的
    print("打印异常信息:", error)
;