📍 第 1 课:Python 基础语法 - 数据类型 & 列表操作

📝 知识点

  1. 基本数据类型

    • int(整数):a = 5
    • float(小数):b = 3.14
    • str(字符串):s = "hello"
    • bool(布尔):flag = True
  2. 列表(list)

    • 创建:nums = [1, 2, 3]
    • 访问:nums[0] → 1
    • 修改:nums[1] = 10[1, 10, 3]
    • 添加:nums.append(4)[1, 10, 3, 4]
    • 删除:nums.pop() → 删除最后一个
  3. 列表推导式(常考!)

    squares = [x*x for x in range(5)]
    # [0, 1, 4, 9, 16]

💡 小练习

  1. 创建一个列表 [1, 2, 3, 4, 5],把每个元素平方,得到 [1, 4, 9, 16, 25]
  2. 写一个函数 filter_even(nums),输入一个数字列表,返回所有偶数。
from operator import truediv
from tokenize import endpats

# 1. 创建一个列表 `[1, 2, 3, 4, 5]`,把每个元素平方,得到 `[1, 4, 9, 16, 25]`。
nums = [1, 2, 3, 4, 5]
squares = [x*x for x in nums]
print(squares)
[1, 4, 9, 16, 25]
# 2. 写一个函数 `filter_even(nums)`,输入一个数字列表,返回所有偶数。
def filter_even1(nums):
result = []
for x in nums:
if x % 2 == 0:
result.append(x)
return result

nums = [1, 2, 3, 4, 5, 6]
print(filter_even1(nums))
[2, 4, 6]
def filter_even2(nums):
return [x for x in nums if x % 2 == 0]
print(filter_even2(nums))
[2, 4, 6]

📍 第 2 课:字符串操作

📝 常用操作

  1. 创建与访问
s = "hello"
print(s[0]) # h
print(s[-1]) # o
  1. 切片
print(s[1:4])   # ell
print(s[::-1]) # olleh (倒序)
  1. 常用方法
s.upper()      # "HELLO"
s.lower() # "hello"
s.strip() # 去掉首尾空格
s.split(" ") # 按空格分割成列表
"-".join(["a", "b", "c"]) # "a-b-c"
  1. 判断
s.startswith("he")   # True
s.endswith("lo") # True
"e" in s # True

💡 小练习

写一个函数 count_vowels(s),统计字符串里有多少个元音字母(a, e, i, o, u,不区分大小写)。

例子:

count_vowels("Hello World")
# 输出 3 (e, o, o)
# 写一个函数 `count_vowels(s)`,统计字符串里有多少个元音字母(a, e, i, o, u,不区分大小写)。
def count_vowels(s):
count = 0
for c in s:
if c.lower() in "aeiou":
count += 1
return count

s = "aeiouabc"
print(count_vowels(s))
6

✅ 小总结:

用 for 遍历字符串,就像遍历列表一样。

判断条件时,最好把大小写统一(比如 lower())。

在 Python 里没有 ++,用 += 1。

📍 字符串练习题

练习 1:反转字符串

写一个函数 reverse_str(s),输入 "hello",返回 "olleh"
👉 提示:可以用切片 [::-1]

练习 2:判断回文

写一个函数 is_palindrome(s),判断字符串是否是回文(正着读和倒着读一样)。
例子:

  • "level" → True
  • "python" → False

👉 提示:可以比较 s == s[::-1]

练习 3:统计单词频率

写一个函数 word_count(s),输入一个句子,输出每个单词出现的次数。
例子:

word_count("hello world hello")
# 输出: {"hello": 2, "world": 1}

👉 提示:可以用 split() 把字符串切成单词,再用字典计数。

# 1.反转字符串
def reverse_str(s):
return s[::-1]

s = "good"
print(reverse_str(s))
doog
# 2.判断回文
def is_palindrome(s):
return s[::-1] == s

print(is_palindrome("level"))
print(is_palindrome("python"))
True
False
# 3.统计单词频率
# 方法 1:普通字典 + if 判断
def word_count(s):
counts = {}
words = s.split()
for w in words:
if w in counts:
counts[w] += 1
else:
counts[w] = 1
return counts

print(word_count("hello world hello"))
{'hello': 2, 'world': 1}
# 方法 2:collections.Counter
from collections import Counter

def word_count(s):
words = s.split()
return dict(Counter(words))
print(word_count("hello world hello"))

