目录
[1. 为什么使用对象](#1. 为什么使用对象)
[2. 类和对象的概念](#2. 类和对象的概念)
[1. 类的定义](#1. 类的定义)
[2. self关键字的作用](#2. self关键字的作用)
[1. 使用类描述现实事物](#1. 使用类描述现实事物)
[2. 类和对象的关系](#2. 类和对象的关系)
[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)的方法 |