【AI大模型--python基础】

基础搭建-python基础

#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
=====================================
Python 基础语法与算法综合案例 (Study)
=====================================

本文件系统涵盖 Python 核心知识点:
1. 装饰器模式 (Decorator Pattern) —— 函数增强技术
2. 数学计算与条件分支 —— 一元二次方程求根
3. 可变默认参数陷阱 —— Python 经典"坑"
4. 可变位置参数 *args —— 灵活参数接收
5. 循环嵌套与格式化输出 —— 9×9 乘法表
6. 递归算法 —— 汉诺塔 (经典分治思想)
7. 列表操作与动态规划 —— 杨辉三角形

学习建议:
  - 先理解每个独立模块的原理
  - 关注代码中的注释标注 [★重点] 和 [!注意]
  - 尝试自己实现后再看参考答案

作者:bloxed
日期:2026-03-18
"""

import math
from functools import reduce
import time


# ============================================================
# 模块一:装饰器 (Decorator) —— 函数计时器
# ============================================================
# [★核心概念] 装饰器是一种设计模式,用于在不修改原函数代码的情况下,
#             为函数添加额外功能(如日志、缓存、权限验证、性能监控等)
#             本质是一个高阶函数:接受函数作为参数,返回一个新函数

def timeit(func):
    """
    计时装饰器:测量被装饰函数的执行时间
    
    工作原理:
    ┌─────────────────────────────────────────┐
    │  @timeit                                 │
    │  def my_func():                          │
    │      ...                                 │
    │                                         │
    │  等价于: my_func = timeit(my_func)       │
    │  调用 my_func() 实际调用的是 wrapper()   │
    └─────────────────────────────────────────┘
    
    参数:
        func: 被装饰的函数对象
    
    返回:
        wrapper: 包装后的新函数
    
    [!注意] 使用 functools.wraps 可以保留原函数的元信息
           (如 __name__, __doc__ 等),这里为了简洁省略
    """
    def wrapper(*args, **kwargs):
        """内部包装函数,在执行前后分别记录时间"""
        start_time = time.perf_counter()  # perf_counter 比 time.time() 更精确
        result = func(*args, **kwargs)     # 执行原函数,保留返回值
        end_time = time.perf_counter()
        print(f"[timeit] {func.__name__} 执行耗时: {end_time - start_time:.4f} 秒")
        return result                      # [★关键] 必须返回原函数结果,否则会丢失返回值
    return wrapper


# ============================================================
# 模块二:一元二次方程求解
# ============================================================
# [数学背景] ax² + bx + c = 0 的解由求根公式给出:
#              _______
#     -b ± √b²-4ac
#   x = ─────────────
#            2a

def quadratic(a, b, c):
    """
    求解一元二次方程 ax² + bx + c = 0 的实数根
    
    参数:
        a: 二次项系数 (不能为0, 否则退化为一次方程)
        b: 一次项系数
        c: 常数项
    
    返回:
        无实数解 → None
        一个解(重根) → float
        两个不同解 → tuple(float, float)
    
    [★知识] 判别式 Δ = b² - 4ac 决定了解的情况:
      Δ > 0  → 两个不等实数根
      Δ = 0  → 两个相等实数根 (重根)
      Δ < 0  → 无实数根 (有共轭复数根)
    
    示例:
        >>> quadratic(1, -3, 2)   # x²-3x+2=0 → x=1 或 x=2
        (2.0, 1.0)
        >>> quadratic(1, 2, 1)    # x²+2x+1=0 → x=-1 (重根)
        -1.0
    """
    discriminant = b**2 - 4*a*c  # 计算判别式 Δ
    
    if discriminant < 0:
        return None  # 无实数解 (Δ < 0)
    elif discriminant == 0:
        return -b / (2*a)  # 重根 (Δ = 0), x = -b/(2a)
    else:
        sqrt_disc = math.sqrt(discriminant)  # 开方
        # [★] 同时返回两个根: (-b+√Δ)/2a 和 (-b-√Δ)/2a
        return ((-b + sqrt_disc) / (2*a), (-b - sqrt_disc) / (2*a))


# ============================================================
# 模块三:可变默认参数陷阱
# ============================================================
# [!!!经典面试题] Python 函数的可变对象默认值只会在定义时创建一次!
#
#   错误写法: def add_end(L=[]):  ← [] 只在函数定义时创建一次
#   后续所有不传参的调用都会共享同一个列表对象!
#
#   正确写法: def add_end(L=None): ← None 是不可变的安全默认值

def add_end(L=None):
    """
    向列表末尾追加 'END' 字符串
    
    [!重要] 这是 Python 可变默认参数的经典反例/正例教学
    
    错误演示 (不要这样写):
        >>> def bad_add_end(L=[])
        ...     L.append('END')
        ...     return L
        >>> bad_add_end()    # ['END']
        >>> bad_add_end()    # ['END', 'END'] !! 第二次调用结果不对!
        >>>
        原因: 默认的 [] 是同一个对象,多次调用会累积
    
    正确做法 (当前实现):
        使用 None 作为默认值,每次调用时创建新的空列表
    
    参数:
        L: 列表,默认为None时自动创建新列表
    
    追回:
        追加了'END'的新列表
    """
    if L is None:  # [★] 用 None 作为哨兵值,每次都创建新列表
        L = []
    L.append('END')
    return L


# ============================================================
# 模块四:可变位置参数 *args
# ============================================================
# [★核心概念] *numbers 会将所有传入的位置参数打包成一个元组 (tuple)
#             这让函数可以接受任意数量的参数

def calc(*numbers):
    """
    计算任意数量数字的平方和: Σ(x²)
    
    参数:
        *numbers: 可变数量的数值参数
        
    返回:
        所有参数的平方之和
    
    [★用法演示]:
        >>> calc(1, 2, 3)          # 1² + 2² + 3² = 14
        14
        >>> calc(10)               # 10² = 100
        100
        >>> calc()                 # 无参数 → sum([]) = 0
        0
        >>> calc(*[1, 2, 3])       # 解包列表作为参数传入
        14
    
    相关语法:
        *args     → 接收任意位置参数,打包为元组
        **kwargs  → 接收任意关键字参数,打包为字典
    """
    return sum(x**2 for x in numbers)  # 生成器表达式,内存效率高


# ============================================================
# 模块五:9×9 乘法表 —— 格式化输出与循环嵌套
# ============================================================

@timeit  # [★] 装饰器语法糖,等价于 multiplication_table = timeit(multiplication_table)
def multiplication_table():
    """
    打印 9×9 乘法表 (中国小学经典练习)
    
    输出格式:
        1*1=1 
        1*2=2  2*2=4 
        1*3=3  2*3=6  3*3=9 
        ...
        1*9=9  ...        9*9=81
    
    [★知识点]:
        1. for-else/嵌套循环: 外层控制行(i),内层控制列(j≤i)
        2. f-string 格式化: f"{j}*{i}={i*j}" — Python 3.6+
        3. end=' ': print 默认换行,end='' 可改为其他结尾
        4. @装饰器: 在不改变函数体的情况下附加功能
    """
    for i in range(1, 10):         # 外层循环:被乘数 1~9
        for j in range(1, i + 1):  # 内层循环:乘数 1~i (形成下三角结构)
            print(f"{j}*{i}={i*j}", end=' ')  # 不换行,用空格分隔
        print()  # 每行结束后换行


# 执行乘法表 (带计时)
print("=" * 50)
print("模块五: 9×9 乘法表")
print("=" * 50)
multiplication_table()


# ============================================================
# 模块六:汉诺塔 (Tower of Hanoi) —— 递归算法经典
# ============================================================
# [算法背景]
#   有三根柱子 A/B/C,A柱上有n个大小不同的盘子(大的在下小的在上)
#   目标:将所有盘子从A移动到C,规则:
#     1. 每次只能移动一个盘子
#     2. 大盘子不能放在小盘子上
#
#   [★递归思想 - 分治法 Divide & Conquer]
#     要把 n 个盘子从 A→C (借助 B):
#       Step 1: 把上面 n-1 个盘子 A→B (借助 C)  [递归]
#       Step 2: 把第 n 号盘子(最大的) A→C         [直接完成]
#       Step 3: 把 n-1 个盘子 B→C (借助 A)        [递归]
#
#   时间复杂度: O(2^n) — n个盘子最少需要 2^n - 1 步
#   例如: 64个盘子 ≈ 1.84×10^19 步 (宇宙年龄级别!)

move_count = 0  # [!] 全局变量统计移动次数 (更好的方式是闭包或类属性)


def hanoi(n, source, target, auxiliary):
    """
    汉诺塔递归求解
    
    参数:
        n: 当前要移动的盘子数量 (从大到小编号)
        source:      来源柱子
        target:      目标柱子
        auxiliary:   辅助柱子
    
    [递归终止条件]: n == 1 时直接移动 (最小子问题)
    [递归关系式]: T(n) = 2*T(n-1) + 1,  T(1) = 1
                  解得: T(n) = 2^n - 1
    """
    global move_count  # [!] 使用全局变量计数 (非最佳实践,但便于理解)
    
    if n == 1:
        # [基准情况 Base Case] 只剩一个盘子,直接移到目标
        move_count += 1
        print(f"第{move_count:2d}步: 盘子1 {source}{target}")
    else:
        # [递归情况 Recursive Case] 分三步走
        # Step 1: 先把上面的 n-1 个盘子移到辅助柱
        hanoi(n - 1, source, auxiliary, target)
        
        # Step 2: 把当前最大的盘子移到目标柱
        move_count += 1
        print(f"第{move_count:2d}步: 盘子{n} {source}{target}")
        
        # Step 3: 再把辅助柱上的 n-1 个盘子移到目标柱
        hanoi(n - 1, auxiliary, target, source)


# 测试汉诺塔 (小规模演示)
print("\n" + "=" * 50)
print("模块六: 汉诺塔 (3个盘子)")
print("=" * 50)
move_count = 0  # 重置计数器
hanoi(3, 'A', 'C', 'B')  # 3个盘子: A→C, B辅助, 共需 2³-1=7 步
print(f"\n总计移动 {move_count} 步 (理论值: 2^3-1 = {2**3-1})")


# ============================================================
# 模块七:杨辉三角形 (Pascal's Triangle) —— 组合数学与动态规划
# ============================================================
# [数学背景]
#   杨辉三角的第 n 行对应二项式 (a+b)^n 展开式的系数
#   每个数等于它上方两数之和: C(n,k) = C(n-1,k-1) + C(n-1,k)
#
#   结构示意 (前5行):
#            1              (n=0)
#          1   1            (n=1)
#        1   2   1          (n=2)
#      1   3   3   1        (n=3)
#    1   4   6   4   1      (n=4)
#
# [★性质]:
#   1. 第n行有 n+1 个元素
#   2. 每行首尾都是 1
#   3. 对称性: 第k个元素 = 第(n-k+1)个元素
#   4. 第n行元素之和 = 2^n

def pascal_triangle(n):
    """
    生成杨辉三角形的前 n 行
    
    参数:
        n: 需要生成的行数
    
    返回:
        triangle: 二维列表,包含每一行的数据
    
    [算法思路 - 动态规划]:
        每行的值依赖上一行:
        triangle[i][j] = triangle[i-1][j-1] + triangle[i-1][j]
        (首尾元素恒为1,不需要计算)
    
    时间复杂度: O(n²)
    空间复杂度: O(n²) (存储完整三角形)
    
    [进阶优化] 可以只用 O(n) 空间,只保留上一行即可
    """
    triangle = []
    for i in range(n):                    # i: 当前行号 (0-indexed)
        row = [1] * (i + 1)               # [★技巧] 先初始化全1,再更新中间值
        for j in range(1, i):             # j=0 和 j=i 已经是1,只需计算中间
            # [★核心公式] 每个数等于上方两数之和
            row[j] = triangle[i - 1][j - 1] + triangle[i - 1][j]
        triangle.append(row)
        print(row)  # 打印当前行
    return triangle


# 测试杨辉三角 (打印前10行)
print("\n" + "=" * 50)
print("模块七: 杨辉三角形 (前10行)")
print("=" * 50)
pascal_triangle(10)

# ============================================================
# 附加: 快速验证 quadratic 函数
# ============================================================
print("\n" + "=" * 50)
print("附加: 一元二次方程验证")
print("=" * 50)

test_cases = [
    (1, -3, 2, "x^2-3x+2=0 (two real roots: 1, 2)"),
    (1, 2, 1, "x^2+2x+1=0 (double root: -1)"),
    (1, 1, 1, "x^2+x+1=0 (no real root)"),
]

for a, b, c, desc in test_cases:
    result = quadratic(a, b, c)
    print(f"  {desc}")
    if result is None:
        print(f"    Result: No real roots (discriminant < 0)")
    elif isinstance(result, tuple):
        print(f"    Result: x1 = {result[0]}, x2 = {result[1]}")
    else:
        print(f"    Result: x = {result} (double root)")
    print()

print("=" * 50)
print("全部模块运行完毕!")
print("=" * 50)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值