{'hello': 2, 'world': 1}

总结

  • 列表推导式 → “一行筛选变换”
  • 切片 → s[::-1](反转)、s[a:b](截取)
  • 字典计数 → if key in dict else …,或者直接用 Counter

📍 第 3 课:类与对象

📝 基础概念

  1. **类 (class)**:一张“设计图”,定义了对象的属性和方法。
  2. **对象 (object)**:类的实例,可以用类里定义的功能。

🔹 示例 1:最简单的类

class Person:
def __init__(self, name, age): # 构造方法,初始化对象
self.name = name # 给对象加属性
self.age = age

def say_hello(self): # 定义一个方法
print(f"Hi, I am {self.name}, {self.age} years old.")

使用:

p1 = Person("Alice", 20)
p1.say_hello()

输出:

Hi, I am Alice, 20 years old.

🔹 示例 2:类的继承

class Student(Person):              # Student 继承 Person
def __init__(self, name, age, student_id):
super().__init__(name, age) # 调用父类的构造方法
self.student_id = student_id

def study(self):
print(f"{self.name} is studying...")

使用:

s1 = Student("Bob", 21, "2024001")
s1.say_hello()
s1.study()

💡 小练习

写一个 BankAccount 类

  • 初始化时有一个 balance(余额,默认 0)

  • 方法:

    • deposit(amount):存钱
    • withdraw(amount):取钱(余额不足时要提示)
    • get_balance():返回余额
class BankAccount():
def __init__(self, balance):
self.balance = balance

def deposit(self, amount):
self.balance += amount

def withdraw(self, amount):
if self.balance >= amount:
self.balance -= amount
print("取钱成功")
else:
print("余额不足")

def get_balance(self):
return self.balance

acct = BankAccount(100)
acct.deposit(50)
print(acct.get_balance()) # 150

acct.withdraw(70) # 取钱成功
print(acct.get_balance()) # 80

acct.withdraw(100) # 余额不足
150
取钱成功
80
余额不足

📍 第 4 课:类方法 & 静态方法

1. 普通方法(实例方法)

  • 第一个参数是 self,表示对象本身。
  • 只能通过 对象 来调用。
class Dog:
def __init__(self, name):
self.name = name

def bark(self): # 实例方法
print(f"{self.name} is barking!")

d = Dog("Lucky")
d.bark() # Lucky is barking!

2. 类方法(@classmethod)

  • 第一个参数是 cls,表示类本身。
  • 常用于 工厂方法:创建对象的另一种方式。
class Dog:
def __init__(self, name):
self.name = name

@classmethod
def from_dict(cls, data): # 工厂方法
return cls(data["name"])

dog_data = {"name": "Coco"}
d2 = Dog.from_dict(dog_data)
print(d2.name) # Coco

3. 静态方法(@staticmethod)

  • 没有 selfcls 参数。
  • 更像是“放在类里面的普通函数”,和类逻辑相关,但不依赖类或对象。
class MathUtils:
@staticmethod
def add(a, b):
return a + b

print(MathUtils.add(3, 5)) # 8

💡 小练习

写一个 Student 类:

  • 属性:name

  • 方法:

    • 普通方法:say_hello() → 打印 “I am XXX”
    • 类方法:from_string(s) → 输入 "Alice", 返回 Student("Alice")
    • 静态方法:is_valid_name(name) → 判断名字是否全是字母
class Student():
def __init__(self, name):
self.name = name

def say_hello(self):
print(f"I am {self.name}")

@classmethod
def from_string(cls, s):
return cls(s)

@staticmethod
def is_valid_name(name):
return name.isalpha()

s1 = Student("Alice")
s1.say_hello() # I am Alice

s2 = Student.from_string("Bob")
s2.say_hello() # I am Bob

print(Student.is_valid_name("Charlie")) # True
print(Student.is_valid_name("Tom123")) # False
I am Alice
I am Bob
True
False

📍 第 5 课:常见魔术方法

1. __str__ —— 对象的可读字符串

class Student:
def __init__(self, name, score):
self.name = name
self.score = score

def __str__(self):
return f"Student(name={self.name}, score={self.score})"

s = Student("Alice", 95)
print(s) # Student(name=Alice, score=95)

👉 没有 __str__ 的话,print(s) 会显示 <__main__.Student object at 0x...>,不直观。


2. __len__ —— 定义 len(obj)

