#!/usr/bin/env python3
"""编程笔记正确性自检 —— 实跑验证笔记里的代码断言。

运行：~/miniconda3/bin/python 自检脚本.py
"""

import math
import random
import time

import numpy as np

ok = lambda b: "✅" if b else "❌"

print("=" * 56)
print("【Python 核心】")
print("=" * 56)

# 1. 可变性：别名共享
a = [1, 2, 3]
b = a
b.append(4)
print(f"  别名共享（改 b 动 a）  {ok(a == [1, 2, 3, 4])}   a = {a}")

# 2. 可变默认参数坑
def add_bad(x, lst=[]):
    lst.append(x)
    return lst

r1 = add_bad(1)
r2 = add_bad(2)
print(f"  可变默认参数坑         {ok(r1 is r2 and r2 == [1, 2])}   add(1)={[1]}, add(2)={r2}")

def add_ok(x, lst=None):
    if lst is None:
        lst = []
    lst.append(x)
    return lst

print(f"  修正版（None 占位）     {ok(add_ok(1) == [1] and add_ok(2) == [2])}")

# 3. is vs ==
a, b = [1, 2, 3], [1, 2, 3]
print(f"  == 比 值 / is 比对象    {ok(a == b and not (a is b))}")

# 4. 小整数驻留
x, y = 256, 256
print(f"  小整数驻留 256 is 256  {ok(x is y)}")

# 5. 浮点数陷阱
print(f"  0.1+0.2 != 0.3        {ok(0.1 + 0.2 != 0.3)}   ({0.1 + 0.2})")
print(f"  math.isclose 修正      {ok(math.isclose(0.1 + 0.2, 0.3))}")

# 6. 推导式 / 生成器
gen = (i ** 2 for i in range(5))
print(f"  生成器惰性             {ok(hasattr(gen, '__next__'))}")
print(f"  推导式                 {ok([i**2 for i in range(5)] == [0, 1, 4, 9, 16])}")


print()
print("=" * 56)
print("【科学计算栈】")
print("=" * 56)

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

print(f"  sum(axis=0) 每列和     {ok(list(A.sum(axis=0)) == [5, 7, 9])}")
print(f"  sum(axis=1) 每行和     {ok(list(A.sum(axis=1)) == [6, 15])}")

# 广播 (2,3)+(3,)
r = A + np.array([10, 20, 30])
print(f"  广播 (2,3)+(3,)        {ok(r.tolist() == [[11,22,33],[14,25,36]])}")

# 广播失败 (2,3)+(2,)
try:
    A + np.array([1, 2])
    print(f"  广播 (2,3)+(2,) 报错   ❌ 竟然没报错")
except ValueError:
    print(f"  广播 (2,3)+(2,) 报错   {ok(True)}")

# 手动升维
r = A + np.array([100, 200]).reshape(2, 1)
print(f"  (2,3)+(2,1) 广播       {ok(r.tolist() == [[101,102,103],[204,205,206]])}")

# 布尔索引 / & |
v = np.array([1, 5, 3, 8, 2])
print(f"  布尔索引 v[v>3]        {ok(list(v[v > 3]) == [5, 8])}")
print(f"  np.where               {ok(list(np.where(v > 3, v, 0)) == [0,5,0,8,0])}")
print(f"  & 组合条件             {ok(list(v[(v > 1) & (v < 5)]) == [3, 2])}")

# arange vs linspace
print(f"  arange 不含终点        {ok(list(np.arange(0, 10, 2)) == [0,2,4,6,8])}")
print(f"  linspace 含终点        {ok(list(np.linspace(0, 1, 5)) == [0,.25,.5,.75,1.])}")

# 向量化加速
arr = np.arange(1_000_000)
t = time.time(); s = 0
for v_ in arr:
    s += v_
t1 = time.time() - t
t = time.time(); arr.sum(); t2 = time.time() - t
print(f"  向量化加速实测         {ok(t1 > t2)}   循环 {t1:.3f}s vs 向量化 {t2:.4f}s = {t1/t2:.0f}倍")


print()
print("=" * 56)
print("【科研计算】")
print("=" * 56)

# 固定种子可复现
np.random.seed(42); a1 = np.random.rand(3)
np.random.seed(42); a2 = np.random.rand(3)
print(f"  固定种子可复现         {ok(np.allclose(a1, a2))}")

# 不固定则不可复现
x1 = np.random.rand(3); x2 = np.random.rand(3)
print(f"  不固定则不同           {ok(not np.allclose(x1, x2))}")

# pandas 流程
try:
    import pandas as pd
    np.random.seed(42)
    n = 200
    df = pd.DataFrame({
        "被试": np.repeat(["A", "B"], n // 2),
        "条件": np.tile(np.repeat(["一致", "不一致"], n // 4), 2),
        "反应时": np.random.normal(600, 100, n),
        "正确": np.random.choice([0, 1], n, p=[0.1, 0.9]),
    })
    df2 = df[df["正确"] == 1]
    df2 = df2[(df2["反应时"] > 200) & (df2["反应时"] < 2000)]
    mean_rt = df2.groupby(["被试", "条件"])["反应时"].mean().reset_index()
    print(f"  清洗后试次数减少       {ok(len(df2) < len(df))}   {len(df)} → {len(df2)}")
    print(f"  groupby 聚合 2×2=4 组  {ok(len(mean_rt) == 4)}")
except ImportError:
    print("  pandas 未安装，跳过")

print()
print("全部核验完毕。任何 ❌ 说明笔记可能有误，请对照官方文档复核。")
