Python 高级
1. 面向对象
封装
核心的手段是在类中通过双下划线来实现封装
单个下划线 _name约定为受保护,但实际可访问。双下划线 __name不能在外部直接进行访问。
python
class Person:
def __init__(self, name, age):
# 双下划线实现name与age的封装,外部不能直接访问该属性
self.__name = name
self.__age = age
# 公开的方法,查看私有属性
def info(self):
print("name: {}, age: {}".format(self.__name, self.__age))
# 公开设置方法,用于修改私有属性
def set_age(self, new_age):
self.__age = new_age
person_a = Person("小明", 10)
person_a.info()
# 修改私有属性 __age
person_a.set_age(18)
person_a.info()
继承
核心:在自定义类名后加括号并写入需要继承的类名即可。
- 调用父类的方法 :
父类名.方法名(self, 参数1, ...),当只有一个父类时,可用super().方法名(参数1, ...),如果是多继承,调用使用super()方法或依次调用所有的被继承者对应的方法。 - 重写父类方法:直接在子类中声明与父类的方法相同的方法名即可。
python
class Camer:
def __init__(self, ip):
self.ip = ip
def take_photo(self, person):
return f"{person}(普通模式)"
def get_info_c(self):
print("相机型号:5D Mark IV")
class Phone:
def __init__(self, number):
self.number = number
def call(self, numer):
return f"呼叫:from {self.number} to {numer}"
def get_info_p(self):
print("电话型号:PHILIPS飞利浦")
class SmartPhone(Camer, Phone):
def __init__(self, ip, number, brand):
# 调用多个父类的初始化方法
Camer.__init__(self, ip)
Phone.__init__(self, number)
self.brand = brand
def use_app(self, app_name):
return f"使用{app_name}应用"
# 重写父类方法
def take_photo(self, person):
return f"{person}(美颜模式)"
xiaomi = SmartPhone("China", "12345678901", "小米")
print(xiaomi.take_photo("张三"))
print(xiaomi.call("10123456789"))
print(xiaomi.use_app("微信"))
xiaomi.get_info_c()
xiaomi.get_info_p()
# 张三(美颜模式)
# 呼叫:from 12345678901 to 10123456789
# 使用微信应用
# 相机型号:5D Mark IV
# 电话型号:PHILIPS飞利浦
多态
同一个方法调用,根据对象的类型不同,执行的逻辑也不同。
通俗理解:各个类都有自己的的方法,但这些方法名相同,不同类通过同一个函数调用这个方法会有不同的返回结果。
python
# 父类:动物
class Animal:
def __init__(self, name):
self.name = name
# 定义通用的"叫"方法(父类占位,由子类重写)
def make_sound(self):
pass # 空实现,子类必须重写
# 子类:猫
class Cat(Animal):
def make_sound(self):
print(f"{self.name}:喵喵喵~")
# 子类:狗
class Dog(Animal):
def make_sound(self):
print(f"{self.name}:汪汪汪!")
# 子类:鸭子
class Duck(Animal):
def make_sound(self):
print(f"{self.name}:嘎嘎嘎~")
# 通用函数:接收Animal类型的对象,调用make_sound方法(多态的核心体现)
def animal_sound(animal):
animal.make_sound()
# 测试多态效果
if __name__ == "__main__":
# 创建不同的动物对象
cat = Cat("橘猫")
dog = Dog("柴犬")
duck = Duck("小黄鸭")
# 调用同一个函数,传入不同对象,表现出不同行为
animal_sound(cat) # 输出:橘猫:喵喵喵~
animal_sound(dog) # 输出:柴犬:汪汪汪!
animal_sound(duck) # 输出:小黄鸭:嘎嘎嘎~
2. 魔法方法
Python 中的魔法方法(Magic Methods / Special Methods)是以双下划线__开头和结尾 的特殊方法(比如__init__、__str__)。它们不是由你手动调用的,而是在特定场景下(比如创建对象、打印对象、做加法运算)由 Python 解释器自动触发执行。
特点
- 无需显式调用 :比如你写
print(obj)时,Python 会自动调用obj的__str__方法,不用你写obj.__str__(); - 绑定特定语法 :每个魔法方法对应 Python 的一个基础语法或操作(比如
__add__对应+运算符,__len__对应len()函数); - 自定义对象行为 :通过重写魔法方法,你可以让自定义的类对象支持 Python 的原生操作(比如让你的类对象能做加法、能被
len()计算长度)。
-
✨
__init__: 创建对象时自动触发,初始化属性。pythondef __init__(self, name, age): self.name = name self.age = age print(f"对象{self.name}已创建") -
__del__: 对象被销毁时自动触发(程序结束/手动删除)pythondef __del__(self): print(f"对象{self.name}已销毁") -
__str__: 触发方式print(obj)或str(obj)pythondef __str__(self): return f"Person(name={self.name}, age={self.age})" -
__repr__: 触发方式 ``repr(obj)或终端直接输对象`pythondef __repr__(self): return f"Person('{self.name}', {self.age})" -
__add__: 自定义加法逻辑, 触发方式bj1 + obj2pythondef __add__(self, other): # 先判断other是不是Rectangle类型,保证健壮性 if isinstance(other, Rectangle): return self.area + other.area else: raise TypeError("只能和Rectangle对象相加") -
__sub__: 自定义减法逻辑,obj1 - obj2 -
__eq__: 自定义 "等于" 逻辑,obj1 == obj2python# 自定义==:年龄相同则相等 def __eq__(self, other): if isinstance(other, Person): return self.age == other.age return False -
__gt__: 自定义 "大于" 逻辑,obj1 > obj2python# 自定义>:年龄大则更大 def __gt__(self, other): if isinstance(other, Person): return self.age > other.age raise TypeError("只能和Person对象比较") -
__lt__: 自定义 "小于" 逻辑,obj1 < obj2 -
✨
__len__: 自定义 "长度" 逻辑,len(obj)python# 自定义len():返回成绩的数量 def __len__(self): return len(self.scores) -
✨
__getitem__: 自定义索引取值逻辑,obj[index]python# 自定义索引取值:score_list[0] def __getitem__(self, index): return self.scores[index] -
✨
__setitem__: 自定义索引赋值逻辑,obj[index] = valuepython# 自定义索引赋值:score_list[0] = 90 def __setitem__(self, index, value): # 校验成绩合法性 if 0 <= value <= 100: self.scores[index] = value else: raise ValueError("成绩必须在0-100之间") -
__enter__: 初始化资源(比如打开文件),触发场景进入 with 代码块时。python# 进入with时触发:打开文件 def __enter__(self): self.file = open(self.filename, self.mode) return self.file # 给as后的变量赋值 -
__exit__: 清理资源(比如关闭文件),触发场景退出 with 代码块时python# 退出with时触发:关闭文件 def __exit__(self, exc_type, exc_val, exc_tb): if self.file: self.file.close() print("文件已自动关闭") -
✨
__call__: 允许类的实例像函数一样被调用。pythonclass Multiplier: def __init__(self, factor): self.factor = factor def __call__(self, x): """使实例可调用,返回x乘以factor的结果""" return x * self.factor # 创建实例 double = Multiplier(2) triple = Multiplier(3) # 像函数一样调用实例 print(double(5)) # 10 print(triple(5)) # 15 print(double(10)) # 20
3. 推导式
列表推导式
语法
python
# 基础语法:无条件筛选
[表达式 for 变量 in 可迭代对象]
# 带条件筛选:只保留满足条件的元素
[表达式 for 变量 in 可迭代对象 if 条件]
# 嵌套循环:处理多层可迭代对象
[表达式 for 变量1 in 可迭代对象1 for 变量2 in 可迭代对象2]
字典推导式
语法
python
# 基础语法
{键表达式: 值表达式 for 变量 in 可迭代对象}
# 带条件筛选
{键表达式: 值表达式 for 变量 in 可迭代对象 if 条件}
集合推导式
语法
python
# 基础语法
{表达式 for 变量 in 可迭代对象}
# 带条件筛选
{表达式 for 变量 in 可迭代对象 if 条件}
生成器推导式
语法
python
# 示例1:创建生成器对象
gen = (i * i for i in range(1, 11))
print(gen) # 输出:<generator object <genexpr> at 0x...>(不是列表,是生成器)
# 示例2:遍历生成器(按需生成元素)
for num in gen:
print(num, end=" ") # 输出:1 4 9 16 25 36 49 64 81 100
# 示例3:大数据量场景------生成1000万个数的平方(生成器更省内存)
# 列表推导式:big_list = [i*i for i in range(10_000_000)] # 占用大量内存
# 生成器推导式:big_gen = (i*i for i in range(10_000_000)) # 几乎不占内存
4. 装饰器
装饰器本质是一个接收函数作为参数、并返回新函数的高阶函数 ,核心作用是:在不修改原函数代码、不改变原函数调用方式的前提下,为函数添加额外功能。
python
# 定义装饰器(高阶函数+闭包)
def log_decorator(func):
# 内层函数(闭包):包装原函数,添加额外功能
def wrapper(*args, **kwargs):
print(f"函数{func.__name__}开始执行...")
result = func(*args, **kwargs)
print(f"函数{func.__name__}执行结束,结果:{result}")
return result
return wrapper
# 使用语法糖@,直接装饰函数
@log_decorator # 等价于:add = log_decorator(add)
def add(a, b):
return a + b
@log_decorator # 等价于:multiply = log_decorator(multiply)
def multiply(a, b):
return a * b
# 调用方式不变
add(1, 2) # 输出:函数add开始执行... 函数add执行结束,结果:3 3
multiply(3, 4) # 输出:函数multiply开始执行... 函数multiply执行结束,结果:12 12
带参数的装饰器
python# 带参数的装饰器(三层嵌套) def log_decorator(prefix=""): # 第一层:接收装饰器的参数 def outer(func): # 第二层:接收被装饰的函数 def wrapper(*args, **kwargs): # 第三层:包装函数,使用装饰器参数 print(f"{prefix}函数{func.__name__}开始执行...") result = func(*args, **kwargs) print(f"{prefix}函数{func.__name__}执行结束,结果:{result}") return result return wrapper return outer # 使用带参数的装饰器 @log_decorator(prefix="[日志]") # 传入自定义前缀 def add(a, b): return a + b @log_decorator() # 不传参数,使用默认值 def multiply(a, b): return a * b # 调用 add(1, 2) # 输出:[日志]函数add开始执行... [日志]函数add执行结束,结果:3 multiply(3, 4) # 输出:函数multiply开始执行... 函数multiply执行结束,结果:12
5. 上下文管理器
python
# 经典用法:with + 上下文管理器
with open("test.txt", "w") as f:
f.write("Hello Context Manager")
# 无需手动调用f.close(),with代码块结束后自动关闭文件
6. 解包操作
基础解包(无*)
适用于列表、元组、字符串、range 等有序可迭代对象 ,要求变量数量和元素数量完全匹配(否则报错),是最基础的解包形式。
python
# 1. 元组解包(最常用,Python中逗号分隔的多个值本质是元组)
tup = (1, 2)
a, b = tup # 把元组的2个元素拆给a、b
print(a, b) # 输出:1 2
# 2. 列表解包
lst = [3, 4]
c, d = lst
print(c, d) # 输出:3 4
# 3. 字符串解包(按字符拆分)
s = "AB"
x, y = s
print(x, y) # 输出:A B
# 4. 处理函数多返回值(本质是元组解包)
def get_user_info():
return "张三", 25, "北京" # 函数返回多个值时,默认打包成元组
name, age, city = get_user_info() # 解包接收
print(name, age, city) # 输出:张三 25 北京
# 注意:变量数量和元素数量不匹配会报错
# a, b = [1,2,3] # ValueError: too many values to unpack (expected 2)
# a, b, c = [1,2] # ValueError: not enough values to unpack (expected 3, got 2)
扩展解包(*):处理数量不匹配的情况
用*符号可以接收 "剩余的所有元素"(生成一个列表),解决变量数量和元素数量不匹配的问题。*可以放在变量的开头、中间或结尾(Python3.0 + 支持),是解包中最灵活的用法。
python
# 1. *放在结尾:接收后面所有剩余元素
a, *b = [1, 2, 3, 4]
print(a) # 输出:1(单个变量接收第一个元素)
print(b) # 输出:[2, 3, 4](*变量接收剩余元素,生成列表)
# 2. *放在开头:接收前面所有剩余元素
*a, b = [1, 2, 3, 4]
print(a) # 输出:[1, 2, 3]
print(b) # 输出:4
# 3. *放在中间:接收中间的剩余元素
a, *b, c = [1, 2, 3, 4]
print(a) # 输出:1
print(b) # 输出:[2, 3]
print(c) # 输出:4
# 4. 特殊:*接收空元素(元素数量刚好匹配时)
a, *b, c = [1, 4]
print(a) # 输出:1
print(b) # 输出:[](空列表)
print(c) # 输出:4
核心:
*+ 容器,表示将容器中的一级元素分离。
字典解包
*:解包字典的键(返回可迭代的键);
**:解包字典的键值对(作为函数的关键字参数)。
python
d = {"name": "张三", "age": 25, "city": "北京"}
# *解包字典的键(返回列表)
keys = [*d]
print(keys) # 输出:['name', 'age', 'city']
# 遍历键值对时的解包(常用)
for k, v in d.items(): # items()返回(键,值)元组,解包给k、v
print(f"{k}: {v}")
# 输出:
# name: 张三
# age: 25
# city: 北京
python
def print_info(name, age, city):
print(f"姓名:{name},年龄:{age},城市:{city}")
user_dict = {"name": "李四", "age": 30, "city": "上海"}
# 用**解包字典,等价于print_info(name="李四", age=30, city="上海")
print_info(**user_dict) # 输出:姓名:李四,年龄:30,城市:上海
# 合并字典(Python3.5+支持)
d1 = {"a": 1, "b": 2}
d2 = {"b": 3, "c": 4}
# **解包两个字典,后面的字典覆盖前面的同名键
merged_dict = {**d1, **d2}
print(merged_dict) # 输出:{'a': 1, 'b': 3, 'c': 4}
7. 匿名函数
基本语法:
python
lambda 参数列表: 表达式
python
# 示例1:无参数(仅返回固定值)
print((lambda: "Hello Lambda")()) # 输出:Hello Lambda
# 示例2:带默认参数
greet = lambda name="陌生人": f"你好,{name}!"
print(greet()) # 输出:你好,陌生人!
print(greet("张三")) # 输出:你好,张三!
# 示例3:带可变参数(*args/**kwargs)
sum_all = lambda *args: sum(args) # 求和任意数量的参数
print(sum_all(1, 2, 3, 4)) # 输出:10
# 示例4:三元表达式(唯一支持的"条件判断"形式)
check_even = lambda x: "偶数" if x % 2 == 0 else "奇数"
print(check_even(4)) # 输出:偶数
print(check_even(5)) # 输出:奇数
8. 并行处理
进程
适用场景 :CPU 密集型任务:比如数学计算、数据建模、视频编码、大文件解压(需要持续占用 CPU,充分利用多核)。
关键三个语句:
- 创建进程:
p = multiprocessing.Process(target=calculate_sum, args=("P1", 0, 50000000)) - 启动:
p.start() - 等待结束:
p.join()
python
import multiprocessing
import time
# 定义CPU密集型任务:计算累加和
def calculate_sum(name, start, end):
total = 0
for i in range(start, end):
total += i
print(f"进程{name}计算完成:{start}到{end}的和为{total}")
if __name__ == "__main__":
start_time = time.time()
# 方式1:单进程(对比用)
# calculate_sum("单进程", 0, 100000000) # 耗时约4秒(视CPU性能)
# 方式2:多进程(利用多核并行)
p1 = multiprocessing.Process(target=calculate_sum, args=("P1", 0, 50000000))
p2 = multiprocessing.Process(target=calculate_sum, args=("P2", 50000000, 100000000))
# 启动进程
p1.start()
p2.start()
# 等待进程结束
p1.join()
p2.join()
end_time = time.time()
print(f"总耗时:{end_time - start_time:.2f}秒") # 耗时约2秒(并行,几乎减半)
进程间通信
关键三个语句:
- 创建队列:
queue = multiprocessing.Queue(maxsize=10) - 出队:
item = queue.get() - 入队:
queue.put(item)
python
import multiprocessing
import time
import random
def producer(queue, name, items):
"""生产者进程:生成数据并放入队列"""
print(f"生产者 {name} 开始工作")
for i in range(items):
item = f"产品-{name}-{i+1}"
queue.put(item)
print(f"生产者 {name} 生产了: {item}")
time.sleep(random.uniform(0.1, 0.5))
# 发送结束信号
queue.put(None)
print(f"生产者 {name} 结束")
def consumer(queue, name):
"""消费者进程:从队列取出并处理数据"""
print(f"消费者 {name} 开始工作")
end_count = 0
while True:
item = queue.get()
if item is None:
end_count += 1
print(f"消费者 {name} 收到结束信号 ({end_count}/3)")
if end_count >= 3: # 有3个生产者
break
else:
print(f"消费者 {name} 消费了: {item}")
time.sleep(random.uniform(0.2, 0.3))
print(f"消费者 {name} 结束")
if __name__ == '__main__':
# 创建队列
queue = multiprocessing.Queue(maxsize=10)
# 创建生产者进程
producers = []
for i in range(3):
p = multiprocessing.Process(
target=producer,
args=(queue, f"P{i+1}", 5)
)
producers.append(p)
# 创建消费者进程
consumers = []
for i in range(2):
c = multiprocessing.Process(
target=consumer,
args=(queue, f"C{i+1}")
)
consumers.append(c)
# 启动所有进程
for p in producers:
p.start()
for c in consumers:
c.start()
# 等待生产者完成
for p in producers:
p.join()
# 确保消费者收到结束信号
for _ in consumers:
queue.put(None)
# 等待消费者完成
for c in consumers:
c.join()
print("所有进程完成!")
进程池
python
import multiprocessing
import time
import os
def process_task(x):
"""处理任务,返回结果的平方"""
print(f"进程 {os.getpid()} 处理任务: {x}")
time.sleep(0.5) # 模拟耗时操作
return x * x
if __name__ == '__main__':
# 创建进程池,最大进程数为4
pool = multiprocessing.Pool(processes=4)
# 准备任务数据
tasks = list(range(1, 11))
print("开始并行处理任务...")
# 方法1: apply - 同步执行,阻塞直到结果返回
print("\n1. 使用apply(同步):")
for task in tasks[:3]:
result = pool.apply(process_task, (task,))
print(f" 任务 {task} 结果: {result}")
# 方法2: apply_async - 异步执行
print("\n2. 使用apply_async(异步):")
async_results = []
for task in tasks[3:7]:
result = pool.apply_async(process_task, (task,))
async_results.append((task, result))
# 获取异步结果
for task, result in async_results:
print(f" 任务 {task} 结果: {result.get()}")
# 方法3: map - 类似内置map函数
print("\n3. 使用map:")
results = pool.map(process_task, tasks[7:])
for i, result in enumerate(results, start=8):
print(f" 任务 {i} 结果: {result}")
# 方法4: imap - 惰性迭代器
print("\n4. 使用imap(惰性):")
for i, result in enumerate(pool.imap(process_task, tasks), start=1):
print(f" 任务 {i} 结果: {result}")
# 关闭进程池
pool.close()
pool.join()
print("所有任务完成!")
补充:获取CPU逻辑核心数
python# 获取CPU逻辑核心数(最常用,对应超线程后的核心数) cpu_count = multiprocessing.cpu_count() print(f"CPU逻辑核心数:{cpu_count}")
线程
适用场景 :IO 密集型任务:比如文件读写、网络请求(爬虫、接口调用)、数据库操作(大部分时间在等待 IO,而非占用 CPU)。
python
import threading
import time
import requests
# 定义IO密集型任务:请求网页
def fetch_url(name, url):
print(f"线程{name}开始请求:{url}")
response = requests.get(url)
print(f"线程{name}请求完成:{url}的状态码为{response.status_code}")
if __name__ == "__main__":
start_time = time.time()
# 方式1:单线程(对比用)
# fetch_url("单线程", "https://www.baidu.com")
# fetch_url("单线程", "https://www.taobao.com")
# fetch_url("单线程", "https://www.jd.com") # 耗时约3秒(串行等待)
# 方式2:多线程(并发,无需等待IO)
t1 = threading.Thread(target=fetch_url, args=("T1", "https://www.baidu.com"))
t2 = threading.Thread(target=fetch_url, args=("T2", "https://www.taobao.com"))
t3 = threading.Thread(target=fetch_url, args=("T3", "https://www.jd.com"))
t1.start()
t2.start()
t3.start()
t1.join() # 等待进程结束
t2.join()
t3.join()
end_time = time.time()
print(f"总耗时:{end_time - start_time:.2f}秒") # 耗时约1秒(并发,几乎并行)
线程池
python
import time
from concurrent.futures import ThreadPoolExecutor
def task(num):
"""简单任务:休眠1秒后返回数字的平方"""
time.sleep(1)
return num * num
if __name__ == "__main__":
# 创建线程池(3个线程)
executor = ThreadPoolExecutor(max_workers=3)
# 提交单个任务,获取Future对象
future1 = executor.submit(task, 2)
future2 = executor.submit(task, 3)
# 方式1:阻塞获取结果(直到任务完成)
print(f"任务1结果:{future1.result()}") # 输出:4
print(f"任务2结果:{future2.result()}") # 输出:9
# 方式2:判断任务状态
print(f"任务1是否完成:{future1.done()}") # 输出:True
print(f"任务1是否取消:{future1.cancelled()}") # 输出:False
# 关闭线程池
executor.shutdown()
协程
适用场景 :超高 IO 密集型任务:比如高并发爬虫、实时通信、微服务接口(需要处理上万 / 百万级 IO 请求)。
python
import asyncio
import aiohttp # 异步HTTP库(需先安装:pip install aiohttp)
import time
# 定义异步IO任务:请求网页
async def fetch_url(name, url):
print(f"协程{name}开始请求:{url}")
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
print(f"协程{name}请求完成:{url}的状态码为{response.status}")
# 主协程
async def main():
# 创建多个协程任务
tasks = [
fetch_url("C1", "https://www.baidu.com"),
fetch_url("C2", "https://www.taobao.com"),
fetch_url("C3", "https://www.jd.com"),
# 可扩展到上千个协程,依然高效
]
# 并发执行所有协程
await asyncio.gather(*tasks)
if __name__ == "__main__":
start_time = time.time()
# 运行异步程序
asyncio.run(main())
end_time = time.time()
print(f"总耗时:{end_time - start_time:.2f}秒") # 耗时约1秒(比多线程更高效)
9. 异常检测
try-except-finally
python
# 示例:读取文件,无论是否出错都关闭文件
file = None
try:
file = open("test.txt", "r")
content = file.read()
print(content)
except FileNotFoundError as e:
print(f"错误:{e}")
finally:
# 无论是否出错,都关闭文件
if file:
file.close()
print("文件已关闭")
捕获所有异常
python
try:
# 任意可能出错的代码
lst = [1,2]
print(lst[3])
except Exception as e:
# 捕获所有运行时异常
print(f"未知错误:{type(e).__name__} - {e}")
主动抛出异常
python
def check_age(age):
if not isinstance(age, int):
# 主动抛出TypeError,自定义错误信息
raise TypeError("年龄必须是整数!")
if age < 0 or age > 120:
# 主动抛出ValueError
raise ValueError("年龄必须在0-120之间!")
return age
# 测试
try:
check_age(-5)
except (TypeError, ValueError) as e:
print(f"参数校验失败:{e}") # 输出:参数校验失败:年龄必须在0-120之间!
10. 断言
语法
python
assert 条件表达式 [, 自定义错误信息]
python
def calculate_area(radius):
# 断言:半径必须是正数(调试阶段校验)
assert isinstance(radius, (int, float)), f"半径必须是数字,当前类型:{type(radius)}"
assert radius > 0, f"半径必须大于0,当前值:{radius}"
return 3.14 * radius * radius
# 调试阶段:参数错误会立刻报错
calculate_area(-2) # 触发AssertionError: 半径必须大于0,当前值:-2
calculate_area("abc") # 触发AssertionError: 半径必须是数字,当前类型:<class 'str'>