class Classroom:
def __init__(self, students):
self.students = students

def __len__(self):
return len(self.students)

c = Classroom(["Alice", "Bob", "Charlie"])
print(len(c)) # 3

3. __iter____next__ —— 让对象可迭代

class Countdown:
def __init__(self, start):
self.start = start

def __iter__(self): # 返回一个迭代器
self.current = self.start
return self

def __next__(self): # 每次迭代返回一个值
if self.current <= 0:
raise StopIteration
self.current -= 1
return self.current + 1

for num in Countdown(3):
print(num) # 3, 2, 1

💡 小练习

写一个 Book 类:

  • 属性:title(书名)、pages(页数)

  • 魔术方法:

    • __str__ → 打印时显示 "Book: <title>, <pages> pages"
    • __len__ → 返回页数

例子:

b = Book("Python Guide", 350)
print(b) # Book: Python Guide, 350 pages
print(len(b)) # 350
class Book():
def __init__(self, title, pages):
self.title = title
self.pages = pages

def __str__(self):
return f"Book: {self.title}, {self.pages} pages"

def __len__(self):
return self.pages

b = Book("Python Guide", 350)
print(b) # Book: Python Guide, 350 pages
print(len(b)) # 350
Book: Python Guide, 350 pages
350

📍 第 6 课:生成器 (Generator)

1. 什么是生成器?

  • 普通函数用 return,一次性返回结果,函数就结束了。
  • 生成器函数yield,每次返回一个值,但函数不会结束,可以继续执行。
  • 生成器特别适合处理 大量数据流式数据

2. 基本例子

def simple_gen():
yield 1
yield 2
yield 3

g = simple_gen()
print(next(g)) # 1
print(next(g)) # 2
print(next(g)) # 3
# print(next(g)) 会报 StopIteration

3. 生成器的好处

节省内存。例如生成 1 到 1000000 的平方:

def squares(n):
for i in range(n):
yield i * i

gen = squares(1000000)
print(next(gen)) # 0
print(next(gen)) # 1
print(next(gen)) # 4

👉 如果用列表,会占用很大内存;生成器是“按需生成”的。


💡 小练习

写一个生成器函数 countdown(n),依次返回:

n, n-1, n-2, ..., 1

例子:

for x in countdown(5):
print(x)

输出:

5
4
3
2
1
# 写一个生成器函数 `countdown(n)`,依次返回:n, n-1, n-2, ..., 1
def countdown(n):
for i in range(n, 0, -1):
yield i

for x in countdown(5):
print(x)
5
4
3
2
1

✅ 小结:

  • 用 yield 可以把函数变成生成器。

  • 每次迭代时,函数会停在 yield 处,下次从那里继续。

  • 生成器适合处理“大量、逐步产生”的数据。

📍 第 7 课:装饰器 (Decorator)

1. 装饰器是什么?

  • 本质:装饰器就是一个函数,用来增强其他函数的功能,但不需要修改原函数的代码。
  • @装饰器名 放在函数定义上方,就能自动应用。

2. 基本例子

def my_decorator(func):
def wrapper():
print("函数执行前做点事情")
func()
print("函数执行后做点事情")
return wrapper

@my_decorator
def say_hello():
print("Hello!")

say_hello()

输出:

函数执行前做点事情
Hello!
函数执行后做点事情

👉 @my_decorator 就等价于:

say_hello = my_decorator(say_hello)

3. 带参数的函数

def log_decorator(func):
def wrapper(*args, **kwargs):
print(f"调用 {func.__name__},参数: {args}, {kwargs}")
result = func(*args, **kwargs)
print(f"结果: {result}")
return result
return wrapper

@log_decorator
def add(a, b):
return a + b

add(3, 5)

输出:

调用 add,参数: (3, 5), {}
结果: 8

💡 小练习

写一个装饰器 timeit,计算函数运行时间。
例子:

@timeit
def slow_func():
for i in range(1000000):
pass

slow_func()

👉 输出类似:

函数 slow_func 执行耗时: 0.05 秒

# 写一个装饰器 timeit,计算函数运行时间。
import time
def timeit(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f"函数 {func.__name__} 执行耗时:{end_time - start_time:.5f} 秒")
return wrapper

@timeit
def slow_func():
for i in range(1000000):
pass

slow_func()


函数 slow_func 执行耗时:0.03480 秒

📍 第 8 课:迭代器 (Iterator)

