第6天-高级特性

2023/6/15

# 第6天-Python高级特性

恭喜你!经过前5天的学习,你已经掌握了Python的基础语法。今天我们来学习Python的高级特性,这些特性让Python变得更加强大和优雅!

# 为什么要学习高级特性?

想象一下:

  • 🚗 普通开车:只会开车,但不知道GPS、自动泊车等高级功能
  • 🏎️ 高级驾驶:熟练使用各种辅助功能,驾驶更轻松高效

Python的高级特性就像汽车的高级功能,让你的编程更加简洁、高效、优雅


# 一、列表推导式(List Comprehension)

# 1.1 什么是列表推导式?

列表推导式是Python创建列表的一种简洁而强大的方法,可以用一行代码完成复杂的列表生成。

生活类比:就像工厂流水线,输入原材料,经过加工,输出成品列表。

# 1.2 基本语法

# 基本语法:[表达式 for 变量 in 可迭代对象]
new_list = [expression for item in iterable]

# 带条件的语法:[表达式 for 变量 in 可迭代对象 if 条件]
new_list = [expression for item in iterable if condition]

# 1.3 从传统方法到列表推导式

# 传统方法:生成1到10的平方
squares_traditional = []
for i in range(1, 11):
    squares_traditional.append(i ** 2)
print(squares_traditional)
# 输出:[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

# 列表推导式:一行搞定!
squares_comprehension = [i ** 2 for i in range(1, 11)]
print(squares_comprehension)
# 输出:[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

# 效果相同,但列表推导式更简洁!

# 1.4 带条件的列表推导式

# 筛选偶数并求平方
numbers = range(1, 11)
even_squares = [x ** 2 for x in numbers if x % 2 == 0]
print(even_squares)  # 输出:[4, 16, 36, 64, 100]

# 处理字符串列表
words = ['hello', 'world', 'python', 'programming']
# 筛选长度大于5的单词并转为大写
long_words = [word.upper() for word in words if len(word) > 5]
print(long_words)  # 输出:['PYTHON', 'PROGRAMMING']

# 处理嵌套数据
students = [('Alice', 85), ('Bob', 92), ('Charlie', 78), ('Diana', 96)]
# 筛选分数大于80的学生姓名
high_scorers = [name for name, score in students if score > 80]
print(high_scorers)  # 输出:['Alice', 'Bob', 'Diana']

# 1.5 嵌套列表推导式

# 创建二维列表(矩阵)
matrix = [[i * j for j in range(1, 4)] for i in range(1, 4)]
print(matrix)
# 输出:[[1, 2, 3], [2, 4, 6], [3, 6, 9]]

# 展平二维列表
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flattened = [num for row in matrix for num in row]
print(flattened)  # 输出:[1, 2, 3, 4, 5, 6, 7, 8, 9]

小白提示:嵌套列表推导式从左到右读:先外层循环,再内层循环。


# 二、字典推导式(Dict Comprehension)

# 2.1 基本语法

# 基本语法:{键表达式: 值表达式 for 变量 in 可迭代对象}
new_dict = {key_expr: value_expr for item in iterable}

# 带条件:{键表达式: 值表达式 for 变量 in 可迭代对象 if 条件}
new_dict = {key_expr: value_expr for item in iterable if condition}

# 2.2 实际应用示例

# 创建数字到平方的映射
square_dict = {x: x**2 for x in range(1, 6)}
print(square_dict)  # 输出:{1: 1, 2: 4, 3: 9, 4: 16, 5: 25}

# 字符串长度映射
words = ['apple', 'banana', 'cherry', 'date']
word_lengths = {word: len(word) for word in words}
print(word_lengths)
# 输出:{'apple': 5, 'banana': 6, 'cherry': 6, 'date': 4}

# 筛选并转换字典
original_dict = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
# 只保留值为偶数的项,并将值翻倍
even_doubled = {k: v*2 for k, v in original_dict.items() if v % 2 == 0}
print(even_doubled)  # 输出:{'b': 4, 'd': 8}

# 交换键值对
original = {'name': 'Alice', 'age': '25', 'city': 'Beijing'}
swapped = {v: k for k, v in original.items()}
print(swapped)  # 输出:{'Alice': 'name', '25': 'age', 'Beijing': 'city'}

# 三、集合推导式(Set Comprehension)

