Skip to content

面向对象 ​

image-20240726165726691

成员变量成员方法 ​

成员变量 ​

  • 定义在类内部的变量称之为成员变量,用法与正常变量一致。

成员方法 ​

​ 定义在类内部的函数称之为方法,与函数存在细微区别。

python
# 函数
# 形参可以为0-N个
def 函数名(形参1,形参2,..,形参N):
    函数体

# 方法
# 形参可以为0-N个
# self关键字必须填写
def 方法名(self,形参1,形参2,..,形参N):
    方法体
# 函数
# 形参可以为0-N个
def 函数名(形参1,形参2,..,形参N):
    函数体

# 方法
# 形参可以为0-N个
# self关键字必须填写
def 方法名(self,形参1,形参2,..,形参N):
    方法体
  • self 关键字在成员方法定义的时候必须填写,表示类对象自身

  • 在方法内部,想要访问类的成员变量,必须使用 self

    c
    class Student:
        name = None
    
        # 调用say_hi1时正常打印
        def say_hi1(self):
            print(f"大家好,我叫{self.name}")
    
        # 调用say_hi2时报错,'name' is not defined
        def say_hi2(self):
            print(f"大家好,我叫{name}")
    class Student:
        name = None
    
        # 调用say_hi1时正常打印
        def say_hi1(self):
            print(f"大家好,我叫{self.name}")
    
        # 调用say_hi2时报错,'name' is not defined
        def say_hi2(self):
            print(f"大家好,我叫{name}")

构造方法 ​

  • 在类可以使用:__init__()方法,即构造方法,快速为对象赋值。

    python
    # 定义类
    class Student:
        name = None  # 姓名
        sex = None  # 性别
        age = None  # 年龄
    
        def __init__(self, name, sex, age):
            self.name = name
            self.sex = sex
            self.age = age
    
    # 创建对象并赋值
    stu_1 = Student("李白", "男", 1000)
    
    # 简化形式:可以省略成员属性定义,但仍可调用
    class Student:
    
        def __init__(self, name, sex, age):
            self.name = name  # 姓名
            self.sex = sex  # 性别
            self.age = age  # 年龄
    
    # 创建对象并赋值
    stu_1 = Student("李白", "男", 1000)
    # 定义类
    class Student:
        name = None  # 姓名
        sex = None  # 性别
        age = None  # 年龄
    
        def __init__(self, name, sex, age):
            self.name = name
            self.sex = sex
            self.age = age
    
    # 创建对象并赋值
    stu_1 = Student("李白", "男", 1000)
    
    # 简化形式:可以省略成员属性定义,但仍可调用
    class Student:
    
        def __init__(self, name, sex, age):
            self.name = name  # 姓名
            self.sex = sex  # 性别
            self.age = age  # 年龄
    
    # 创建对象并赋值
    stu_1 = Student("李白", "男", 1000)
  • 在创建类对象(构造类)的时候,会自动执行,将传入参数自动传递给init方法使用。

  • 构造方法也是成员方法,定义时也需要在参数列表中提供:self

  • 变量定义在构造方法内部,如果要成为成员变量,需要用 self 来表示,例如 self.name

  • 使用了构造方法,创建对象时必须传参否则会报错

魔术方法 ​

方法功能
__init__构造方法,可用于创建类对象的时候设置初始化行为
__str__字符串方法,用于实现类对象转字符串的行为
__lt__用于 2 个类对象进行小于(<)或大于(>)比较
__le__用于 2 个类对象进行小于等于(<=)或大于等于(>=)比较
__eq__用于 2 个类对象进行相等(==)比较
  • str方法

    • 当直接打印类对象时,打印的是对象的内存地址,用处不大。
    • 我们可以通过__str__方法,自定义控制打印类对象时输出的内容。
    python
    class Student:
    
        def __init__(self, name, age):
            self.name = name  # 姓名
            self.age = age  # 年龄
    
    	# 自定义打印输出内容
        def __str__(self):
            return f"Student对象,name={self.name},age={self.age}"
    
    stu_1 = Student("李白", 1000)
    print(stu_1)
    # 打印 Student对象,name=李白,age=1000
    class Student:
    
        def __init__(self, name, age):
            self.name = name  # 姓名
            self.age = age  # 年龄
    
    	# 自定义打印输出内容
        def __str__(self):
            return f"Student对象,name={self.name},age={self.age}"
    
    stu_1 = Student("李白", 1000)
    print(stu_1)
    # 打印 Student对象,name=李白,age=1000
  • lt方法

    • 直接对 2 个对象进行比较是不可以的,会报错。
    • 在类中实现__lt__方法即可完成:小于符号 和 大于符号 2 种比较
    python
    class Student:
    
        def __init__(self, name, age):
            self.name = name  # 姓名
            self.age = age  # 年龄
    
        def __lt__(self, other):
            return self.age < other.age
    
    
    stu_1 = Student("李白", 1000)
    stu_2 = Student("罗辑", 300)
    print(stu_1 > stu_2) # 打印 True
    class Student:
    
        def __init__(self, name, age):
            self.name = name  # 姓名
            self.age = age  # 年龄
    
        def __lt__(self, other):
            return self.age < other.age
    
    
    stu_1 = Student("李白", 1000)
    stu_2 = Student("罗辑", 300)
    print(stu_1 > stu_2) # 打印 True

