第2课-Python基础回顾
第2课:Python基础回顾
课程目标
通过本课程学习,你将能够:
- 掌握Python面向对象编程的核心概念
- 理解模块和包的导入机制
- 掌握装饰器的原理和使用
- 理解生成器和迭代器的工作原理
- 掌握异常处理的最佳实践
- 理解上下文管理器的应用场景
- 为后续学习OneForAll项目打下坚实的Python基础
2.1 面向对象编程基础
2.1.1 类与对象
什么是类?
类(Class)是创建对象的模板或蓝图,它定义了一类对象的属性和方法。
什么是对象?
对象(Object)是类的实例,是根据类创建的具体实体。
基本语法:
# 定义一个类
class Dog:
# 类属性(所有实例共享)
species = "Canis familiaris"
# 初始化方法(构造函数)
def __init__(self, name, age):
# 实例属性(每个实例独有)
self.name = name
self.age = age
# 实例方法
def bark(self):
return f"{self.name} says Woof!"
def introduce(self):
return f"My name is {self.name} and I'm {self.age} years old."
# 类方法
@classmethod
def get_species(cls):
return cls.species
# 静态方法
@staticmethod
def is_dog(animal):
return animal.lower() == "dog"
# 创建对象(实例化)
dog1 = Dog("Buddy", 3)
dog2 = Dog("Max", 5)
# 访问实例属性
print(dog1.name) # 输出: Buddy
print(dog2.age) # 输出: 5
# 调用实例方法
print(dog1.bark()) # 输出: Buddy says Woof!
print(dog2.introduce()) # 输出: My name is Max and I'm 5 years old.
# 访问类属性
print(dog1.species) # 输出: Canis familiaris
# 调用类方法
print(Dog.get_species()) # 输出: Canis familiaris
# 调用静态方法
print(Dog.is_dog("dog")) # 输出: True
2.1.2 继承
什么是继承?
继承允许一个类(子类)获取另一个类(父类)的属性和方法,实现代码复用和扩展。
基本语法:
# 父类(基类)
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
raise NotImplementedError("Subclass must implement abstract method")
def eat(self):
return f"{self.name} is eating."
# 子类继承父类
class Dog(Animal):
def __init__(self, name, breed):
# 调用父类的初始化方法
super().__init__(name)
self.breed = breed
# 重写父类方法
def speak(self):
return f"{self.name} says Woof!"
# 新增方法
def fetch(self):
return f"{self.name} is fetching the ball!"
class Cat(Animal):
def __init__(self, name, color):
super().__init__(name)
self.color = color
def speak(self):
return f"{self.name} says Meow!"
def scratch(self):
return f"{self.name} is scratching!"
# 使用继承
dog = Dog("Buddy", "Golden Retriever")
cat = Cat("Whiskers", "Orange")
print(dog.speak()) # 输出: Buddy says Woof!
print(dog.eat()) # 输出: Buddy is eating.
print(dog.fetch()) # 输出: Buddy is fetching the ball!
print(cat.speak()) # 输出: Whiskers says Meow!
print(cat.eat()) # 输出: Whiskers is eating.
print(cat.scratch()) # 输出: Whiskers is scratching!
2.1.3 多态
什么是多态?
多态允许不同类的对象对相同的方法调用做出不同的响应。
class Animal:
def speak(self):
pass
class Dog(Animal):
def speak(self):
return "Woof!"
class Cat(Animal):
def speak(self):
return "Meow!"
class Cow(Animal):
def speak(self):
return "Moo!"
# 多态演示
def animal_sound(animal):
return animal.speak()
# 创建不同的动物对象
animals = [Dog(), Cat(), Cow()]
# 相同的方法调用,不同的响应
for animal in animals:
print(animal_sound(animal))
# 输出:
# Woof!
# Meow!
# Moo!
2.1.4 封装
什么是封装?
封装是隐藏对象的内部实现细节,只暴露必要的接口。
class BankAccount:
def __init__(self, owner, balance=0):
self.owner = owner
# 私有属性(以双下划线开头)
self.__balance = balance
# 公有方法
def deposit(self, amount):
if amount > 0:
self.__balance += amount
return f"Deposited ${amount}. New balance: ${self.__balance}"
return "Invalid deposit amount."
def withdraw(self, amount):
if 0 < amount <= self.__balance:
self.__balance -= amount
return f"Withdrew ${amount}. New balance: ${self.__balance}"
return "Invalid withdrawal amount or insufficient funds."
# 只读属性访问器
def get_balance(self):
return self.__balance
# 受保护属性(以单下划线开头)
def _internal_method(self):
return "This is an internal method"
# 使用封装
account = BankAccount("John", 1000)
print(account.deposit(500)) # 输出: Deposited $500. New balance: $1500
print(account.withdraw(200)) # 输出: Withdrew $200. New balance: $1300
print(account.get_balance()) # 输出: 1300
# 不能直接访问私有属性
# print(account.__balance) # 会报错: AttributeError
# 但Python的私有只是名称改写
print(account._BankAccount__balance) # 可以访问(不推荐)
2.1.5 特殊方法(魔法方法)
常用的特殊方法:
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
# 字符串表示
def __str__(self):
return f"Vector({self.x}, {self.y})"
# 官方字符串表示
def __repr__(self):
return f"Vector({self.x}, {self.y})"
# 相等运算
def __eq__(self, other):
if isinstance(other, Vector):
return self.x == other.x and self.y == other.y
return False
# 加法运算
def __add__(self, other):
if isinstance(other, Vector):
return Vector(self.x + other.x, self.y + other.y)
raise TypeError("Operands must be of type Vector")
# 长度(len函数)
def __len__(self):
return int((self.x ** 2 + self.y ** 2) ** 0.5)
# 索引访问
def __getitem__(self, index):
if index == 0:
return self.x
elif index == 1:
return self.y
else:
raise IndexError("Index out of range")
# 使用特殊方法
v1 = Vector(3, 4)
v2 = Vector(1, 2)
print(v1) # 输出: Vector(3, 4)
print(str(v1)) # 输出: Vector(3, 4)
print(repr(v1)) # 输出: Vector(3, 4)
print(v1 == v2) # 输出: False
print(v1 + v2) # 输出: Vector(4, 6)
print(len(v1)) # 输出: 5
print(v1[0], v1[1]) # 输出: 3 4
2.2 模块和包
2.2.1 模块(Module)
什么是模块?
模块是一个包含Python定义和语句的文件,文件名就是模块名加上.py后缀。
创建模块:
# mymodule.py
def greet(name):
return f"Hello, {name}!"
class Calculator:
def add(self, a, b):
return a + b
def subtract(self, a, b):
return a - b
PI = 3.14159
导入模块:
# 方法1:导入整个模块
import mymodule
print(mymodule.greet("Alice"))
calc = mymodule.Calculator()
print(calc.add(5, 3))
# 方法2:导入特定函数或类
from mymodule import greet, Calculator
print(greet("Bob"))
calc = Calculator()
print(calc.subtract(10, 4))
# 方法3:导入所有内容(不推荐)
from mymodule import *
print(greet("Charlie"))
print(PI)
# 方法4:给模块起别名
import mymodule as mm
print(mm.greet("David"))
# 方法5:给导入的内容起别名
from mymodule import greet as say_hello
print(say_hello("Eve"))
2.2.2 包(Package)
什么是包?
包是一个包含多个模块的目录,目录中必须有一个__init__.py文件(Python 3.3+可以是空文件)。
包的结构:
mypackage/
├── __init__.py
├── module1.py
├── module2.py
└── subpackage/
├── __init__.py
└── module3.py
创建包:
# mypackage/__init__.py
"""
This is the mypackage package.
"""
from . import module1
from . import module2
__version__ = "1.0.0"
# mypackage/module1.py
def func1():
return "Function 1 from module1"
class Class1:
def method(self):
return "Method from Class1"
# mypackage/module2.py
def func2():
return "Function 2 from module2"
# mypackage/subpackage/__init__.py
from . import module3
# mypackage/subpackage/module3.py
def func3():
return "Function 3 from subpackage.module3"
导入包:
# 导入包
import mypackage
print(mypackage.__version__)
# 导入包中的模块
from mypackage import module1, module2
print(module1.func1())
print(module2.func2())
# 导入包中的特定内容
from mypackage.module1 import func1, Class1
print(func1())
obj = Class1()
print(obj.method())
# 导入子包
from mypackage.subpackage import module3
print(module3.func3())
# 使用点号导入
from mypackage.module1 import func1 as f1
from mypackage.subpackage.module3 import func3 as f3
print(f1())
print(f3())
2.2.3 __init__.py的作用
__init__.py文件有以下作用:
- 标识目录为Python包
- 控制包的导入行为
- 提供包级别的初始化代码
- 定义
__all__变量,控制from package import *的行为
# mypackage/__init__.py
# 定义包的公共接口
from .module1 import func1, Class1
from .module2 import func2
# 定义__all__,控制import *的行为
__all__ = ['func1', 'Class1', 'func2']
# 包级别的变量
__version__ = "1.0.0"
__author__ = "Your Name"
# 包初始化时执行的代码
print(f"Initializing mypackage v{__version__}")
# 现在可以这样导入
from mypackage import func1, Class1, func2
# 这样只会导入__all__中定义的内容
from mypackage import *
2.2.4 相对导入
在包内部,可以使用相对导入:
# mypackage/module1.py
from .module2 import func2 # 导入同一包中的module2
from ..subpackage import module3 # 导入父包的subpackage
相对导入语法:
.: 当前包..: 父包...: 祖父包
2.2.5 模块的__name__属性
每个模块都有一个__name__属性:
# mymodule.py
def main():
print("This is the main function")
if __name__ == "__main__":
print("This module is being run directly")
main()
else:
print("This module is being imported")
运行效果:
# 直接运行模块
$ python mymodule.py
This module is being run directly
This is the main function
# 导入模块
$ python -c "import mymodule"
This module is being imported
2.3 装饰器(Decorator)
2.3.1 函数装饰器基础
什么是装饰器?
装饰器是一个接受函数作为参数,并返回一个新函数的函数。它可以在不修改原函数代码的情况下,为函数添加额外的功能。
基本概念:
# 简单的装饰器示例
def my_decorator(func):
def wrapper():
print("Before function call")
func()
print("After function call")
return wrapper
@my_decorator
def say_hello():
print("Hello!")
# 调用函数
say_hello()
# 输出:
# Before function call
# Hello!
# After function call
# 等价于:
# say_hello = my_decorator(say_hello)
# say_hello()
2.3.2 装饰带参数的函数
def my_decorator(func):
def wrapper(*args, **kwargs):
print(f"Calling {func.__name__} with args: {args}, kwargs: {kwargs}")
result = func(*args, **kwargs)
print(f"{func.__name__} returned: {result}")
return result
return wrapper
@my_decorator
def add(a, b):
return a + b
@my_decorator
def greet(name, greeting="Hello"):
return f"{greeting}, {name}!"
print(add(3, 5))
# 输出:
# Calling add with args: (3, 5), kwargs: {}
# add returned: 8
# 8
print(greet("Alice"))
# 输出:
# Calling greet with args: ('Alice',), kwargs: {'greeting': 'Hello'}
# greet returned: Hello, Alice!
# Hello, Alice!
2.3.3 带参数的装饰器
def repeat(times):
def decorator(func):
def wrapper(*args, **kwargs):
results = []
for _ in range(times):
result = func(*args, **kwargs)
results.append(result)
return results
return wrapper
return decorator
@repeat(3)
def greet(name):
return f"Hello, {name}!"
print(greet("Bob"))
# 输出:
# ['Hello, Bob!', 'Hello, Bob!', 'Hello, Bob!']
2.3.4 保留原函数的元数据
使用functools.wraps装饰器保留原函数的元数据:
import functools
def my_decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print(f"Calling {func.__name__}")
return func(*args, **kwargs)
return wrapper
@my_decorator
def add(a, b):
"""Add two numbers."""
return a + b
print(add.__name__) # 输出: add
print(add.__doc__) # 输出: Add two numbers.
# 如果不使用@functools.wraps,输出会是wrapper和None
2.3.5 实用装饰器示例
计时装饰器:
import time
import functools
def timer(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f"{func.__name__} took {end_time - start_time:.4f} seconds")
return result
return wrapper
@timer
def slow_function():
time.sleep(1)
return "Done!"
print(slow_function())
# 输出:
# slow_function took 1.0012 seconds
# Done!
日志装饰器:
import functools
import logging
logging.basicConfig(level=logging.INFO)
def log(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
logging.info(f"Calling {func.__name__} with args={args}, kwargs={kwargs}")
try:
result = func(*args, **kwargs)
logging.info(f"{func.__name__} returned {result}")
return result
except Exception as e:
logging.error(f"{func.__name__} raised {e}")
raise
return wrapper
@log
def divide(a, b):
return a / b
print(divide(10, 2))
# 输出:
# INFO:root:Calling divide with args=(10, 2), kwargs={}
# INFO:root:divide returned 5.0
# 5.0
print(divide(10, 0))
# 输出:
# INFO:root:Calling divide with args=(10, 0), kwargs={}
# ERROR:root:divide raised division by zero
# ZeroDivisionError: division by zero
缓存装饰器:
import functools
def cache(func):
cached_results = {}
@functools.wraps(func)
def wrapper(*args):
if args not in cached_results:
cached_results[args] = func(*args)
return cached_results[args]
return wrapper
@cache
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
print(fibonacci(10)) # 输出: 55
print(fibonacci(10)) # 第二次调用会从缓存中读取
注意: Python内置了@functools.lru_cache装饰器,功能更强大:
import functools
@functools.lru_cache(maxsize=None)
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
2.3.6 类装饰器
class CountCalls:
def __init__(self, func):
self.func = func
self.count = 0
def __call__(self, *args, **kwargs):
self.count += 1
print(f"Call {self.count} of {self.func.__name__}")
return self.func(*args, **kwargs)
@CountCalls
def say_hello():
print("Hello!")
say_hello() # 输出: Call 1 of say_hello
say_hello() # 输出: Call 2 of say_hello
say_hello() # 输出: Call 3 of say_hello
2.4 生成器与迭代器
2.4.1 迭代器(Iterator)
什么是迭代器?
迭代器是实现了__iter__()和__next__()方法的对象,可以用于遍历序列。
创建迭代器:
class MyIterator:
def __init__(self, data):
self.data = data
self.index = 0
def __iter__(self):
return self
def __next__(self):
if self.index < len(self.data):
result = self.data[self.index]
self.index += 1
return result
else:
raise StopIteration
# 使用迭代器
my_iter = MyIterator([1, 2, 3, 4, 5])
for item in my_iter:
print(item)
# 输出:
# 1
# 2
# 3
# 4
# 5
# 手动使用迭代器
my_iter = MyIterator([1, 2, 3])
print(next(my_iter)) # 输出: 1
print(next(my_iter)) # 输出: 2
print(next(my_iter)) # 输出: 3
# print(next(my_iter)) # 抛出 StopIteration
2.4.2 生成器(Generator)
什么是生成器?
生成器是一种特殊的迭代器,使用yield语句来生成值,而不是一次性返回所有结果。
创建生成器:
# 方法1:使用yield关键字
def my_generator(n):
for i in range(n):
yield i
# 使用生成器
gen = my_generator(5)
print(next(gen)) # 输出: 0
print(next(gen)) # 输出: 1
print(next(gen)) # 输出: 2
# 在for循环中使用
for num in my_generator(5):
print(num)
# 输出:
# 0
# 1
# 2
# 3
# 4
# 方法2:生成器表达式
gen_expr = (x ** 2 for x in range(5))
for num in gen_expr:
print(num)
# 输出:
# 0
# 1
# 4
# 9
# 16
2.4.3 生成器的优势
1. 内存效率:
# 列表方式(占用大量内存)
def squares_list(n):
return [x ** 2 for x in range(n)]
# 生成器方式(内存友好)
def squares_generator(n):
for x in range(n):
yield x ** 2
# 对比
import sys
# 列表方式
squares = squares_list(1000000)
print(f"List size: {sys.getsizeof(squares)} bytes") # 约8MB
# 生成器方式
gen = squares_generator(1000000)
print(f"Generator size: {sys.getsizeof(gen)} bytes") # 约200字节
2. 惰性求值:
def infinite_counter():
n = 0
while True:
yield n
n += 1
# 无限序列(只在需要时才计算)
counter = infinite_counter()
print(next(counter)) # 输出: 0
print(next(counter)) # 输出: 1
print(next(counter)) # 输出: 2
# 可以无限继续...
2.4.4 生成器的高级用法
发送值到生成器:
def accumulator():
total = 0
while True:
value = yield total
if value is not None:
total += value
acc = accumulator()
next(acc) # 启动生成器
print(acc.send(10)) # 输出: 10
print(acc.send(20)) # 输出: 30
print(acc.send(30)) # 输出: 60
生成器委托:
def sub_generator():
yield "Sub 1"
yield "Sub 2"
yield "Sub 3"
def main_generator():
yield "Main 1"
yield from sub_generator() # 委托给子生成器
yield "Main 2"
for item in main_generator():
print(item)
# 输出:
# Main 1
# Sub 1
# Sub 2
# Sub 3
# Main 2
2.4.5 实用生成器示例
斐波那契数列:
def fibonacci():
a, b = 0, 1
while True:
yield a
a, b = b, a + b
# 获取前10个斐波那契数
fib = fibonacci()
fibonacci_numbers = [next(fib) for _ in range(10)]
print(fibonacci_numbers)
# 输出: [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
读取大文件:
def read_large_file(file_path):
with open(file_path, 'r') as file:
for line in file:
yield line.strip()
# 逐行处理大文件,不占用过多内存
for line in read_large_file('large_file.txt'):
process(line) # 处理每一行
生成器链:
def numbers():
for i in range(10):
yield i
def even_numbers(numbers):
for num in numbers:
if num % 2 == 0:
yield num
def squared(numbers):
for num in numbers:
yield num ** 2
# 链式调用
result = squared(even_numbers(numbers()))
for num in result:
print(num)
# 输出:
# 0
# 4
# 16
# 36
# 64
2.5 异常处理
2.5.1 异常基础
什么是异常?
异常是程序运行时发生的错误,Python使用异常对象来表示错误。
基本语法:
try:
# 可能引发异常的代码
result = 10 / 0
except ZeroDivisionError as e:
# 处理特定异常
print(f"Error: {e}")
except Exception as e:
# 处理其他所有异常
print(f"Unexpected error: {e}")
else:
# 没有异常时执行
print("No errors occurred")
finally:
# 无论是否有异常都会执行
print("This always runs")
# 输出:
# Error: division by zero
# This always runs
2.5.2 常见异常类型
# ZeroDivisionError: 除数为零
try:
result = 10 / 0
except ZeroDivisionError:
print("Cannot divide by zero")
# TypeError: 类型错误
try:
result = "10" + 5
except TypeError as e:
print(f"TypeError: {e}")
# ValueError: 值错误
try:
number = int("abc")
except ValueError as e:
print(f"ValueError: {e}")
# IndexError: 索引越界
try:
items = [1, 2, 3]
print(items[10])
except IndexError as e:
print(f"IndexError: {e}")
# KeyError: 键不存在
try:
data = {"name": "Alice"}
print(data["age"])
except KeyError as e:
print(f"KeyError: {e}")
# FileNotFoundError: 文件不存在
try:
with open("nonexistent.txt") as f:
content = f.read()
except FileNotFoundError as e:
print(f"FileNotFoundError: {e}")
# AttributeError: 属性不存在
try:
text = "hello"
text.append("world")
except AttributeError as e:
print(f"AttributeError: {e}")
2.5.3 自定义异常
# 自定义异常类
class InvalidAgeError(Exception):
"""当年龄无效时抛出"""
pass
class NegativeValueError(Exception):
"""当值为负数时抛出"""
pass
def set_age(age):
if age < 0:
raise NegativeValueError("Age cannot be negative")
if age > 150:
raise InvalidAgeError("Age cannot be greater than 150")
return age
# 使用自定义异常
try:
age = set_age(-5)
except NegativeValueError as e:
print(f"NegativeValueError: {e}")
except InvalidAgeError as e:
print(f"InvalidAgeError: {e}")
else:
print(f"Age set to: {age}")
# 输出: NegativeValueError: Age cannot be negative
2.5.4 异常处理最佳实践
1. 具体捕获异常:
# 好的做法:捕获具体异常
try:
result = 10 / 0
except ZeroDivisionError:
print("Cannot divide by zero")
# 不好的做法:捕获所有异常
try:
result = 10 / 0
except: # 不要这样做!
print("An error occurred")
2. 提供有用的错误信息:
def divide(a, b):
try:
return a / b
except ZeroDivisionError:
raise ValueError(f"Cannot divide {a} by {b}") from None
try:
result = divide(10, 0)
except ValueError as e:
print(f"Error: {e}")
3. 使用finally清理资源:
def process_file(filename):
file = None
try:
file = open(filename, 'r')
content = file.read()
return content
except FileNotFoundError:
print(f"File {filename} not found")
return None
finally:
if file:
file.close()
print("File closed")
# 更好的方式:使用with语句
def process_file(filename):
try:
with open(filename, 'r') as file:
return file.read()
except FileNotFoundError:
print(f"File {filename} not found")
return None
4. 异常链:
def read_config(filename):
try:
with open(filename) as f:
return f.read()
except FileNotFoundError as e:
raise RuntimeError(f"Configuration file {filename} not found") from e
try:
config = read_config("config.txt")
except RuntimeError as e:
print(f"Error: {e}")
print(f"Caused by: {e.__cause__}")
2.5.5 上下文管理器与异常处理
结合上下文管理器处理异常:
from contextlib import contextmanager
@contextmanager
def error_handler(error_message):
try:
yield
except Exception as e:
print(f"{error_message}: {e}")
raise
# 使用
with error_handler("Failed to process data"):
data = [1, 2, 3]
print(data[10]) # IndexError
2.6 上下文管理器
2.6.1 什么是上下文管理器?
上下文管理器是一个对象,它定义了进入和退出上下文时应该执行的代码,主要用于资源管理(如文件、网络连接、锁等)。
2.6.2 使用with语句
基本用法:
# 文件操作
with open('example.txt', 'w') as file:
file.write('Hello, World!')
# 文件自动关闭,即使发生异常
# 线程锁
import threading
lock = threading.Lock()
with lock:
# 临界区代码
print("Critical section")
# 锁自动释放
# 数据库连接(示例)
# with database.connection() as conn:
# cursor = conn.cursor()
# cursor.execute("SELECT * FROM users")
# # 连接自动关闭
2.6.3 创建上下文管理器
方法1:使用类实现__enter__和__exit__方法:
class FileManager:
def __init__(self, filename, mode):
self.filename = filename
self.mode = mode
self.file = None
def __enter__(self):
"""进入上下文时调用"""
self.file = open(self.filename, self.mode)
return self.file
def __exit__(self, exc_type, exc_val, exc_tb):
"""退出上下文时调用"""
if self.file:
self.file.close()
# 返回False会传播异常,返回True会抑制异常
if exc_type is not None:
print(f"An exception occurred: {exc_val}")
return False
# 使用
with FileManager('example.txt', 'w') as f:
f.write('Hello, Context Manager!')
# f.write(None) # 这会引发异常
print("File operations completed")
方法2:使用@contextmanager装饰器:
from contextlib import contextmanager
@contextmanager
def file_manager(filename, mode):
file = open(filename, mode)
try:
yield file
finally:
file.close()
# 使用
with file_manager('example.txt', 'w') as f:
f.write('Hello from contextmanager!')
2.6.4 实用上下文管理器示例
计时上下文管理器:
import time
from contextlib import contextmanager
@contextmanager
def timer(name):
start = time.time()
yield
elapsed = time.time() - start
print(f"{name} took {elapsed:.4f} seconds")
# 使用
with timer("Data processing"):
# 模拟耗时操作
time.sleep(1)
data = [i ** 2 for i in range(100000)]
# 输出: Data processing took 1.0234 seconds
临时修改配置:
from contextlib import contextmanager
@contextmanager
def temporary_setting(obj, attr, value):
"""临时修改对象属性"""
old_value = getattr(obj, attr)
setattr(obj, attr, value)
try:
yield
finally:
setattr(obj, attr, old_value)
# 使用
class Config:
debug = False
config = Config()
print(f"Debug mode: {config.debug}") # 输出: Debug mode: False
with temporary_setting(config, 'debug', True):
print(f"Debug mode: {config.debug}") # 输出: Debug mode: True
# 在这个块中debug为True
print(f"Debug mode: {config.debug}") # 输出: Debug mode: False
数据库事务:
from contextlib import contextmanager
@contextmanager
def database_transaction(connection):
"""模拟数据库事务"""
cursor = connection.cursor()
try:
yield cursor
connection.commit() # 提交事务
print("Transaction committed")
except Exception as e:
connection.rollback() # 回滚事务
print(f"Transaction rolled back: {e}")
raise
finally:
cursor.close()
# 使用示例(伪代码)
# with database_transaction(conn) as cursor:
# cursor.execute("INSERT INTO users VALUES (?, ?)", (1, 'Alice'))
# cursor.execute("INSERT INTO users VALUES (?, ?)", (2, 'Bob'))
抑制异常:
from contextlib import suppress
# 抑制特定异常
with suppress(FileNotFoundError):
with open('nonexistent.txt') as f:
content = f.read()
print("Continuing execution...")
# 输出: Continuing execution...
# 程序不会因为FileNotFoundError而停止
2.6.5 嵌套上下文管理器
from contextlib import contextmanager
@contextmanager
def context_a():
print("Entering A")
yield
print("Exiting A")
@contextmanager
def context_b():
print("Entering B")
yield
print("Exiting B")
# 嵌套使用
with context_a():
with context_b():
print("In both contexts")
# 输出:
# Entering A
# Entering B
# In both contexts
# Exiting B
# Exiting A
# 使用ExitStack管理多个上下文
from contextlib import ExitStack
with ExitStack() as stack:
file1 = stack.enter_context(open('file1.txt', 'w'))
file2 = stack.enter_context(open('file2.txt', 'w'))
# 使用file1和file2
file1.write("Content 1")
file2.write("Content 2")
# 所有文件都会正确关闭
2.7 综合示例
2.7.1 OneForAll中的模块基类
在OneForAll项目中,common/module.py定义了所有收集模块的基类,使用了我们学到的许多概念:
import threading
import time
import requests
from functools import wraps
class Module:
"""OneForAll模块基类"""
def __init__(self):
self.module = 'Module'
self.source = 'BaseModule'
self.header = dict()
self.proxy = None
self.timeout = 30
self.domain = str()
self.subdomains = set()
self.start = time.time()
self.end = None
def begin(self):
"""开始日志"""
print(f"Starting {self.source} module")
def finish(self):
"""完成日志"""
self.end = time.time()
elapse = round(self.end - self.start, 1)
print(f"Finished {self.source} module in {elapse} seconds")
def get(self, url, check=True, **kwargs):
"""HTTP GET请求"""
try:
response = requests.get(url, headers=self.header,
proxies=self.proxy,
timeout=self.timeout, **kwargs)
if check and response.status_code == 200:
return response
return response
except Exception as e:
print(f"Request error: {e}")
return None
def save_db(self):
"""保存结果到数据库"""
# 实现数据库保存逻辑
pass
# 使用装饰器添加日志功能
def log_execution(func):
@wraps(func)
def wrapper(self, *args, **kwargs):
self.begin()
result = func(self, *args, **kwargs)
self.finish()
return result
return wrapper
# 自定义异常
class ModuleError(Exception):
"""模块异常基类"""
pass
class APIError(ModuleError):
"""API调用异常"""
pass
# 使用示例
class MyModule(Module):
def __init__(self):
super().__init__()
self.module = 'MyModule'
self.source = 'MySource'
@log_execution
def run(self, domain):
"""运行模块"""
self.domain = domain
# 模拟收集子域名
self.subdomains = {
f"www.{domain}",
f"mail.{domain}",
f"api.{domain}"
}
self.save_db()
return self.subdomains
# 使用模块
module = MyModule()
subdomains = module.run("example.com")
print(f"Found subdomains: {subdomains}")
2.7.2 实用工具函数
1. 带重试的HTTP请求:
import time
from functools import wraps
def retry(max_attempts=3, delay=1):
"""重试装饰器"""
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
attempts = 0
while attempts < max_attempts:
try:
return func(*args, **kwargs)
except Exception as e:
attempts += 1
if attempts == max_attempts:
raise
time.sleep(delay)
return None
return wrapper
return decorator
@retry(max_attempts=3, delay=2)
def fetch_data(url):
"""获取数据"""
import requests
response = requests.get(url)
response.raise_for_status()
return response.json()
# 使用
try:
data = fetch_data("https://api.example.com/data")
except Exception as e:
print(f"Failed to fetch data: {e}")
2. 缓存装饰器:
import functools
import hashlib
import pickle
import os
def disk_cache(cache_dir="cache"):
"""磁盘缓存装饰器"""
os.makedirs(cache_dir, exist_ok=True)
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
# 生成缓存键
key = hashlib.md5(
pickle.dumps((args, kwargs))
).hexdigest()
cache_file = os.path.join(cache_dir, f"{key}.cache")
# 尝试从缓存读取
if os.path.exists(cache_file):
with open(cache_file, 'rb') as f:
return pickle.load(f)
# 执行函数并缓存结果
result = func(*args, **kwargs)
with open(cache_file, 'wb') as f:
pickle.dump(result, f)
return result
return wrapper
return decorator
@disk_cache()
def expensive_computation(n):
"""耗时的计算"""
print(f"Computing {n}...")
return sum(i ** 2 for i in range(n))
# 第一次调用会执行计算
print(expensive_computation(1000000))
# 第二次调用从缓存读取
print(expensive_computation(1000000))
3. 上下文管理器管理多个资源:
from contextlib import contextmanager, ExitStack
@contextmanager
def resource_manager():
"""管理多个资源"""
with ExitStack() as stack:
# 可以动态添加多个上下文管理器
resources = []
for i in range(3):
resource = stack.enter_context(open(f"file_{i}.txt", "w"))
resources.append(resource)
yield resources
# 所有资源自动关闭
# 使用
with resource_manager() as files:
for i, file in enumerate(files):
file.write(f"Content of file {i}")
2.8 实践任务
任务1:实现一个简单的类层次结构
目标: 创建一个动物类层次结构,演示继承、多态和封装。
要求:
- 创建基类
Animal,包含属性name和age,方法speak()和eat() - 创建子类
Dog和Cat,重写speak()方法 - 添加私有属性和方法,演示封装
- 创建多个动物对象,使用多态调用
speak()方法
代码框架:
# 在这里实现你的代码
class Animal:
pass
class Dog(Animal):
pass
class Cat(Animal):
pass
# 测试代码
animals = [Dog("Buddy", 3), Cat("Whiskers", 2)]
for animal in animals:
print(animal.speak())
任务2:创建和使用装饰器
目标: 实现至少3个实用的装饰器。
要求:
- 创建一个计时装饰器,测量函数执行时间
- 创建一个日志装饰器,记录函数调用信息
- 创建一个缓存装饰器,缓存函数结果
- 应用这些装饰器到示例函数并测试
代码框架:
# 在这里实现你的装饰器
def timer(func):
pass
def logger(func):
pass
def cache(func):
pass
# 测试装饰器
@timer
@logger
@cache
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
print(fibonacci(10))
任务3:实现生成器和迭代器
目标: 创建一个生成器和迭代器来处理数据。
要求:
- 创建一个生成器,生成斐波那契数列
- 创建一个迭代器类,实现倒序遍历
- 使用生成器表达式处理数据
- 比较生成器和列表的内存使用
代码框架:
# 在这里实现你的代码
def fibonacci_generator():
pass
class ReverseIterator:
pass
# 测试代码
fib = fibonacci_generator()
for i in range(10):
print(next(fib))
data = [1, 2, 3, 4, 5]
rev_iter = ReverseIterator(data)
for item in rev_iter:
print(item)
任务4:异常处理练习
目标: 实现一个函数,包含完整的异常处理。
要求:
- 创建一个函数,读取和处理文件
- 处理文件不存在、权限错误、编码错误等异常
- 使用自定义异常
- 使用finally确保资源释放
- 提供有用的错误信息
代码框架:
# 在这里实现你的代码
class FileProcessingError(Exception):
pass
def process_file(filename):
try:
# 实现文件处理逻辑
pass
except Exception as e:
# 处理异常
pass
finally:
# 清理资源
pass
# 测试代码
try:
result = process_file("example.txt")
print(result)
except FileProcessingError as e:
print(f"Error: {e}")
任务5:创建上下文管理器
目标: 实现至少2个实用的上下文管理器。
要求:
- 创建一个计时上下文管理器,测量代码块执行时间
- 创建一个临时目录上下文管理器,自动创建和清理临时目录
- 使用
@contextmanager装饰器实现 - 测试嵌套使用上下文管理器
代码框架:
# 在这里实现你的上下文管理器
from contextlib import contextmanager
@contextmanager
def timer():
pass
@contextmanager
def temp_directory():
pass
# 测试代码
with timer():
with temp_directory() as temp_dir:
print(f"Working in {temp_dir}")
# 在临时目录中工作
2.9 本课总结
本课重点内容回顾
1. 面向对象编程
- 类与对象的概念
- 继承:代码复用和扩展
- 多态:相同方法不同响应
- 封装:隐藏实现细节
- 特殊方法:自定义对象行为
2. 模块和包
- 模块:Python文件作为模块
- 包:包含
__init__.py的目录 - 导入机制:import、from...import
__init__.py的作用- 相对导入和绝对导入
3. 装饰器
- 函数装饰器:不修改原函数添加功能
- 带参数的装饰器
@functools.wraps保留元数据- 类装饰器
- 实用装饰器:计时、日志、缓存
4. 生成器与迭代器
- 迭代器:
__iter__和__next__ - 生成器:
yield关键字 - 生成器表达式
- 内存效率和惰性求值
- 高级用法:send、yield from
5. 异常处理
- try-except-else-finally结构
- 常见异常类型
- 自定义异常
- 异常链
- 最佳实践
6. 上下文管理器
__enter__和__exit__方法@contextmanager装饰器- with语句的使用
- 实用示例:计时、临时修改、事务
下节课预告
第3课:网络编程基础
- HTTP协议详解
- DNS协议原理
- requests库使用
- 代理和认证
- 网络超时处理
- 实践:实现HTTP客户端
课后思考
- 为什么OneForAll要使用模块化的设计?
- 装饰器在OneForAll中有哪些应用场景?
- 生成器在处理大量子域名时有什么优势?
- 如何设计一个良好的异常处理策略?
- 上下文管理器在资源管理中有什么作用?
推荐阅读
- Python官方文档 - 类:https://docs.python.org/zh-cn/3/tutorial/classes.html
- Python官方文档 - 模块:https://docs.python.org/zh-cn/3/tutorial/modules.html
- Python官方文档 - 装饰器:https://docs.python.org/zh-cn/3/glossary.html#term-decorator
- PEP 8 - Python代码风格指南:https://www.python.org/dev/peps/pep-0008/
2.10 附录
附录A:Python特殊方法速查表
class MyClass:
# 对象创建和销毁
def __new__(cls, *args, **kwargs): pass
def __init__(self, *args, **kwargs): pass
def __del__(self): pass
# 字符串表示
def __str__(self): pass
def __repr__(self): pass
# 比较操作
def __eq__(self, other): pass
def __ne__(self, other): pass
def __lt__(self, other): pass
def __gt__(self, other): pass
def __le__(self, other): pass
def __ge__(self, other): pass
# 算术运算
def __add__(self, other): pass
def __sub__(self, other): pass
def __mul__(self, other): pass
def __truediv__(self, other): pass
def __floordiv__(self, other): pass
def __mod__(self, other): pass
def __pow__(self, other): pass
# 容器类型
def __len__(self): pass
def __getitem__(self, key): pass
def __setitem__(self, key, value): pass
def __delitem__(self, key): pass
def __contains__(self, item): pass
def __iter__(self): pass
# 可调用对象
def __call__(self, *args, **kwargs): pass
# 上下文管理器
def __enter__(self): pass
def __exit__(self, exc_type, exc_val, exc_tb): pass
附录B:常用装饰器模板
# 1. 计时装饰器
import time
import functools
def timer(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(f"{func.__name__} took {end - start:.4f} seconds")
return result
return wrapper
# 2. 日志装饰器
import logging
import functools
logging.basicConfig(level=logging.INFO)
def logger(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
logging.info(f"Calling {func.__name__}")
try:
result = func(*args, **kwargs)
logging.info(f"{func.__name__} succeeded")
return result
except Exception as e:
logging.error(f"{func.__name__} failed: {e}")
raise
return wrapper
# 3. 重试装饰器
import time
import functools
def retry(max_attempts=3, delay=1):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
attempts = 0
while attempts < max_attempts:
try:
return func(*args, **kwargs)
except Exception as e:
attempts += 1
if attempts == max_attempts:
raise
time.sleep(delay)
return wrapper
return decorator
# 4. 单例装饰器
def singleton(cls):
instances = {}
@functools.wraps(cls)
def get_instance(*args, **kwargs):
if cls not in instances:
instances[cls] = cls(*args, **kwargs)
return instances[cls]
return get_instance
# 5. 缓存装饰器
import functools
@functools.lru_cache(maxsize=None)
def cached_function(arg):
# 函数实现
pass
附录C:异常处理最佳实践清单
附录D:学习检查清单
恭喜你完成了第2课的学习!🎉
现在你已经掌握了Python的高级特性,包括面向对象编程、模块化设计、装饰器、生成器、异常处理和上下文管理器。这些都是开发OneForAll这样复杂项目所必需的技能。
在下一课中,我们将学习网络编程基础,了解HTTP和DNS协议,为后续学习OneForAll的网络请求和DNS解析功能做好准备。
记住: 理论知识需要通过实践来巩固,一定要动手完成所有的实践任务!
继续加油,我们下节课见!💪

浙公网安备 33010602011771号