# 3.1 基本用法

# 基本语法:{表达式 for 变量 in 可迭代对象}
new_set = {expression for item in iterable}

# 创建平方数集合
squares_set = {x**2 for x in range(1, 6)}
print(squares_set)  # 输出:{1, 4, 9, 16, 25}

# 去重功能
numbers = [1, 2, 2, 3, 3, 4, 5, 5]
unique_squares = {x**2 for x in numbers}
print(unique_squares)  # 输出:{1, 4, 9, 16, 25}

# 字符串处理
text = "Hello World"
unique_chars = {char.lower() for char in text if char.isalpha()}
print(unique_chars)  # 输出:{'h', 'e', 'l', 'o', 'w', 'r', 'd'}

# 四、生成器(Generator)

# 4.1 什么是生成器?

生成器是一种特殊的迭代器,它按需生成数据,而不是一次性创建所有数据。

生活类比

  • 列表:像一次性买一箱苹果,占用很多冰箱空间
  • 生成器:像果园,需要时才摘一个苹果,节省空间

# 4.2 生成器表达式

# 生成器表达式:用圆括号代替方括号
squares_gen = (x**2 for x in range(1, 6))
print(type(squares_gen))  # 输出:<class 'generator'>

# 逐个获取值
print(next(squares_gen))  # 输出:1
print(next(squares_gen))  # 输出:4
print(next(squares_gen))  # 输出:9

# 或者用for循环遍历
squares_gen = (x**2 for x in range(1, 6))
for square in squares_gen:
    print(square)
# 输出:1 4 9 16 25

# 4.3 yield关键字

def fibonacci_generator(n):
    """生成斐波那契数列的前n项"""
    a, b = 0, 1
    count = 0
    while count < n:
        yield a  # 返回当前值,但函数不结束
        a, b = b, a + b
        count += 1

# 使用生成器
fib_gen = fibonacci_generator(10)
for num in fib_gen:
    print(num, end=' ')
# 输出:0 1 1 2 3 5 8 13 21 34

print()  # 换行

# 生成器的内存优势
def large_range_list(n):
    """传统方法:创建大列表"""
    return [i for i in range(n)]

def large_range_generator(n):
    """生成器方法:按需生成"""
    for i in range(n):
        yield i

# 对比内存使用(这里只是演示概念)
import sys

# 小数据量时差别不大
small_list = large_range_list(100)
small_gen = large_range_generator(100)

print(f"列表大小:{sys.getsizeof(small_list)} 字节")
print(f"生成器大小:{sys.getsizeof(small_gen)} 字节")

# 4.4 生成器的实际应用

def read_large_file(filename):
    """逐行读取大文件,节省内存"""
    with open(filename, 'r', encoding='utf-8') as file:
        for line in file:
            yield line.strip()

def process_data_stream():
    """模拟数据流处理"""
    data = range(1000000)  # 模拟大量数据
    for item in data:
        if item % 2 == 0:  # 只处理偶数
            yield item * 2

# 使用生成器处理大量数据
processed_data = process_data_stream()
# 只取前10个结果
for i, value in enumerate(processed_data):
    if i >= 10:
        break
    print(value, end=' ')
# 输出:0 4 8 12 16 20 24 28 32 36

# 五、迭代器(Iterator)

# 5.1 理解迭代器

# 可迭代对象 vs 迭代器
my_list = [1, 2, 3, 4, 5]  # 可迭代对象
my_iterator = iter(my_list)  # 迭代器

print(type(my_list))      # <class 'list'>
print(type(my_iterator))  # <class 'list_iterator'>

# 使用迭代器
print(next(my_iterator))  # 1
print(next(my_iterator))  # 2
print(next(my_iterator))  # 3

# 迭代器只能向前,不能后退
# print(next(my_iterator))  # 4
# print(next(my_iterator))  # 5
# print(next(my_iterator))  # StopIteration 异常

# 5.2 自定义迭代器

class CountDown:
    """倒计时迭代器"""
    
    def __init__(self, start):
        self.start = start
    
    def __iter__(self):
        return self
    
    def __next__(self):
        if self.start <= 0:
            raise StopIteration
        self.start -= 1
        return self.start + 1

# 使用自定义迭代器
countdown = CountDown(5)
for num in countdown:
    print(f"倒计时:{num}")