三大特性 ​

面向对象包含 3 大主要特性:封装,继承,多态

封装 ​

私有成员 ​

在类中提供仅供内部使用的属性和方法,无法被对象调用

  • 基本语法:

    • 私有成员变量:变量名以__开头(2 个下划线)
    • 私有成员方法:方法名以__开头(2 个下划线)
    python
    class Student:
        name = None  # 普通成员变量
        __age = None  # 私有成员变量
    
        # 普通成员方法
        def say_hi(self):
            print("你好")
    
        # 私有成员方法
        def __DNA(self):
            print("DNA数量")
    class Student:
        name = None  # 普通成员变量
        __age = None  # 私有成员变量
    
        # 普通成员方法
        def say_hi(self):
            print("你好")
    
        # 私有成员方法
        def __DNA(self):
            print("DNA数量")
  • 仅在成员内部可以使用

    python
    class Student:
        name = None  # 普通成员变量
        __age = 16  # 私有成员变量
    
        # 普通成员方法
        def show(self):
            self.__check()  # 在类中使用私有成员变量
            if self.__age > 18: # 在类中使用私有成员变量
                print("成年人")
            else:
                print("未成年")
    
        # 私有成员方法
        def __check(self):
            print("自检")
    class Student:
        name = None  # 普通成员变量
        __age = 16  # 私有成员变量
    
        # 普通成员方法
        def show(self):
            self.__check()  # 在类中使用私有成员变量
            if self.__age > 18: # 在类中使用私有成员变量
                print("成年人")
            else:
                print("未成年")
    
        # 私有成员方法
        def __check(self):
            print("自检")

继承 ​

单继承 ​
  • 基本语法:
python
class 类名(父类名):
    类内容体
12
class 类名(父类名):
    类内容体
12
  • 基本使用:
python
# 待继承的类
class Phone:
    producer = "apple"  # 厂商

    def call_by_4g(self):
        print("4g通话")

# 继承Phone
class Phone2022(Phone):
    face_id = True  # 面部识别

    def call_by_5g(self):
        print("2022最新5G通话")
# 创建对象
phone = Phone2022()
# 使用
print(phone.producer) # 可调用 继承自Phone的成员变量
print(phone.face_id) # 可调用 自身的成员变量
phone.call_by_4g() # 可调用 继承自Phone的成员方法
phone.call_by_5g() # 可调用 自身的成员方法
# 待继承的类
class Phone:
    producer = "apple"  # 厂商

    def call_by_4g(self):
        print("4g通话")

# 继承Phone
class Phone2022(Phone):
    face_id = True  # 面部识别

    def call_by_5g(self):
        print("2022最新5G通话")
# 创建对象
phone = Phone2022()
# 使用
print(phone.producer) # 可调用 继承自Phone的成员变量
print(phone.face_id) # 可调用 自身的成员变量
phone.call_by_4g() # 可调用 继承自Phone的成员方法
phone.call_by_5g() # 可调用 自身的成员方法
多继承 ​
  • 一个类也可以继承多个类
  • 多个父类中,如果有同名的成员,默认以继承顺序(从左到右)为优先级。即:后继承的被先继承的覆盖
  • 基本语法:
python
class 类名(父类1,父类2,...,父类N):
    类内容体
12
class 类名(父类1,父类2,...,父类N):
    类内容体
12
  • 使用示例:
python
class Phone:
    producer = "apple"  # 厂商

class Camera:
    producer = "suoni"  # 厂商

class Phone2022(Phone, Camera):
    face_id = True  # 面部识别

    def call_by_5g(self):
        print("2022最新5G通话")

phone = Phone2022()

print(phone.producer)  # 打印结果为apple而非suoni
class Phone:
    producer = "apple"  # 厂商