1. 什么是迭代器?

  • **可迭代对象 (Iterable)**:能用 for ... in ... 遍历,比如 liststrdict

  • **迭代器 (Iterator)**:一种能逐个取出元素的对象,支持两个方法:

    • __iter__()
    • __next__()

👉 用内置函数 iter() 可以把可迭代对象变成迭代器,用 next() 取元素。


2. 基本例子

nums = [1, 2, 3]
it = iter(nums) # 得到一个迭代器

print(next(it)) # 1
print(next(it)) # 2
print(next(it)) # 3
# print(next(it)) # StopIteration(没有元素了)

3. 自定义迭代器

我们可以写一个类,让它支持迭代。

class Countdown:
def __init__(self, start):
self.start = start

def __iter__(self): # 返回迭代器对象
self.current = self.start
return self

def __next__(self): # 定义取下一个元素的逻辑
if self.current <= 0:
raise StopIteration
self.current -= 1
return self.current + 1

for x in Countdown(5):
print(x)

输出:

5
4
3
2
1

💡 小练习

写一个迭代器类 EvenNumbers(n)

  • 迭代从 0n 之间的所有偶数。

例子:

for x in EvenNumbers(10):
print(x)

输出:

0
2
4
6
8
10

class EvenNumbers:
def __init__(self, end):
self.end = end

def __iter__(self):
self.current = 0
return self

def __next__(self):
if self.current > self.end:
raise StopIteration
result = self.current
self.current += 2
return result

for x in EvenNumbers(10):
print(x)
0
2
4
6
8
10

✅ 小总结:

  • iter → 返回迭代器本身

  • next → 定义“下一个元素怎么产生”,没了就 StopIteration

  • 迭代器 = 一次性遍历的数据流,和生成器很像(生成器其实就是迭代器的语法糖)。

📍 第 9 课:异常处理

1. 什么是异常?

程序运行时遇到错误时,会抛出异常(Exception),默认会导致程序崩溃。
👉 用 try / except 可以优雅地捕获错误,避免程序中断。


2. 基本语法

try:
x = 1 / 0 # 这里会报错 ZeroDivisionError
except ZeroDivisionError:
print("不能除以 0")

输出:

不能除以 0

3. 捕获多种异常

try:
num = int("abc")
except ValueError:
print("输入不是整数")
except ZeroDivisionError:
print("除零错误")

4. 捕获所有异常

try:
f = open("not_exist.txt")
except Exception as e: # 捕获所有异常
print("出错了:", e)

5. finally 子句(无论如何都会执行)

try:
f = open("data.txt")
print(f.read())
except FileNotFoundError:
print("文件不存在")
finally:
print("程序结束,关闭资源")

💡 小练习

写一个函数 safe_divide(a, b)

  • 返回 a / b 的结果
  • 如果 b == 0,捕获异常并返回 "除数不能为 0"

例子:

print(safe_divide(10, 2))   # 5.0
print(safe_divide(8, 0)) # "除数不能为 0"

def safe_divide(a, b):
try:
return a / b
except ZeroDivisionError:
return "除数不能为 0"

print(safe_divide(10, 2))
print(safe_divide(8, 0))
5.0
除数不能为 0

📍 第 10 课:上下文管理器 (with)

1. 问题引入

打开文件时,如果忘记 close(),可能会导致资源泄露:

f = open("test.txt", "w")
f.write("hello")
f.close() # 必须手动关闭

如果中间报错,f.close() 可能不会执行。


2. with 自动管理资源

with 语句会在代码块结束时,自动调用资源的关闭方法,不管中间有没有异常。

with open("test.txt", "w") as f:
f.write("hello")
# 这里自动关闭 f

3. 自定义上下文管理器

只要一个类实现了:

  • __enter__():进入时执行
  • __exit__(self, exc_type, exc_val, exc_tb):退出时执行(不管有没有异常)
class MyContext:
def __enter__(self):
print("进入上下文")
return "资源"

def __exit__(self, exc_type, exc_val, exc_tb):
print("退出上下文")
return False # 如果返回 True,异常会被忽略

with MyContext() as res:
print("使用中:", res)

输出:

进入上下文
使用中: 资源
退出上下文

💡 小练习

写一个上下文管理器 FileWriter

  • 初始化时传入文件名
  • __enter__:打开文件(写模式),返回文件对象
  • __exit__:关闭文件

例子:

with FileWriter("output.txt") as f:
f.write("Hello Python")

# FileWriter:
# 1.初始化时传入文件名
# 2.__enter__:打开文件(写模式),返回文件对象
# 3.__exit__:关闭文件

class FileWriter:
def __init__(self, file_name):
self.file_name = file_name

def __enter__(self):
self.f = open(self.file_name, "w")
return self.f
def __exit__(self, exc_type, exc_val, exc_tb):
self.f.close()

with FileWriter("output.txt") as f:
f.write("Hello Python")

✅ 小结:

  • with = 自动帮你调用 enterexit

  • 常用于:文件操作、数据库连接、网络请求、锁 (threading.Lock)

  • exit 的参数 exc_type, exc_val, exc_tb 可以用来处理异常

📍 第 11 课:单元测试 (unittest)

1. 为什么要写测试?

  • 确保函数/类逻辑正确
  • 修改代码时防止“牵一发而动全身”
  • 大厂工程开发必备技能

2. unittest 最小结构

import unittest

def add(a, b):
return a + b

class TestAdd(unittest.TestCase):
def test_add(self):
self.assertEqual(add(2, 3), 5)

if __name__ == "__main__":
unittest.main()

运行这个脚本,终端会输出绿色 “OK”,说明通过。


3. 常用断言

  • assertEqual(a, b):判断相等
  • assertTrue(x) / assertFalse(x):判断真假
  • assertIn(x, container) / assertNotIn(x, container):判断是否包含
  • assertRaises(Error, func, *args):判断是否抛出异常

4. 应用到我们之前的代码

比如 BankAccount 类

class BankAccount:
def __init__(self, balance=0):
self.balance = balance
def deposit(self, amount):
self.balance += amount
def withdraw(self, amount):
if self.balance >= amount:
self.balance -= amount
return True
return False
def get_balance(self):
return self.balance

测试样例:

class TestBankAccount(unittest.TestCase):
def test_deposit_and_balance(self):
acct = BankAccount(100)
acct.deposit(50)
self.assertEqual(acct.get_balance(), 150)

def test_withdraw_success(self):
acct = BankAccount(80)
ok = acct.withdraw(30)
self.assertTrue(ok)
self.assertEqual(acct.get_balance(), 50)

💡 小练习

请你在 TestBankAccount 里再写一个测试:

  • 初始余额是 50
  • 尝试取 100(应失败)
  • 检查返回值为 False,余额依然是 50

👉 你能写出 test_withdraw_fail_balance_unchanged 吗?

import unittest

class TestBankAccount(unittest.TestCase):
def test_deposit_and_balance(self):
acct = BankAccount(100)
acct.deposit(50)
self.assertEqual(acct.get_balance(), 150)

def test_withdraw_success(self):
acct = BankAccount(80)
ok = acct.withdraw(30)
self.assertTrue(ok)
self.assertEqual(acct.get_balance(), 50)

def test_withdraw_fail_balance_unchanged(self):
acct = BankAccount(80)
fail = acct.withdraw(90)
self.assertFalse(fail)
self.assertEqual(acct.get_balance(), 80)

📍 第 12 课:日志 (logging)

1. 为什么用日志?

  • print() 只能简单输出,不能分级别,也不好存文件。
  • logging 模块可以记录 调试、警告、错误 等信息,并保存到文件,方便排查问题。

2. logging 的基本用法

import logging

logging.basicConfig(level=logging.INFO)

logging.debug("这是调试信息") # 级别最低,一般开发调试时用
logging.info("程序运行正常") # 常规运行信息
logging.warning("这是警告") # 程序可能有问题
logging.error("这是错误") # 出现错误
logging.critical("严重错误!") # 系统可能要崩溃

👉 默认只显示 WARNING 及以上的日志,所以 debug/info 不会输出。


3. 设置日志格式

logging.basicConfig(
level=logging.INFO,
format="%(asctime)s - %(levelname)s - %(message)s"
)

logging.info("程序启动")

输出示例:

2025-08-20 10:23:45,123 - INFO - 程序启动

4. 日志写入文件

logging.basicConfig(
filename="app.log",
level=logging.INFO,
format="%(asctime)s - %(levelname)s - %(message)s"
)

logging.error("这是写入文件的错误日志")

👉 会在当前目录生成 app.log 文件。


💡 小练习