# 输出:
# 倒计时:5
# 倒计时:4
# 倒计时:3
# 倒计时:2
# 倒计时:1

# 六、装饰器进阶

# 6.1 带参数的装饰器

def repeat(times):
    """重复执行装饰器"""
    def decorator(func):
        def wrapper(*args, **kwargs):
            for i in range(times):
                result = func(*args, **kwargs)
            return result
        return wrapper
    return decorator

@repeat(3)
def greet(name):
    print(f"Hello, {name}!")

greet("Alice")
# 输出:
# Hello, Alice!
# Hello, Alice!
# Hello, Alice!

# 6.2 类装饰器

class Timer:
    """计时装饰器类"""
    
    def __init__(self, func):
        self.func = func
    
    def __call__(self, *args, **kwargs):
        import time
        start = time.time()
        result = self.func(*args, **kwargs)
        end = time.time()
        print(f"{self.func.__name__} 执行时间:{end - start:.4f}秒")
        return result

@Timer
def slow_function():
    import time
    time.sleep(1)
    return "完成"

result = slow_function()
print(result)

# 6.3 多个装饰器组合

def bold(func):
    def wrapper(*args, **kwargs):
        result = func(*args, **kwargs)
        return f"<b>{result}</b>"
    return wrapper

def italic(func):
    def wrapper(*args, **kwargs):
        result = func(*args, **kwargs)
        return f"<i>{result}</i>"
    return wrapper

@bold
@italic
def say_hello(name):
    return f"Hello, {name}!"

print(say_hello("World"))
# 输出:<b><i>Hello, World!</i></b>

# 七、高阶函数

# 7.1 map()函数

# map(function, iterable) - 将函数应用到每个元素
numbers = [1, 2, 3, 4, 5]

# 使用普通函数
def square(x):
    return x ** 2

squared = list(map(square, numbers))
print(squared)  # [1, 4, 9, 16, 25]

# 使用lambda函数
squared_lambda = list(map(lambda x: x ** 2, numbers))
print(squared_lambda)  # [1, 4, 9, 16, 25]

# 处理字符串
words = ['hello', 'world', 'python']
uppercase = list(map(str.upper, words))
print(uppercase)  # ['HELLO', 'WORLD', 'PYTHON']

# 多个可迭代对象
nums1 = [1, 2, 3]
nums2 = [4, 5, 6]
sums = list(map(lambda x, y: x + y, nums1, nums2))
print(sums)  # [5, 7, 9]

# 7.2 filter()函数

# filter(function, iterable) - 过滤元素
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# 筛选偶数
even_numbers = list(filter(lambda x: x % 2 == 0, numbers))
print(even_numbers)  # [2, 4, 6, 8, 10]

# 筛选大于5的数
greater_than_5 = list(filter(lambda x: x > 5, numbers))
print(greater_than_5)  # [6, 7, 8, 9, 10]

# 筛选非空字符串
words = ['hello', '', 'world', '', 'python']
non_empty = list(filter(None, words))  # None会过滤掉假值
print(non_empty)  # ['hello', 'world', 'python']

# 自定义过滤函数
def is_long_word(word):
    return len(word) > 5

words = ['cat', 'elephant', 'dog', 'hippopotamus']
long_words = list(filter(is_long_word, words))
print(long_words)  # ['elephant', 'hippopotamus']

# 7.3 reduce()函数

from functools import reduce

# reduce(function, iterable[, initializer]) - 累积操作
numbers = [1, 2, 3, 4, 5]

# 计算总和
total = reduce(lambda x, y: x + y, numbers)
print(total)  # 15

# 计算乘积
product = reduce(lambda x, y: x * y, numbers)
print(product)  # 120

# 找最大值
max_value = reduce(lambda x, y: x if x > y else y, numbers)
print(max_value)  # 5

# 字符串连接
words = ['Hello', ' ', 'World', '!']
sentence = reduce(lambda x, y: x + y, words)
print(sentence)  # "Hello World!"

# 带初始值
numbers = [1, 2, 3, 4, 5]
total_with_init = reduce(lambda x, y: x + y, numbers, 100)
print(total_with_init)  # 115 (100 + 15)

# 7.4 zip()函数

# zip(*iterables) - 打包多个可迭代对象
names = ['Alice', 'Bob', 'Charlie']
ages = [25, 30, 35]
cities = ['Beijing', 'Shanghai', 'Guangzhou']