class Camera:
    producer = "suoni"  # 厂商

class Phone2022(Phone, Camera):
    face_id = True  # 面部识别

    def call_by_5g(self):
        print("2022最新5G通话")

phone = Phone2022()

print(phone.producer)  # 打印结果为apple而非suoni
复写 ​
  • 子类继承父类的成员属性和成员方法后,如果对其“不满意”,那么可以进行复写。即:在子类中重新定义同名的属性或方法。
  • 一旦复写父类成员,那么类对象调用成员的时候,就会调用复写后的新成员
python
class Phone2021:
    producer = "apple"  # 厂商

    def call_by_5g(self):
        print("2021版5G通话")

class Phone2022(Phone2021):
    face_id = True  # 面部识别

    def call_by_5g(self):
        print("2022升级版5G通话")

phone = Phone2022()
phone.call_by_5g()  # 打印 2022升级版5G通话
class Phone2021:
    producer = "apple"  # 厂商

    def call_by_5g(self):
        print("2021版5G通话")

class Phone2022(Phone2021):
    face_id = True  # 面部识别

    def call_by_5g(self):
        print("2022升级版5G通话")

phone = Phone2022()
phone.call_by_5g()  # 打印 2022升级版5G通话
  • 如果需要使用被复写的父类的成员,只能在子类内通过如下方式调用父类的同名成员:

    • 方式一:使用父类名调用

      使用成员变量:父类名.成员变量 使用成员方法:父类名.成员方法(self)

    • 方式二:使用super()调用

      使用成员变量:super().成员变量 使用成员方法:super().成员方法()

    • 使用实例

      python
      class Phone2021:
          producer = "apple"  # 厂商
      
          def call_by_5g(self):
              print("2021版5G通话")
      
      class Phone2022(Phone2021):
          face_id = True  # 面部识别
      
          def call_by_5g(self):
              # 方式一调用
              print(Phone2021.producer)  # 打印 apple
              Phone2021.call_by_5g(self)# 打印 2021版5G通话
              # 方式二调用
              print(super().producer)# 打印 apple
              super().call_by_5g()# 打印 2021版5G通话
      class Phone2021:
          producer = "apple"  # 厂商
      
          def call_by_5g(self):
              print("2021版5G通话")
      
      class Phone2022(Phone2021):
          face_id = True  # 面部识别
      
          def call_by_5g(self):
              # 方式一调用
              print(Phone2021.producer)  # 打印 apple
              Phone2021.call_by_5g(self)# 打印 2021版5G通话
              # 方式二调用
              print(super().producer)# 打印 apple
              super().call_by_5g()# 打印 2021版5G通话

多态 ​

多种状态,即完成某个行为时,使用不同的对象会得到不同的状态

多态常作用在继承关系上,函数(方法)形参声明接收父类对象,实际传入父类的子类对象进行工作,即

  • 以父类做定义声明
  • 以子类做实际工作
  • 用以获得同一行为, 不同状态

image-20240726170121103

抽象类(接口) ​

抽象类就好比定义一个标准,包含了一些抽象的方法,要求子类必须实现

  • 抽象类:包含抽象方法的类
  • 抽象方法:没有具体实现的方法(只含 pass)称之为抽象方法
  • pass是占位语句,用来保证函数(方法)或类定义的完整性,表示无内容,空的意思

  • 多用于做顶层设计(设计标准),以便子类做具体实现。是对子类的一种软性约束,要求子类必须复写(实现)父类的一些方法

    并配合多态使用,获得不同的工作状态。

类型注解 ​

变量类型注解 ​

基础类型 ​

  • 整数类型注解
python
var_1: int = 1314
var_1: int = 1314
  • 浮点数类型注解
python
var_2: float = 5.21
var_2: float = 5.21
  • 布尔类型注解
python
var_3: bool = True
var_3: bool = True
  • 字符串类型注解
python
var_4: str = "hhybd"
var_4: str = "hhybd"

类对象 ​

python
# 定义学生类
class Student:
    pass

stu: Student = Student()  # 学生类类型注解
# 定义学生类
class Student:
    pass

stu: Student = Student()  # 学生类类型注解