请你用 logging 改造之前的 safe_divide(a, b)

  • 除法成功时,记录 INFO 日志,打印结果。
  • 除以 0 时,记录 ERROR 日志,提示错误。

👉 你要不要试着写一版改造后的 safe_divide

import logging

logging.basicConfig(
level=logging.INFO,
format="%(asctime)s - %(levelname)s - %(message)s"
)
def safe_divide(a, b):
try:
c = a / b
logging.info(f"除法成功,结果为:{c}")
return c
except ZeroDivisionError:
logging.error(f"除法失败,不能除以 0")
return "除数不能为 0"

safe_divide(10, 2)
safe_divide(8, 0)
INFO:root:除法成功,结果为:5.0
ERROR:root:除法失败,不能除以 0





'除数不能为 0'

好👌 我们来进入 Numpy —— Python 里做数值计算的必备库。


📍 第 13 课:Numpy 基础

1. 什么是 Numpy?

  • 一个高性能的 数值计算库,支持多维数组(ndarray)。
  • 比 Python 自带的 list 更快、更省内存。
  • pandas、机器学习、深度学习 的底层依赖。

2. 创建数组

import numpy as np

arr1 = np.array([1, 2, 3]) # 从列表创建
arr2 = np.zeros((2, 3)) # 2x3 全 0 矩阵
arr3 = np.ones((3, 3)) # 3x3 全 1 矩阵
arr4 = np.arange(0, 10, 2) # [0, 2, 4, 6, 8]
arr5 = np.linspace(0, 1, 5) # 等间距 [0,0.25,0.5,0.75,1]

3. 基本属性

arr = np.array([[1, 2, 3], [4, 5, 6]])
print(arr.shape) # (2, 3) 维度
print(arr.ndim) # 2 维度数
print(arr.size) # 6 元素个数
print(arr.dtype) # int64 数据类型

4. 运算

a = np.array([1, 2, 3])
b = np.array([4, 5, 6])

print(a + b) # [5 7 9]
print(a * b) # [4 10 18]
print(a.dot(b)) # 点积 1*4+2*5+3*6 = 32
print(np.mean(a)) # 平均值
print(np.max(b)) # 最大值

5. 索引 & 切片

arr = np.array([[1, 2, 3],
[4, 5, 6]])

print(arr[0, 1]) # 2 (第一行第二列)
print(arr[:, 0]) # [1 4] (第一列)
print(arr[1, :]) # [4 5 6] (第二行)

💡 小练习

写一个函数 vector_stats(arr),输入一个一维 Numpy 数组,返回:

  • 平均值
  • 最大值
  • 最小值

例子:

import numpy as np
a = np.array([3, 7, 2, 9, 5])
print(vector_stats(a))

输出:

(5.2, 9, 2)

👉 要不要你来试试写 vector_stats

import numpy as np

def vector_stats(arr):
return {
"mean": np.mean(arr),
"max": np.max(arr),
"min": np.min(arr)
}

a = np.array([3, 7, 2, 9, 5])
print(vector_stats(a))
{'mean': 5.2, 'max': 9, 'min': 2}

好,我们来学 矩阵运算,这是 Numpy 的核心技能。


📍 第 14 课:Numpy 矩阵运算

1. 矩阵创建

import numpy as np

A = np.array([[1, 2],
[3, 4]])
B = np.array([[5, 6],
[7, 8]])

2. 基本运算

print(A + B)   # 矩阵加法 [[6 8], [10 12]]
print(A - B) # 矩阵减法 [[-4 -4], [-4 -4]]
print(A * B) # 对应元素相乘 [[5 12], [21 32]]

3. 矩阵乘法 (dot / @)

print(A.dot(B))
# [[19 22]
# [43 50]]

print(A @ B) # 和 A.dot(B) 等价

4. 常用矩阵操作

print(A.T)       # 转置 [[1 3], [2 4]]
print(np.linalg.inv(A)) # 逆矩阵 [[-2. 1. ]
# [ 1.5 -0.5]]
print(np.linalg.det(A)) # 行列式 -2.0

5. 单位矩阵 & 矩阵乘法验证

I = np.eye(2)   # 2x2 单位矩阵
print(A @ I) # 结果等于 A 本身

💡 小练习

写一个函数 matrix_ops(A, B),输入两个二维数组,返回:

  • 它们的加法结果
  • 它们的矩阵乘法结果
  • A 的转置

例子:

A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
print(matrix_ops(A, B))