# 基本用法
combined = list(zip(names, ages))
print(combined)  # [('Alice', 25), ('Bob', 30), ('Charlie', 35)]

# 三个列表组合
full_info = list(zip(names, ages, cities))
print(full_info)
# [('Alice', 25, 'Beijing'), ('Bob', 30, 'Shanghai'), ('Charlie', 35, 'Guangzhou')]

# 解包zip结果
for name, age, city in zip(names, ages, cities):
    print(f"{name}, {age}岁, 来自{city}")

# zip的逆操作:解包
combined = [('Alice', 25), ('Bob', 30), ('Charlie', 35)]
names_unpacked, ages_unpacked = zip(*combined)
print(names_unpacked)  # ('Alice', 'Bob', 'Charlie')
print(ages_unpacked)   # (25, 30, 35)

# 不同长度的列表(以最短为准)
short_list = [1, 2]
long_list = [10, 20, 30, 40]
result = list(zip(short_list, long_list))
print(result)  # [(1, 10), (2, 20)]

# 八、上下文管理器(with语句)

# 8.1 文件操作的最佳实践

# 传统方法(不推荐)
file = open('example.txt', 'w')
file.write('Hello, World!')
file.close()  # 容易忘记关闭

# 使用with语句(推荐)
with open('example.txt', 'w') as file:
    file.write('Hello, World!')
# 自动关闭文件,即使出现异常也会关闭

# 读取文件
with open('example.txt', 'r') as file:
    content = file.read()
    print(content)  # Hello, World!

# 8.2 自定义上下文管理器

class Timer:
    """计时上下文管理器"""
    
    def __enter__(self):
        import time
        self.start = time.time()
        print("开始计时...")
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        import time
        self.end = time.time()
        print(f"执行时间:{self.end - self.start:.4f}秒")

# 使用自定义上下文管理器
with Timer():
    import time
    time.sleep(1)
    print("执行一些操作...")
# 输出:
# 开始计时...
# 执行一些操作...
# 执行时间:1.0012秒

# 8.3 使用contextlib简化

from contextlib import contextmanager

@contextmanager
def timer_context():
    import time
    start = time.time()
    print("开始计时...")
    try:
        yield
    finally:
        end = time.time()
        print(f"执行时间:{end - start:.4f}秒")

# 使用
with timer_context():
    import time
    time.sleep(0.5)
    print("执行操作...")

# 九、类型注解(Type Hints)

# 9.1 基本类型注解

# 变量类型注解
name: str = "Alice"
age: int = 25
height: float = 1.68
is_student: bool = True

# 函数类型注解
def greet(name: str, age: int) -> str:
    return f"Hello, {name}! You are {age} years old."

def calculate_area(length: float, width: float) -> float:
    """计算矩形面积"""
    return length * width

# 使用
result = greet("Bob", 30)
area = calculate_area(5.0, 3.0)
print(result)
print(f"面积:{area}")

# 9.2 复杂类型注解

from typing import List, Dict, Tuple, Optional, Union

# 列表类型
def process_numbers(numbers: List[int]) -> List[int]:
    return [n * 2 for n in numbers]

# 字典类型
def get_student_info() -> Dict[str, Union[str, int]]:
    return {"name": "Alice", "age": 20, "grade": "A"}

# 元组类型
def get_coordinates() -> Tuple[float, float]:
    return (39.9042, 116.4074)

# 可选类型
def find_user(user_id: int) -> Optional[str]:
    users = {1: "Alice", 2: "Bob"}
    return users.get(user_id)  # 可能返回None

# 联合类型
def process_id(user_id: Union[int, str]) -> str:
    return str(user_id)

# 使用示例
numbers = [1, 2, 3, 4, 5]
doubled = process_numbers(numbers)
print(doubled)  # [2, 4, 6, 8, 10]

student = get_student_info()
print(student)  # {'name': 'Alice', 'age': 20, 'grade': 'A'}

coords = get_coordinates()
print(coords)  # (39.9042, 116.4074)

user = find_user(1)
print(user)  # Alice

user_id = process_id(123)
print(user_id)  # "123"

# 十、实战练习

# 10.1 数据处理综合练习