数据容器 ​

  • 列表类型注解

    • 方式一:

      python
      my_list: list = [1, 2, 3]
      my_list: list = [1, 2, 3]
    • 方式二,list[基础类型]:

      python
      my_list: list[int] = [1, 2, 3]
      my_list: list[int] = [1, 2, 3]
  • 元组类型注解

    • 方式一:

      python
      my_tuple: tuple = (1, 2, 3)
      my_tuple: tuple = (1, 2, 3)
    • 方式二,元组类型需要将每一个元素都标记出来:

      python
      my_tuple: tuple[str, int, bool] = ("bd", 521, True)
      my_tuple: tuple[str, int, bool] = ("bd", 521, True)
  • 集合类型注解

    • 方式一:

      python
      my_set: set = {1, 2, 3}
      my_set: set = {1, 2, 3}
    • 方式二,set[基础类型]:

      python
      my_set: set[int] = {1, 2, 3}
      my_set: set[int] = {1, 2, 3}
  • 字典类型注解

    • 方式一:

      python
      my_dict: dict = {"hhbdy": 250}
      my_dict: dict = {"hhbdy": 250}
    • 方式二,dict[键类型,值类型]:

      python
      my_dict: dict[str, int] = {"hhbdy": 250}
      my_dict: dict[str, int] = {"hhbdy": 250}

其他语法格式 ​

stu = Student()  # type:Student
var_1 = 123  # type:int
my_list = [1, 2, 3]  # type:list
my_set = {1, 2, 3}  # type:set[int]
stu = Student()  # type:Student
var_1 = 123  # type:int
my_list = [1, 2, 3]  # type:list
my_set = {1, 2, 3}  # type:set[int]

进阶类型注解(Protocol / TypedDict / Literal) ​

Protocol(结构鸭子类型) ​

python
from typing import Protocol

# 定义协议(类似接口)
class Drawable(Protocol):
    def draw(self) -> str: ...

# 无需显式继承,只要实现了协议方法即可
class Circle:
    def draw(self) -> str:
        return "画一个圆"

class Square:
    def draw(self) -> str:
        return "画一个正方形"

def render(obj: Drawable):
    print(obj.draw())

render(Circle())   # 正确
render(Square())   # 正确
# render(123)      # mypy 类型检查会报错
from typing import Protocol

# 定义协议(类似接口)
class Drawable(Protocol):
    def draw(self) -> str: ...

# 无需显式继承,只要实现了协议方法即可
class Circle:
    def draw(self) -> str:
        return "画一个圆"

class Square:
    def draw(self) -> str:
        return "画一个正方形"

def render(obj: Drawable):
    print(obj.draw())

render(Circle())   # 正确
render(Square())   # 正确
# render(123)      # mypy 类型检查会报错

TypedDict(字典类型约束) ​

python
from typing import TypedDict, NotRequired  # NotRequired 3.11+

class UserDict(TypedDict):
    name: str
    age: int
    email: NotRequired[str]  # 可选字段

# 类型安全的字典
user: UserDict = {"name": "Alice", "age": 30}
user["age"] = "30"  # mypy 会报错:类型不匹配
from typing import TypedDict, NotRequired  # NotRequired 3.11+

class UserDict(TypedDict):
    name: str
    age: int
    email: NotRequired[str]  # 可选字段

# 类型安全的字典
user: UserDict = {"name": "Alice", "age": 30}
user["age"] = "30"  # mypy 会报错:类型不匹配

Literal(字面量类型) ​

python
from typing import Literal

def set_mode(mode: Literal["dev", "prod", "test"]) -> str:
    return f"当前模式: {mode}"

set_mode("dev")   # 正确
# set_mode("staging")  # mypy 会报错

# 联合字面量
def http_status(code: Literal[200, 201, 400, 404, 500]) -> str:
    ...
from typing import Literal

def set_mode(mode: Literal["dev", "prod", "test"]) -> str:
    return f"当前模式: {mode}"

set_mode("dev")   # 正确
# set_mode("staging")  # mypy 会报错

# 联合字面量
def http_status(code: Literal[200, 201, 400, 404, 500]) -> str:
    ...

Final(不可覆盖) ​

python
from typing import Final

MAX_SIZE: Final = 100
# MAX_SIZE = 200  # mypy 会报错

class Config:
    VERSION: Final = "1.0"
from typing import Final

MAX_SIZE: Final = 100
# MAX_SIZE = 200  # mypy 会报错

class Config:
    VERSION: Final = "1.0"

assert_never(穷尽检查) ​

python
from typing import assert_never

def process(value: int | str):
    match value:
        case int():
            print(f"整数: {value}")
        case str():
            print(f"字符串: {value}")
        case _:
            assert_never(value)  # 如果未来新增类型,编译时报错
from typing import assert_never

def process(value: int | str):
    match value:
        case int():
            print(f"整数: {value}")
        case str():
            print(f"字符串: {value}")
        case _:
            assert_never(value)  # 如果未来新增类型,编译时报错