🏠 第 4 层 ── 屋顶(综合项目能力:部署、Docker、架构设计) 🧱 第 3 层 ── 功能模块(专项技能:数据库、AI推理、量化交易、音视频) 🪟 第 2 层 ── 主体结构(Web 开发:前端 → 后端 → 全栈) 🪨 第 1 层 ── 地基(编程基础:Python → Git → 命令行)
地基不稳,上面的楼层就容易塌。所以我们从第 1 层开始,打好基础。但同一层内的内容你可以按兴趣随意跳着学。
无论你是文科生、艺术生还是从未接触过编程的朋友,这份教程都将用最通俗的语言,带你走进软件开发的世界。 目标不是让你成为资深程序员,而是让你理解概念、看懂代码、与 AI 高效协作。
🏠 第 4 层 ── 屋顶(综合项目能力:部署、Docker、架构设计) 🧱 第 3 层 ── 功能模块(专项技能:数据库、AI推理、量化交易、音视频) 🪟 第 2 层 ── 主体结构(Web 开发:前端 → 后端 → 全栈) 🪨 第 1 层 ── 地基(编程基础:Python → Git → 命令行)
地基不稳,上面的楼层就容易塌。所以我们从第 1 层开始,打好基础。但同一层内的内容你可以按兴趣随意跳着学。
一切的前提——就像学开车之前要先认识方向盘、油门和刹车
如果编程语言是外语,Python 就是其中最接近"白话文"的一种。它的语法简洁、直观,几乎就像在用英语写句子:
# 这是 Python 代码
if age >= 18:
print("你成年了")对比一下 Java:
// 这是 Java 代码
if (age >= 18) {
System.out.println("你成年了");
}Python 不需要那么多括号和分号,更加干净清爽。这也是为什么它成了初学者和 AI 辅助开发的首选语言。
变量就是一个"标签",你把数据贴上标签,以后用这个名字就能找到它。
name = "小明" # 字符串(str):一段文字,用引号包裹
age = 25 # 整数(int):没有小数点的数字
height = 1.75 # 浮点数(float):带小数点的数字
is_student = True # 布尔值(bool):只有 True 或 FalsePython 还有几种常用的容器类型,用来装多个数据:
| 类型 | 长什么样 | 特点 | 生活比喻 |
|---|---|---|---|
| 列表 list | [1, 2, 3] | 有序,可以修改 | 购物清单——可以增删改 |
| 元组 tuple | (1, 2, 3) | 有序,不能修改 | 身份证号——定了就不变 |
| 字典 dict | {"name": "小明"} | 键值对,查找快 | 通讯录——通过名字找电话 |
| 集合 set | {1, 2, 3} | 无序,自动去重 | 一袋弹珠——不在乎顺序 |
# 列表:最常用的容器
fruits = ["苹果", "香蕉", "橘子"]
fruits.append("西瓜") # 往列表末尾加一个元素
print(fruits[0]) # 输出"苹果"(编程中从 0 开始数!)
# 字典:用"键"来查找"值"
student = {
"name": "小明",
"age": 25,
"scores": [90, 85, 92] # 值可以是任何类型,包括列表
}
print(student["name"]) # 输出"小明"[0],第二个是 [1]。程序之所以比计算器强大,就是因为它能做判断和重复执行。
temperature = 35
if temperature >= 35:
print("太热了,开空调!")
elif temperature >= 20:
print("温度刚好,出去走走")
else:
print("有点冷,穿外套")# 对列表中的每个水果说"我喜欢"
fruits = ["苹果", "香蕉", "橘子"]
for fruit in fruits:
print(f"我喜欢吃{fruit}")
# 输出:我喜欢吃苹果 / 我喜欢吃香蕉 / 我喜欢吃橘子money = 100
while money > 0:
print(f"还剩 {money} 元,继续购物")
money -= 30 # 每次花 30 元
# 当 money 不大于 0 时,循环结束函数就像一台小机器:你往里面放原料(参数),它给你产出成品(返回值)。
def greet(name, greeting="你好"):
"""向某人打招呼"""
return f"{greeting},{name}!"
message = greet("小明") # 输出:你好,小明!
message = greet("Tom", "Hello") # 输出:Hello,Tom!def 是定义函数的关键字(define 的缩写)name 是必填参数greeting="你好" 是默认参数——不传就用默认值return 是函数的"出口",把结果交出去def make_pizza(*toppings):
"""制作一个披萨,配料数量不限"""
print("你点的披萨配料有:")
for topping in toppings:
print(f" - {topping}")
make_pizza("芝士", "培根", "蘑菇", "青椒")*args:接收任意多个位置参数,打包成一个元组**kwargs:接收任意多个关键字参数,打包成一个字典面向对象编程(OOP) 的核心思想是:把数据和操作数据的方法打包在一起,形成"对象"。
class Cat:
"""猫的蓝图/模板"""
def __init__(self, name, color):
self.name = name # self 指"这只猫自己"
self.color = color
self.energy = 100
def meow(self):
print(f"{self.name}: 喵喵喵~")
def eat(self, food):
self.energy += 20
print(f"{self.name}吃了{food},体力恢复到{self.energy}")
# 根据蓝图创建具体的猫(实例化)
my_cat = Cat("橘子", "橘色")
my_cat.meow() # 输出:橘子: 喵喵喵~
my_cat.eat("小鱼干") # 输出:橘子吃了小鱼干,体力恢复到120class PersianCat(Cat):
"""波斯猫,继承了普通猫的所有能力"""
def __init__(self, name):
super().__init__(name, "白色") # 波斯猫默认白色
self.hair_length = "长毛"
def show_off(self):
print(f"{self.name}甩了甩{self.hair_length},真好看!")
persian = PersianCat("雪球")
persian.meow() # 继承了父类的方法
persian.show_off() # 自己独有的方法self 就是"我自己"的意思。当你说 self.name = "橘子" 时,就是说"我的名字是橘子"。try:
number = int(input("请输入一个数字:"))
result = 100 / number
print(f"结果是:{result}")
except ValueError:
print("请输入一个有效的数字!")
except ZeroDivisionError:
print("不能除以零!")
except Exception as e:
print(f"出了一个意外的错误:{e}")
finally:
print("程序执行完毕")| 关键字 | 作用 | 比喻 |
|---|---|---|
try | 尝试执行代码 | 试着过马路 |
except | 出错了怎么办 | 遇到红灯就停下 |
finally | 不管怎样都执行 | 不管过没过马路,都要继续走 |
# 传统写法:筛选出偶数
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
even_numbers = []
for n in numbers:
if n % 2 == 0:
even_numbers.append(n)
# 列表推导式:一行搞定
even_numbers = [n for n in numbers if n % 2 == 0]
# 结果:[2, 4, 6, 8, 10]# 列表推导式:一次性生成所有数据,全部存在内存里
squares_list = [x**2 for x in range(1000000)] # 占用大量内存
# 生成器:只在需要的时候才计算下一个值
squares_gen = (x**2 for x in range(1000000)) # 几乎不占内存把 [] 换成 () 就变成了生成器。当数据量很大的时候,生成器能节省大量内存。
# 不用 with(需要手动关闭文件)
file = open("data.txt", "r")
content = file.read()
file.close() # 如果上面出错了,这行就不会执行!
# 用 with(自动关闭文件,哪怕中间出错)
with open("data.txt", "r") as file:
content = file.read()
# 出了 with 块,文件自动关闭装饰器就是给现有函数额外加功能,但不修改函数本身。
import time
def timer(func):
"""一个计时装饰器:测量函数执行了多久"""
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(f"{func.__name__} 执行了 {end - start:.2f} 秒")
return result
return wrapper
@timer # 给 download_video 加上计时功能
def download_video(url):
time.sleep(2) # 模拟下载耗时
print("下载完成!")
download_video("https://example.com/video.mp4")
# 输出:下载完成!/ download_video 执行了 2.00 秒@timer 等价于 download_video = timer(download_video)。你在 Flask/FastAPI 代码中会看到 @app.route("/") 这样的装饰器。
命令行(终端、Terminal)是用文字命令来告诉电脑你要干什么。图形界面 = 看菜单图片点菜,命令行 = 直接告诉服务员你要什么菜。
pwd # 显示你现在在哪
ls # 列出当前目录下的文件和文件夹
ls -la # 详细信息 + 隐藏文件
cd Documents # 进入 Documents 文件夹
cd .. # 回到上一级目录
cd ~ # 回到家目录Tab 键,终端会自动补全。mkdir my_project # 创建文件夹
mkdir -p a/b/c # 一次性创建多层目录
touch hello.txt # 创建空文件
cp file.txt backup.txt # 复制文件
cp -r folder/ backup/ # 复制整个文件夹
mv old.txt new.txt # 移动/重命名文件
rm file.txt # 删除文件(没有回收站!)
rm -r folder/ # 删除整个文件夹rm 删除的文件不会进回收站,是永久删除。尤其永远不要执行 rm -rf /。-rw-r--r-- 1 qiaochenxu staff 1234 Jan 1 10:00 file.txt
↑权限 ↑所有者 ↑大小 ↑文件名
- rw- r-- r--
↑ ↑ ↑ ↑
类型 所有者 所属组 其他人
读写 只读 只读chmod +x script.sh # 给文件添加执行权限
chmod 755 script.sh # 用数字设置权限(7=rwx, 5=r-x)echo $HOME # 查看家目录
echo $PATH # 系统在哪些目录找可执行文件
export MY_API_KEY="abc123" # 设置环境变量(仅当前终端有效).env 文件绝对不能上传到 GitHub!里面有你的密码和密钥。ls -la | grep ".txt" # 列出文件,只显示包含".txt"的行
cat log.txt | head -20 # 查看文件前20行
echo "hello" > file.txt # 覆盖写入
echo "world" >> file.txt # 追加写入python server.py # 运行程序
# 按 Ctrl+C 强制停止当前运行的程序
python server.py & # 后台运行
ps aux | grep python # 查看进程
kill 12345 # 杀死进程
kill -9 12345 # 强制杀死| 系统 | 包管理器 | 例子 |
|---|---|---|
| Mac | brew (Homebrew) | brew install python |
| Ubuntu/Debian | apt | sudo apt install python3 |
| Windows | choco / winget | choco install python |
Git 就是代码的"时光机"——记录每一次修改、随时回到任何历史版本、多人同时修改而不冲突。
| 概念 | 英文 | 比喻 |
|---|---|---|
| 仓库 | Repository | 项目的"存档柜" |
| 提交 | Commit | 一张"快照" |
| 分支 | Branch | 平行宇宙 |
| 暂存区 | Staging Area | 购物车 |
cd my_project && git init # 创建 Git 仓库
git status # 查看状态
git add main.py # 把文件放入暂存区
git add . # 把所有改动放入暂存区
git commit -m "添加了用户登录功能" # 提交(拍快照)
git log --oneline # 查看简洁版历史git branch # 查看所有分支
git checkout -b new-feature # 创建并切换到新分支
# ... 在新分支上改代码 ...
git checkout main # 切回主分支
git merge new-feature # 合并新分支的改动主分支(main): A --- B --- C --------- F (合并)
\ /
新分支(feature): D --- E ---git remote add origin https://github.com/你/项目.git # 关联远程仓库
git push -u origin main # 推送到 GitHub
git pull origin main # 从 GitHub 拉取
git clone https://github.com/某人/项目.git # 克隆项目| 命令 | 方向 | 比喻 |
|---|---|---|
git push | 本地 → GitHub | 上传到云盘 |
git pull | GitHub → 本地 | 从云盘下载 |
git clone | GitHub → 本地(首次) | 下载整个项目 |
# Python 虚拟环境
venv/
.venv/
# 依赖目录
node_modules/
# 环境变量文件(含密码!)
.env
.env.local
# 编译生成的文件
__pycache__/
*.pyc
.next/
# IDE 配置
.vscode/
.idea/包就是别人写好的代码,你可以直接拿来用。就像做菜直接买面粉而不是自己种小麦。
pip install requests # 安装包
pip install flask==2.3.0 # 安装指定版本
pip install -r requirements.txt # 根据配料表安装所有依赖
# 虚拟环境:给每个项目创建独立的"隔离间"
python -m venv venv # 创建虚拟环境
source venv/bin/activate # Mac/Linux 激活
# venv\Scripts\activate # Windows 激活
deactivate # 退出虚拟环境npm install express # 安装包
npm install -D typescript # 安装开发依赖
npm install # 根据 package.json 安装所有依赖{
"name": "my-web-app",
"scripts": {
"dev": "next dev",
"build": "next build"
},
"dependencies": {
"next": "^14.0.0",
"react": "^18.2.0"
},
"devDependencies": {
"typescript": "^5.0.0"
}
}| 字段 | 含义 |
|---|---|
dependencies | 运行时需要的包 |
devDependencies | 只在开发时需要的包 |
scripts | 快捷命令,npm run dev = next dev |
node_modules 放进 Git 仓库!别人可以通过 npm install 自己安装。从"看得见的"到"看不见的":前端 → 后端 → 全栈
一个网页就像一栋房子:HTML = 结构(墙壁门窗),CSS = 装修(颜色材质),JavaScript = 电器(开灯空调)。
<!DOCTYPE html>
<html>
<head>
<title>我的第一个网页</title>
</head>
<body>
<h1>欢迎来到我的网站</h1>
<p>这是一个段落。</p>
<a href="https://example.com">这是一个链接</a>
<img src="cat.jpg" alt="一只可爱的猫">
</body>
</html>.container {
display: flex; /* 启用 Flexbox */
justify-content: center; /* 主轴居中 */
align-items: center; /* 交叉轴居中 */
gap: 10px; /* 子元素间距 */
}flex-start: |A B C | ← 靠左 center: | A B C | ← 居中 flex-end: | A B C| ← 靠右 space-between: |A B C| ← 两端对齐
+--------------------------------------------+ | margin(外边距) | | +--------------------------------------+ | | | border(边框) | | | | +--------------------------------+ | | | | | padding(内边距) | | | | | | +-------------------------+ | | | | | | | content(内容) | | | | | | | +-------------------------+ | | | | | +--------------------------------+ | | | +--------------------------------------+ | +--------------------------------------------+
/* 默认样式(手机) */
.container { flex-direction: column; }
/* 屏幕宽度大于 768px 时 */
@media (min-width: 768px) {
.container { flex-direction: row; }
}JS 让网页可以响应用户的操作。借助 Node.js,它也能写后端服务器。
let age = 25; // 可以重新赋值
const name = "小明"; // 不可以重新赋值
// 优先用 const,需要改变的用 let,忘掉 var
// 箭头函数(现代 JS 最常见写法)
const add = (a, b) => a + b;
console.log(add(3, 5)); // 输出:8// 解构赋值:快速提取数据
const { name, age } = student;
const [first, second] = [10, 20, 30];
// 常用数组方法
const numbers = [1, 2, 3, 4, 5];
numbers.map(n => n * 2); // [2, 4, 6, 8, 10]
numbers.filter(n => n > 3); // [4, 5]
numbers.find(n => n > 3); // 4
numbers.reduce((sum, n) => sum + n, 0); // 15| 方法 | 作用 | 比喻 |
|---|---|---|
.map() | 逐个变换 | 给每个学生发书包 |
.filter() | 筛选 | 从苹果里挑出红的 |
.find() | 找第一个 | 找到第一个空座位 |
.reduce() | 汇总 | 把所有分数加起来 |
async function loadUserData() {
try {
const response = await fetch("/api/user");
const data = await response.json();
console.log("用户数据:", data);
} catch (error) {
console.log("加载失败:", error);
}
}const title = document.querySelector("h1");
title.textContent = "新标题";
title.style.color = "red";
title.classList.add("highlight");
const button = document.querySelector("#myButton");
button.addEventListener("click", () => {
alert("你点了按钮!");
});TypeScript = JavaScript + 类型系统。在你写代码的时候就发现 bug,而不是等到运行时才崩溃。
// 基本类型
let username: string = "小明";
let age: number = 25;
let scores: number[] = [90, 85, 92];
let id: string | number = "abc123"; // 联合类型
// interface:描述对象结构
interface User {
name: string;
age: number;
email?: string; // ? 表示可选
}
// 泛型:灵活的类型模板
function getFirst<T>(arr: T[]): T {
return arr[0];
}
getFirst<number>([1, 2, 3]); // 返回 number
getFirst<string>(["a", "b"]); // 返回 string前端在浏览器里展示页面,后端在服务器上处理数据和业务逻辑。
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route("/")
def home():
return "欢迎来到首页!"
@app.route("/user/<username>")
def show_user(username):
return f"用户 {username} 的主页"
@app.route("/api/feedback", methods=["POST"])
def create_feedback():
data = request.get_json()
return jsonify({"message": "反馈已收到!"}), 201from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class FeedbackCreate(BaseModel):
content: str
rating: int # 自动验证数据格式
@app.get("/")
async def home():
return {"message": "欢迎!"}
@app.post("/api/feedback")
async def create_feedback(feedback: FeedbackCreate):
return {"message": f"收到评分为 {feedback.rating} 的反馈"}启动后访问 http://localhost:8000/docs 可看到自动生成的 API 文档。
React 用组件来搭建页面——像乐高积木一样,每个组件独立、可复用、可嵌套。
import { useState } from "react";
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>你点了 {count} 次</p>
<button onClick={() => setCount(count + 1)}>点我 +1</button>
</div>
);
}app/
├── page.tsx → / (首页)
├── about/
│ └── page.tsx → /about (关于页面)
├── blog/
│ ├── page.tsx → /blog (博客列表页)
│ └── [slug]/
│ └── page.tsx → /blog/xxx (具体文章)
└── api/
└── users/
└── route.ts → /api/users (API 接口)经验法则:需要用户交互的组件加 "use client",其他默认就好。
像自助餐一样——正在做哪个项目就学哪个方向
数据库就是后厨的仓库——所有数据存在这里。关系型数据库就是超级强大的 Excel。
SELECT name, age FROM users WHERE age > 20;
INSERT INTO users (name, age) VALUES ('小王', 30);
UPDATE users SET age = 26 WHERE id = 1;
DELETE FROM users WHERE id = 3;
-- 联合查询
SELECT users.name, posts.title
FROM users JOIN posts ON users.id = posts.user_id;model User {
id Int @id @default(autoincrement())
name String
email String @unique
posts Post[]
}
model Post {
id Int @id @default(autoincrement())
title String
content String?
author User @relation(fields: [authorId], references: [id])
authorId Int
}const users = await prisma.user.findMany();
const user = await prisma.user.findUnique({
where: { id: 1 },
include: { posts: true }
});| 方法 | 含义 | 比喻 |
|---|---|---|
| GET | 获取数据 | 去图书馆借书 |
| POST | 创建数据 | 填表注册 |
| PUT | 整体替换 | 重写简历 |
| PATCH | 部分修改 | 只改电话号码 |
| DELETE | 删除数据 | 注销账号 |
| 状态码 | 含义 | 理解为 |
|---|---|---|
| 200 | 成功 | "没问题" |
| 201 | 创建成功 | "已建好" |
| 400 | 请求有误 | "我没听懂" |
| 401 | 未认证 | "你谁?先登录" |
| 404 | 找不到 | "不存在" |
| 500 | 服务器错误 | "我这边出问题了" |
GET /api/users → 获取所有用户 GET /api/users/42 → 获取 id 为 42 的用户 POST /api/users → 创建新用户 PUT /api/users/42 → 更新用户 42 DELETE /api/users/42 → 删除用户 42
前端 localhost:3000 和后端 localhost:8000 端口不同 → 不同源 → 被拦截。解决方法:
# Flask
from flask_cors import CORS
CORS(app)
# FastAPI
from fastapi.middleware.cors import CORSMiddleware
app.add_middleware(CORSMiddleware, allow_origins=["http://localhost:3000"])千万不能明文存密码!哈希是单向加密——无法反推回原始密码。
import bcrypt
# 注册时:哈希后存储
hashed = bcrypt.hashpw("123456".encode(), bcrypt.gensalt())
# 登录时:比较哈希值
if bcrypt.checkpw(input_password.encode(), hashed):
print("密码正确!")| Session | JWT Token | |
|---|---|---|
| 存储 | 服务器内存 | 客户端 |
| 优点 | 安全,数据在服务器 | 无状态,适合分布式 |
| 缺点 | 消耗服务器内存 | 无法主动失效 |
HTTP 是明信片(谁都能看),HTTPS 是密封信封(只有收件人能打开)。现代网站必须使用 HTTPS。
用来描述文本模式的工具,就像超级强大的"查找替换"。
| 符号 | 含义 | 例子 | 能匹配 |
|---|---|---|---|
. | 任意一个字符 | a.c | abc, a1c |
* | 前面重复 0+ 次 | ab*c | ac, abc |
+ | 前面重复 1+ 次 | ab+c | abc, abbc |
\d | 一个数字 | \d\d\d | 123 |
\w | 字母/数字/下划线 | \w+ | hello |
import re
# 匹配邮箱
emails = re.findall(r'[\w.+-]+@[\w-]+\.[\w.]+', text)
# 匹配日期
match = re.search(r'(\d{4})-(\d{2})-(\d{2})', '今天是 2024-01-15')
year, month, day = match.group(1), match.group(2), match.group(3)输入:一张猫的图片(像素数字) ↓ 第 1 层:识别边缘和线条 ↓ 第 2 层:识别形状 ↓ 第 3 层:识别部位(耳朵、眼睛) ↓ 输出:"这是一只猫"(95% 确信度)
| 阶段 | 做什么 | 比喻 | 需要什么 |
|---|---|---|---|
| 训练 | 用数据"教会"模型 | 学生做题 | 大量数据 + GPU + 几天 |
| 推理 | 用模型处理新数据 | 考试做新题 | 模型文件 + 普通 GPU |
| 方案 | 适用 GPU | 说明 |
|---|---|---|
| CUDA | NVIDIA | 最成熟、最广泛 |
| MPS | Apple Silicon | macOS GPU 加速 |
| Vulkan | 通用 | 跨平台 |
| ROCm | AMD | AMD 的替代品 |
视频 = 一连串图片(帧)快速播放 + 音频轨道。编码是压缩算法,容器是打包格式。
ffmpeg -i input.avi output.mp4 # 格式转换
ffmpeg -i input.mkv -c copy output.mp4 # 只换容器(超快)
ffmpeg -i input.mp4 -c:v libx265 out.mp4 # H.265 编码
ffmpeg -i video.mp4 -vn audio.mp3 # 提取音频
ffmpeg -i input.mp4 -ss 00:00:30 -t 00:01:00 out.mp4 # 截取片段
ffmpeg -i input.mp4 -c:v libx264 -crf 23 out.mp4 # 质量控制| 参数 | 含义 |
|---|---|
-c copy | 不重新编码(最快) |
-c:v | 视频编码器 |
-crf | 质量(0=最好,51=最差,推荐 18-28) |
-vn | 去掉视频 |
-an | 去掉音频 |
用代码"操控"浏览器——就像有一个隐形人在帮你点击和输入。
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch(headless=False)
page = browser.new_page()
page.goto("https://example.com")
page.click("button#login")
page.fill("input[name='username']", "小明")
page.wait_for_selector(".dashboard")
content = page.text_content(".main-content")
browser.close()| 工具 | 语言 | 特点 |
|---|---|---|
| Playwright | Python/Node.js | 微软出品,最新最强 |
| Selenium | Python/Java | 老牌工具,社区大 |
| Puppeteer | Node.js | Google 出品,只支持 Chrome |
用计算机程序根据预设策略自动买卖,不受情绪影响、24/7 运行。
┃ ← 上影线(最高价)
┌─┃─┐
│ ┃ │ ← 实体(绿=上涨,红=下跌)
└───┘
┃ ← 下影线(最低价)
一根 K 线包含:开盘价、收盘价、最高价、最低价(OHLC)| 概念 | 说明 | 比喻 |
|---|---|---|
| 止损 | 亏到一定程度自动卖出 | "最多输多少就走" |
| 止盈 | 赚到一定程度自动卖出 | "赚够了就收手" |
| 仓位管理 | 每次投入多少资金 | 不把鸡蛋放一个篮子 |
让项目跑得更稳、让别人也能用、方便维护和扩展
把代码和整个运行环境一起打包进"集装箱",搬到哪台电脑都能运行。
| 概念 | 是什么 | 比喻 |
|---|---|---|
| 镜像 Image | 只读模板 | 蛋糕模具 |
| 容器 Container | 镜像的运行实例 | 做出来的蛋糕 |
FROM python:3.11-slim # 基础镜像
WORKDIR /app # 工作目录
COPY requirements.txt . # 复制依赖文件
RUN pip install -r requirements.txt # 安装依赖
COPY . . # 复制项目代码
EXPOSE 8000 # 暴露端口
CMD ["python", "main.py"] # 启动命令docker build -t my-app . # 构建镜像
docker run -p 8000:8000 my-app # 运行容器
docker run -d -p 8000:8000 my-app # 后台运行
docker ps # 查看运行中的容器
docker stop <容器ID> # 停止容器version: "3.8"
services:
backend:
build: ./backend
ports: ["8000:8000"]
depends_on: [db]
frontend:
build: ./frontend
ports: ["3000:3000"]
db:
image: postgres:15
volumes: [pgdata:/var/lib/postgresql/data]
volumes:
pgdata:docker-compose up -d # 一键启动所有服务
docker-compose down # 停止所有服务| VPS | PaaS | |
|---|---|---|
| 是什么 | 自己租虚拟服务器 | 一键部署平台 |
| 代表 | 阿里云、AWS、Vultr | Vercel、Railway |
| 比喻 | 租毛坯房自己装修 | 住酒店拎包入住 |
| 适合 | Docker、后台服务 | 前端、Next.js 全栈 |
用户请求 ↓ Nginx(前台/反向代理) ├──→ 前端服务(端口 3000) ├──→ 后端 API(端口 8000) └──→ 静态文件(图片、CSS、JS)
xxx.vercel.app 域名每次推送代码,Vercel 自动重新部署——这叫 CI/CD(持续集成/持续部署)。
crypto_trader/ ├── exchange/ # 交易所相关 ├── strategy/ # 策略模块 ├── risk/ # 风控模块 ├── data/ # 数据模块 ├── utils/ # 工具函数 ├── tests/ # 测试 ├── config/ # 配置 ├── main.py # 入口文件 └── requirements.txt
class BaseStrategy:
def generate_signal(self, data):
raise NotImplementedError
class MACrossStrategy(BaseStrategy):
def generate_signal(self, data):
return "buy" if short_ma > long_ma else "sell"
# 使用时只需换一行代码
strategy = MACrossStrategy()
signal = strategy.generate_signal(market_data)class EventEmitter:
def __init__(self):
self.listeners = {}
def on(self, event, callback):
self.listeners.setdefault(event, []).append(callback)
def emit(self, event, data):
for cb in self.listeners.get(event, []):
cb(data)
emitter = EventEmitter()
emitter.on("new_trade", lambda t: send_notification(t))
emitter.emit("new_trade", {"symbol": "BTC/USDT", "price": 50000})测试就是你的安全网——每次改代码后跑一遍测试,确保没有改坏别的功能。
# calculator.py
def add(a, b): return a + b
def divide(a, b):
if b == 0: raise ValueError("不能除以零")
return a / b
# test_calculator.py
import pytest
from calculator import add, divide
def test_add():
assert add(2, 3) == 5
assert add(-1, -2) == -3
def test_divide_by_zero():
with pytest.raises(ValueError):
divide(10, 0)pytest # 运行所有测试
pytest -v # 显示详细信息from unittest.mock import MagicMock
def test_get_btc_price():
mock_exchange = MagicMock()
mock_exchange.fetch_ticker.return_value = {"last": 50000}
price = get_btc_price(mock_exchange)
assert price == 50000
mock_exchange.fetch_ticker.assert_called_once_with("BTC/USDT")第 1 周 ─── Python 核心语法 + 命令行基础 + Git
(补齐地基,尤其是 Git——给代码买"保险")
第 2 周 ─── HTML/CSS + JavaScript + HTTP/API
(理解 Web 怎么工作的)
第 3 周 ─── Flask/FastAPI + 数据库 + 认证
(理解后端在干什么)
第 4 周 ─── TypeScript + React + Next.js
(理解现代前端和全栈)
第 5 周起 ── 按需学专项技能
(正在做哪个项目就学哪个方向)第一步:建立上下文
"我是一个非专业开发者,请用简单的语言给我解释 [某个概念],配合实际例子。"
第二步:结合项目深入
"你看我的项目里有这段代码 [贴代码],里面的 async/await 是在做什么?"
第三步:动手实践
"帮我在我的项目里加一个功能,让我来理解这个过程中用到的技术。"