# 学生成绩数据处理
students_data = [
    {'name': 'Alice', 'scores': [85, 92, 78, 96]},
    {'name': 'Bob', 'scores': [76, 88, 82, 79]},
    {'name': 'Charlie', 'scores': [95, 87, 91, 93]},
    {'name': 'Diana', 'scores': [68, 74, 82, 79]}
]

# 使用列表推导式计算每个学生的平均分
average_scores = [
    {
        'name': student['name'], 
        'average': sum(student['scores']) / len(student['scores'])
    } 
    for student in students_data
]

print("平均分:")
for student in average_scores:
    print(f"{student['name']}: {student['average']:.2f}")

# 使用filter筛选优秀学生(平均分>85)
excellent_students = list(filter(
    lambda s: s['average'] > 85, 
    average_scores
))

print("\n优秀学生:")
for student in excellent_students:
    print(f"{student['name']}: {student['average']:.2f}")

# 使用map转换数据格式
student_names = list(map(lambda s: s['name'].upper(), excellent_students))
print(f"\n优秀学生姓名(大写):{student_names}")

# 10.2 文件处理生成器

def process_log_file(filename: str):
    """处理日志文件的生成器"""
    try:
        with open(filename, 'r', encoding='utf-8') as file:
            for line_num, line in enumerate(file, 1):
                line = line.strip()
                if line and not line.startswith('#'):  # 跳过空行和注释
                    yield line_num, line
    except FileNotFoundError:
        print(f"文件 {filename} 不存在")

# 创建示例日志文件
with open('sample.log', 'w', encoding='utf-8') as f:
    f.write("""# 这是注释
INFO: 应用启动
WARNING: 内存使用率较高
ERROR: 数据库连接失败
# 另一个注释
INFO: 重新连接成功
""")

# 使用生成器处理文件
print("处理日志文件:")
for line_num, content in process_log_file('sample.log'):
    print(f"第{line_num}行: {content}")

# 10.3 装饰器实战

from functools import wraps
import time

def cache(func):
    """简单的缓存装饰器"""
    cache_dict = {}
    
    @wraps(func)
    def wrapper(*args, **kwargs):
        # 创建缓存键
        key = str(args) + str(sorted(kwargs.items()))
        
        if key in cache_dict:
            print(f"缓存命中: {func.__name__}")
            return cache_dict[key]
        
        print(f"计算中: {func.__name__}")
        result = func(*args, **kwargs)
        cache_dict[key] = result
        return result
    
    return wrapper

def timing(func):
    """计时装饰器"""
    @wraps(func)
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print(f"{func.__name__} 执行时间: {end - start:.4f}秒")
        return result
    return wrapper

@cache
@timing
def fibonacci(n: int) -> int:
    """计算斐波那契数列(递归版本)"""
    if n <= 1:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

# 测试缓存效果
print("第一次计算:")
result1 = fibonacci(10)
print(f"fibonacci(10) = {result1}")

print("\n第二次计算(应该使用缓存):")
result2 = fibonacci(10)
print(f"fibonacci(10) = {result2}")

# 十一、总结

# 11.1 高级特性对比表

特性 优点 使用场景 注意事项
列表推导式 简洁、高效 数据转换、过滤 不要过度复杂化
生成器 节省内存 大数据处理、流式处理 只能遍历一次
装饰器 代码复用、功能增强 日志、缓存、权限验证 理解执行顺序
高阶函数 函数式编程 数据处理、函数组合 可读性考虑
类型注解 代码可读性、IDE支持 大型项目、团队协作 运行时不强制

# 11.2 最佳实践建议

  1. 适度使用:不要为了炫技而使用高级特性
  2. 可读性优先:代码要让其他人能够理解
  3. 性能考虑:在需要时才优化性能
  4. 团队规范:与团队保持一致的编码风格

# 11.3 下一步学习方向

掌握了这些高级特性后,你可以继续学习:

  • 模块和包:代码组织和管理
  • 面向对象编程:类的高级特性
  • 异常处理:错误处理和调试
  • 文件和IO操作:数据持久化
  • 网络编程:Web开发基础

恭喜你!掌握了这些高级特性,你的Python编程能力已经上了一个台阶!🚀


练习建议

  1. 重写之前的代码,使用列表推导式简化
  2. 尝试创建自己的生成器函数
  3. 编写实用的装饰器
  4. 练习使用高阶函数处理数据
  5. 为自己的函数添加类型注解