期望输出(可以是元组):

(
[[ 6 8]
[10 12]],

[[19 22]
[43 50]],

[[1 3]
[2 4]]
)

👉 你要不要先试着写 matrix_ops

import numpy as np

def matrix_ops(A, B):
add = A + B
muti = A.dot(B)
return add, muti, A.T

A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])

print(matrix_ops(A, B))
(array([[ 6,  8],
       [10, 12]]), array([[19, 22],
       [43, 50]]), array([[1, 3],
       [2, 4]]))

好👌 我们来学习 Numpy 随机数与模拟


📍 第 15 课:Numpy 随机数与模拟

1. 生成随机数

import numpy as np

print(np.random.rand(3)) # [0.1 0.7 0.3] 0~1之间的随机数
print(np.random.rand(2, 3)) # 2x3 矩阵
print(np.random.randn(3)) # 标准正态分布(均值0,方差1)

2. 随机整数

print(np.random.randint(0, 10, size=5))   # [2 9 4 7 1],0~9 的随机整数

3. 控制随机性(随机种子)

np.random.seed(42)
print(np.random.rand(3)) # 每次运行结果相同

4. 常用分布

print(np.random.normal(loc=10, scale=2, size=5))
# 平均值10,标准差2,生成5个正态分布数

print(np.random.binomial(n=10, p=0.5, size=5))
# 5次实验,每次进行10次伯努利试验,成功概率0.5

5. 随机打乱与抽样

arr = np.arange(10)
np.random.shuffle(arr) # 原地打乱
print(arr)

print(np.random.choice(arr, size=5, replace=False))
# 从 arr 中随机抽 5 个不重复元素

💡 小练习

写一个函数 simulate_dice(n)

  • 模拟掷 n 次骰子(点数 1-6)
  • 返回每个点数出现的次数(用字典表示)

例子:

print(simulate_dice(20))

可能输出:

{1: 3, 2: 2, 3: 5, 4: 4, 5: 3, 6: 3}

👉 要不要你来写 simulate_dice

import numpy as np

def simulate_dice(n):
results = np.random.randint(1, 7, size=n)
counts = {i: 0 for i in range(1, 7)}
for x in results:
counts[x] += 1
return counts

print(simulate_dice(20))

{1: 0, 2: 3, 3: 6, 4: 5, 5: 5, 6: 1}

好 👍 我们来做个更直观的练习 —— 模拟 10000 次掷骰子并画柱状图


📍 第 16 课:模拟骰子分布 & 可视化

1. 用 matplotlib 画图

import numpy as np
import matplotlib.pyplot as plt

def simulate_dice(n):
results = np.random.randint(1, 7, size=n)
counts = {i: 0 for i in range(1, 7)}
for x in results:
counts[x] += 1
return counts

# 模拟 10000 次
counts = simulate_dice(10000)

# 准备数据
faces = list(counts.keys()) # [1,2,3,4,5,6]
values = list(counts.values()) # 每个点数的次数

# 画柱状图
plt.bar(faces, values, color="skyblue", edgecolor="black")
plt.xlabel("骰子点数")
plt.ylabel("出现次数")
plt.title("掷骰子 10000 次的分布")
plt.show()

2. 结果分析

  • 柱状图大致 接近均匀分布(每个点数次数接近 10000/6 ≈ 1666)
  • 但每次运行结果略有不同,因为是随机的。

💡 小练习:
你能不能自己试一下,把 simulate_dice(10000) 换成 simulate_dice(600)(相当于每个点数期望出现 100 次),看看柱状图是不是更不均匀?

要不要你来跑一下这两种情况(10000 次 vs 600 次)并比较?

import numpy as np
import matplotlib.pyplot as plt

def simulate_dice(n):
results = np.random.randint(1, 7, size=n)
counts = {i: 0 for i in range(1, 7)}
for x in results:
counts[x] += 1
return counts

# 模拟 10000 次
counts = simulate_dice(1000000)

# 准备数据
faces = list(counts.keys()) # [1,2,3,4,5,6]
values = list(counts.values()) # 每个点数的次数

# 画柱状图
plt.rcParams['font.family'] = 'SimHei'
plt.bar(faces, values, color="skyblue", edgecolor="black")
plt.xlabel("骰子点数")
plt.ylabel("出现次数")
plt.title("掷骰子 10000 次的分布")
plt.show()

image-20250823001258268