Python系列课(9)——面向对象

目录

一、初识对象

[1. 为什么使用对象](#1. 为什么使用对象)

[2. 类和对象的概念](#2. 类和对象的概念)

二、成员方法

[1. 类的定义](#1. 类的定义)

[2. self关键字的作用](#2. self关键字的作用)

三、类和对象

[1. 使用类描述现实事物](#1. 使用类描述现实事物)

[2. 类和对象的关系](#2. 类和对象的关系)

四、构造方法(init)

[1. 基本使用](#1. 基本使用)

[2. 构造方法注意事项](#2. 构造方法注意事项)

练习:学生信息录入

五、其它内置方法(魔术方法)

[1. str - 字符串方法](#1. str - 字符串方法)

[2. lt - 小于比较方法](#2. lt - 小于比较方法)

[3. le - 小于等于比较方法](#3. le - 小于等于比较方法)

[4. eq - 相等比较方法](#4. eq - 相等比较方法)

六、封装

[1. 封装的概念](#1. 封装的概念)

[2. 私有成员](#2. 私有成员)

练习:设计带有私有成员的手机

七、继承

[1. 单继承](#1. 单继承)

[2. 多继承](#2. 多继承)

[3. 多继承同名方法优先级](#3. 多继承同名方法优先级)

[4. pass关键字](#4. pass关键字)

[5. 复写父类成员和调用父类](#5. 复写父类成员和调用父类)

八、类型注解

[1. 变量类型注解](#1. 变量类型注解)

[2. 函数(方法)类型注解](#2. 函数(方法)类型注解)

九、多态

[1. 多态的概念](#1. 多态的概念)

[2. 抽象类(接口)](#2. 抽象类(接口))

十、综合案例

数据分析案例:计算每日销售额

十一、面向对象速查表

类定义与对象

封装

继承

类型注解

多态


一、初识对象

1. 为什么使用对象

使用变量记录数据时,数据组织混乱、不统一。使用对象可以像设计表格一样组织数据。

2. 类和对象的概念

生活概念 程序概念
设计表格 设计类(class)
打印表格 创建对象
填写表格 对象属性赋值
复制代码
# 设计类(设计表格)
class Student:
    name = None   # 成员变量
    age = None
​
# 创建对象(打印表格)
stu1 = Student()
stu2 = Student()
​
# 对象属性赋值(填写表格)
stu1.name = "张三"
stu1.age = 18
stu2.name = "李四"
stu2.age = 20
​
print(stu1.name, stu1.age)   # 张三 18
print(stu2.name, stu2.age)   # 李四 20

二、成员方法

1. 类的定义

复制代码
class 类名:
    成员变量 = 值
    
    def 成员方法(self, 参数):
        方法体

2. self关键字的作用

  • self表示类对象自身

  • 通过self可以访问类的成员变量

  • self在参数列表中,但传参时可以忽略

复制代码
class Student:
    name = None
    age = None
    
    def say_hello(self):
        print(f"你好,我是{self.name}")
    
    def introduce(self, msg):
        print(f"{self.name}说:{msg}")
​
# 使用
stu = Student()
stu.name = "张三"
stu.say_hello()        # 你好,我是张三
stu.introduce("大家好")  # 张三说:大家好

三、类和对象

1. 使用类描述现实事物

复制代码
class Phone:
    # 属性(成员变量)
    brand = None
    price = 0
    
    # 行为(成员方法)
    def call(self):
        print(f"{self.brand}手机正在通话...")
    
    def send_sms(self, number, msg):
        print(f"给{number}发送短信:{msg}")
​
# 创建对象并使用
iphone = Phone()
iphone.brand = "Apple"
iphone.price = 7999
iphone.call()           # Apple手机正在通话...
iphone.send_sms("12345", "你好")  # 给12345发送短信:你好

2. 类和对象的关系

  • 类是程序中的"设计图纸"

  • 对象是基于图纸生产的具体实体

复制代码
# 同一个类可以创建多个对象
phone1 = Phone()
phone1.brand = "华为"
phone2 = Phone()
phone2.brand = "小米"
​
print(phone1.brand)   # 华为
print(phone2.brand)   # 小米

四、构造方法(init

1. 基本使用

构造方法在创建类对象时自动执行,并接收传入的参数。

复制代码
class Student:
    # 构造方法
    def __init__(self, name, age):
        print("构造方法被调用了")
        self.name = name   # 使用self定义成员变量
        self.age = age
​
# 创建对象时自动调用构造方法
stu = Student("张三", 18)
print(stu.name)   # 张三
print(stu.age)    # 18

2. 构造方法注意事项

  • 名称必须是 __init__(前后各2个下划线)

  • 不要忘记 self 参数

  • 使用 self.变量名 定义成员变量

复制代码
class Person:
    def __init__(self, name, age, city):
        self.name = name
        self.age = age
        self.city = city
        print(f"已创建:{name},{age}岁,来自{city}")
​
# 一行代码完成对象创建和属性赋值
p = Person("李四", 20, "北京")
# 输出:已创建:李四,20岁,来自北京

练习:学生信息录入

复制代码
class Student:
    def __init__(self, name, age, address):
        self.name = name
        self.age = age
        self.address = address
​
# 循环录入学生信息
students = []
for i in range(3):
    print(f"\n请输入第{i+1}个学生信息:")
    name = input("姓名:")
    age = int(input("年龄:"))
    address = input("地址:")
    stu = Student(name, age, address)
    students.append(stu)
​
# 输出信息
print("\n=== 学生信息列表 ===")
for stu in students:
    print(f"姓名:{stu.name},年龄:{stu.age},地址:{stu.address}")

假设输入:

复制代码
请输入第1个学生信息:
姓名:张三
年龄:18
地址:北京
请输入第2个学生信息:
姓名:李四
年龄:19
地址:上海
请输入第3个学生信息:
姓名:王五
年龄:20
地址:广州

输出:

复制代码
=== 学生信息列表 ===
姓名:张三,年龄:18,地址:北京
姓名:李四,年龄:19,地址:上海
姓名:王五,年龄:20,地址:广州

五、其它内置方法(魔术方法)

1. __str__ - 字符串方法

控制对象转换为字符串时的输出。

复制代码
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 = Student("张三", 18)
print(stu)   # Student(name=张三, age=18)
print(str(stu))  # Student(name=张三, age=18)

2. __lt__ - 小于比较方法

实现 <> 比较运算符。

复制代码
class Student:
    def __init__(self, name, score):
        self.name = name
        self.score = score
    
    def __lt__(self, other):
        return self.score < other.score
​
s1 = Student("张三", 85)
s2 = Student("李四", 92)
​
print(s1 < s2)   # True (85 < 92)
print(s2 > s1)   # True (92 > 85)

3. __le__ - 小于等于比较方法

实现 <=>= 比较运算符。

复制代码
class Student:
    def __init__(self, name, score):
        self.name = name
        self.score = score
    
    def __le__(self, other):
        return self.score <= other.score
​
s1 = Student("张三", 85)
s2 = Student("李四", 85)
​
print(s1 <= s2)   # True (85 <= 85)
print(s2 >= s1)   # True (85 >= 85)

4. __eq__ - 相等比较方法

实现 == 比较运算符。

复制代码
class Student:
    def __init__(self, name, score):
        self.name = name
        self.score = score
    
    def __eq__(self, other):
        return self.score == other.score
​
s1 = Student("张三", 85)
s2 = Student("李四", 85)
s3 = Student("王五", 90)
​
print(s1 == s2)   # True (分数相同)
print(s1 == s3)   # False (分数不同)

六、封装

1. 封装的概念

将现实世界事物的属性和行为封装到类中,描述为成员变量和成员方法。

2. 私有成员

__(双下划线)开头命名的成员变量或方法,变成私有成员。

复制代码
class Phone:
    # 私有成员变量
    __is_5g_enable = False
    
    # 私有成员方法
    def __check_5g(self):
        if self.__is_5g_enable:
            print("5g开启")
        else:
            print("5g关闭,使用4g网络")
    
    # 公开成员方法
    def call_by_5g(self):
        self.__check_5g()
        print("正在通话中")
​
# 使用
phone = Phone()
phone.call_by_5g()
# 输出:
# 5g关闭,使用4g网络
# 正在通话中
​
# 以下代码会报错(无法访问私有成员)
# phone.__check_5g()
# print(phone.__is_5g_enable)

练习:设计带有私有成员的手机

复制代码
class Phone:
    def __init__(self):
        self.__is_5g_enable = True  # 私有变量
    
    def __check_5g(self):            # 私有方法
        if self.__is_5g_enable:
            print("5g开启")
        else:
            print("5g关闭,使用4g网络")
    
    def call_by_5g(self):            # 公开方法
        self.__check_5g()
        print("正在通话中")
​
# 测试
phone = Phone()
phone.call_by_5g()
# 输出:
# 5g开启
# 正在通话中

七、继承

1. 单继承

复制代码
# 父类
class Phone:
    def call(self):
        print("正在打电话...")
    
    def send_sms(self):
        print("正在发短信...")
​
# 子类继承父类
class SmartPhone(Phone):
    def play_game(self):
        print("正在玩游戏...")
​
# 使用
sp = SmartPhone()
sp.call()        # 继承自父类:正在打电话...
sp.send_sms()    # 继承自父类:正在发短信...
sp.play_game()   # 自己的方法:正在玩游戏...

2. 多继承

复制代码
class Camera:
    def take_photo(self):
        print("拍照中...")
​
class MusicPlayer:
    def play_music(self):
        print("播放音乐中...")
​
class SmartPhone(Camera, MusicPlayer):
    def call(self):
        print("打电话中...")
​
# 使用
sp = SmartPhone()
sp.take_photo()   # 继承自Camera
sp.play_music()   # 继承自MusicPlayer
sp.call()         # 自己的方法

3. 多继承同名方法优先级

父类优先级按继承顺序从左到右,先继承的优先级更高。

复制代码
class A:
    def say(self):
        print("A say")
​
class B:
    def say(self):
        print("B say")
​
class C(A, B):   # A优先级高于B
    pass
​
class D(B, A):   # B优先级高于A
    pass
​
c = C()
c.say()   # A say
​
d = D()
d.say()   # B say

4. pass关键字

pass是占位语句,用于保持代码结构完整性。

复制代码
class EmptyClass:
    pass   # 暂时空实现
​
def temp_function():
    pass   # 暂时空实现

5. 复写父类成员和调用父类

复制代码
class Phone:
    brand = "手机"
    
    def call(self):
        print("父类:正在打电话")
​
class SmartPhone(Phone):
    # 复写父类属性
    brand = "智能手机"
    
    # 复写父类方法
    def call(self):
        print("子类:正在用5G打电话")
        
        # 方式1:使用父类名调用
        Phone.call(self)
        
        # 方式2:使用super()调用
        super().call()
​
sp = SmartPhone()
print(sp.brand)   # 智能手机
sp.call()
# 输出:
# 子类:正在用5G打电话
# 父类:正在打电话
# 父类:正在打电话

八、类型注解

1. 变量类型注解

复制代码
from typing import Union
​
# 基础类型注解
name: str = "张三"
age: int = 18
score: float = 95.5
is_student: bool = True
​
# 容器类型注解
# 列表
names: list = ["张三", "李四"]
# 列表(指定元素类型)
scores: list[int] = [85, 92, 78]
# 元组(需要标注每个元素类型)
person: tuple[str, int, str] = ("张三", 18, "北京")
# 字典
info: dict[str, int] = {"age": 18, "score": 85}
# 集合
tags: set[str] = {"Python", "Java"}
​
# Union类型(多种可能)
value: Union[int, str] = 100
value = "hello"
​
# 注释中标注
name2 = "李四"  # type: str

2. 函数(方法)类型注解

复制代码
from typing import Union
​
# 形参和返回值类型注解
def add(x: int, y: int) -> int:
    return x + y
​
print(add(5, 3))   # 8
​
# 带Union的注解
def process(data: Union[int, str]) -> str:
    return str(data)
​
print(process(100))   # 100
print(process("abc")) # abc
​
# 列表参数注解
def sum_list(nums: list[int]) -> int:
    return sum(nums)
​
print(sum_list([1, 2, 3, 4, 5]))   # 15

九、多态

1. 多态的概念

同一行为,使用不同的对象得到不同的状态。

复制代码
class Animal:
    def speak(self):
        pass   # 抽象方法
​
class Dog(Animal):
    def speak(self):
        print("汪汪汪")
​
class Cat(Animal):
    def speak(self):
        print("喵喵喵")
​
class Duck(Animal):
    def speak(self):
        print("嘎嘎嘎")
​
# 多态:同一个函数,传入不同对象,表现不同行为
def make_sound(animal: Animal):
    animal.speak()
​
make_sound(Dog())    # 汪汪汪
make_sound(Cat())    # 喵喵喵
make_sound(Duck())   # 嘎嘎嘎

2. 抽象类(接口)

定义标准,要求子类必须实现。

复制代码
from abc import ABC, abstractmethod
​
# 抽象类
class Animal(ABC):
    @abstractmethod
    def speak(self):
        """子类必须实现此方法"""
        pass
​
class Dog(Animal):
    def speak(self):
        print("汪汪汪")
​
class Cat(Animal):
    def speak(self):
        print("喵喵喵")
​
# 以下代码会报错(没有实现抽象方法)
# class Fish(Animal):
#     pass
​
# 正确使用
def animal_sound(animal: Animal):
    animal.speak()
​
animal_sound(Dog())   # 汪汪汪
animal_sound(Cat())   # 喵喵喵

十、综合案例

复制代码
import json
from abc import ABC, abstractmethod
from typing import List, Dict


class Record:
    def __init__(self, date: str, order_id: str, money: int, province: str):
        self.date = date
        self.order_id = order_id
        self.money = money
        self.province = province


class FileReader(ABC):
    @abstractmethod
    def read_data(self, file_path: str) -> List[Record]:
        pass


class TextFileReader(FileReader):
    def read_data(self, file_path: str) -> List[Record]:
        records = []
        with open(file_path, "r", encoding="UTF-8") as f:
            for line in f:
                line = line.strip()
                if not line:
                    continue
                parts = line.split(",")
                record = Record(parts[0], parts[1], int(parts[2]), parts[3])
                records.append(record)
        return records


class JsonFileReader(FileReader):
    def read_data(self, file_path: str) -> List[Record]:
        records = []
        with open(file_path, "r", encoding="UTF-8") as f:
            data = json.load(f)
            for item in data:
                record = Record(item["date"], item["order_id"], item["money"], item["province"])
                records.append(record)
        return records


class DailySalesCalculator:
    def calculate(self, records: List[Record]) -> Dict[str, int]:
        daily_sales = {}
        for record in records:
            daily_sales[record.date] = daily_sales.get(record.date, 0) + record.money
        return daily_sales


class ChartDrawer:
    @staticmethod
    def draw(daily_sales: Dict[str, int], file_name: str = "sales_chart.html"):
        try:
            from pyecharts.charts import Bar
            from pyecharts import options as opts
        except ImportError:
            print("❌ pyecharts未安装,请运行: pip install pyecharts")
            return

        dates = list(daily_sales.keys())
        sales = list(daily_sales.values())

        bar = Bar()
        bar.add_xaxis(dates)
        bar.add_yaxis("销售额(元)", sales)
        bar.set_global_opts(
            title_opts=opts.TitleOpts(title="每日销售额统计", pos_left="center"),
            xaxis_opts=opts.AxisOpts(name="日期", axislabel_opts=opts.LabelOpts(rotate=45)),
            yaxis_opts=opts.AxisOpts(name="销售额(元)"),
        )
        bar.render(file_name)
        print(f"✅ 图表已生成:{file_name}")


def main():
    print("=" * 50)
    print("程序开始运行...")
    print("=" * 50)

    jan_data = """2024-01-01,ORD001,1000,北京
2024-01-01,ORD002,1500,上海
2024-01-02,ORD003,2000,广东
2024-01-02,ORD004,1200,北京"""

    feb_data = [
        {"date": "2024-02-01", "order_id": "FEB001", "money": 3000, "province": "上海"},
        {"date": "2024-02-01", "order_id": "FEB002", "money": 2500, "province": "广东"},
        {"date": "2024-02-02", "order_id": "FEB003", "money": 1800, "province": "北京"}
    ]

    print("正在写入测试文件...")
    with open("sales_jan.txt", "w", encoding="UTF-8") as f:
        f.write(jan_data)
    with open("sales_feb.json", "w", encoding="UTF-8") as f:
        json.dump(feb_data, f, ensure_ascii=False)
    print("文件写入完成")

    all_records: List[Record] = []

    text_reader = TextFileReader()
    jan_records = text_reader.read_data("sales_jan.txt")
    all_records.extend(jan_records)
    print(f"1月数据:{len(jan_records)} 条")

    json_reader = JsonFileReader()
    feb_records = json_reader.read_data("sales_feb.json")
    all_records.extend(feb_records)
    print(f"2月数据:{len(feb_records)} 条")

    calculator = DailySalesCalculator()
    daily_sales = calculator.calculate(all_records)

    print("\n=== 每日销售额统计 ===")
    for date, money in sorted(daily_sales.items()):
        print(f"{date}: {money}元")

    ChartDrawer.draw(daily_sales)
    print("\n程序执行完毕!")


if __name__ == "__main__":
    main()

输出:

复制代码
==================================================
程序开始运行...
==================================================
正在写入测试文件...
文件写入完成
1月数据:4 条
2月数据:3 条

=== 每日销售额统计 ===
2024-01-01: 2500元
2024-01-02: 3200元
2024-02-01: 5500元
2024-02-02: 1800元
✅ 图表已生成:sales_chart.html

程序执行完毕!

十一、面向对象速查表

类定义与对象

概念 语法 示例
类定义 class 类名: class Student:
创建对象 对象 = 类名() stu = Student()
构造方法 def __init__(self): def __init__(self, name):
成员变量 self.变量名 = 值 self.name = name
成员方法 def 方法名(self): def say(self):

封装

概念 语法 示例
私有成员 __成员名 self.__password
私有方法 def __方法名(self) def __check(self):

继承

概念 语法 示例
单继承 class 子类(父类): class Dog(Animal):
多继承 class 子类(父类1, 父类2): class C(A, B):
复写 重新定义同名成员 见上方示例
调用父类 super().方法()父类名.方法(self) super().__init__()

类型注解

场景 语法 示例
变量 变量: 类型 name: str = "张三"
返回值 def func() -> 类型: def add(x, y) -> int:
Union Union[类型1, 类型2] value: Union[int, str]

多态

概念 说明
多态 同一行为,不同对象产生不同状态
抽象类 包含抽象方法的类,用于定义标准
抽象方法 方法体为空(pass)的方法
相关推荐
两年半的个人练习生^_^1 小时前
什么是内存泄漏?什么是内存溢出?
java·开发语言
曦夜日长1 小时前
C++ STL容器string(二):删除与插入、数据查找、自定义输入
java·开发语言·c++
jimy11 小时前
C语言中的inline function specifier(函数说明符、关键字)
c语言·开发语言
赏金术士1 小时前
Kotlin 协程底层原理(Continuation)详解
java·开发语言·kotlin
wen_zhufeng1 小时前
python-dotenv 使用文档
数据库·python·oracle
Str_Null1 小时前
杀戮尖塔通过修改记录文件和备份文件进行修改血量和金币
python
钝挫力PROGRAMER2 小时前
复杂PDF转Markdown实战:从Marker到多模态的处理全记录
python·pdf
TechWayfarer2 小时前
账号安全实战:基于IP归属地基线的三原则异地登录风控模型
服务器·网络·python·安全·网络安全
ZGi.ai2 小时前
私有化大模型接入企业系统:SSO+权限+API网关完整方案
java·开发语言·大模型·私有化部署·sso·企业架构