如果你是"看得懂教程但写不出代码"的初学者,这份笔记就是为你准备的。
核心内容:Python基础 → 文件I/O → 面向对象 → 命令行工具 → API调用 → 异步编程
每天读一遍,直到这些模板你能默写出来。

目录

  1. 万能骨架模板(任何程序从这里开始)
  2. 菜单循环模板(Day 1-2)
  3. 文件I/O模板(Day 3)
  4. 面向对象模板(Day 4)
  5. argparse模板(Day 5)
  6. Day 1-5完整串联——记账CLI全模板
  7. API调用模板(Day 6)
  8. 异步编程模板(Day 7)
  9. 你踩过的所有坑汇总
  10. 概念速查表

一、万能骨架模板

面对空白文件不知道写什么?永远先写这个骨架。 任何程序都可以从这里开始。

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

"""这里写你的程序是干什么的"""

import json, os, sys       # 常用模块先导入
# import requests, argparse, ...  # 按需要添加


def main():
    """程序入口"""
    pass                    # 先占位,跑通了再填


if __name__ == "__main__":
    main()

💡 写完骨架先跑一次 python 文件名.py,没报错就有了地基,再往里填功能。


二、菜单循环模板

这是 Day 1-2 的核心结构。所有交互式程序(记账、学生管理、笔记CLI)都长这样。

# ── 用户交互菜单的通用结构 ──
def main():
    """主循环:显示选项 → 用户选择 → 执行功能"""
    while True:                     # 无限循环,直到用户选"退出"
        print("\n========= 功能菜单 =========")
        print("1. 功能一")
        print("2. 功能二")
        print("3. 退出")
        choice = input("请选择:")    # input() 返回的是字符串!

        if choice == "1":
            func_one()               # 调对应功能
        elif choice == "2":
            func_two()
        elif choice == "3":
            print("再见!")
            break                    # break 跳出 while 循环
        else:
            print("输入错误,请重新输入")

while 和 for 的选择

# 你知道循环次数 → 用 for
for i in range(3):        # 登录最多试 3 次
    print(f"第 {i+1} 次尝试")

# 你不知道循环次数 → 用 while
while True:               # 菜单不断显示,直到用户选退出
    choice = input("> ")
    if choice == "q":
        break

⚠ input() 的常见错误

guess = input("猜一个数字:")
if guess > 50:            # ❌ 报错!字符串不能和数字比大小

guess = int(input("猜一个数字:"))  # ✅ int() 转成数字
if guess > 50:            # ✅ 正确

三、文件I/O模板

Day 3 的核心。I/O 再怎么变,永远就是"读"和"写"两个固定操作。背下这两个函数就行。

读取模板(背下来)

import json
import os

def load_data(filename="data.json"):
    """从 JSON 文件加载数据 → 返回 Python 字典/列表"""
    if os.path.exists(filename):             # 先检查文件存不存在
        with open(filename, "r", encoding="utf-8") as f:
            return json.load(f)              # json.load = 文件 → 内存
    return []                                 # 文件不存在,返回空(不报错)

写入模板(背下来)

def save_data(data, filename="data.json"):
    """把 Python 数据写回 JSON 文件"""
    with open(filename, "w", encoding="utf-8") as f:
        json.dump(data, f, ensure_ascii=False, indent=2)

读写联动的标准流程

# 启动时
records = load_data()      # 先在内存里建好数据

# 修改数据
records.append({"item": "午餐", "amount": 25})
# 注意:改了数据后,"立刻"调保存,否则数据留在内存,一关就没了

# 保存
save_data(records)          # 把整个 records 写回文件

⚠ "w" 还是 "a"?—— 最常见的坑

# ❌ 错误:用 "a"(追加模式)
with open("data.json", "a", encoding="utf-8") as f:
    json.dump(data, f, ensure_ascii=False, indent=2)
# 第一次写:[{"a":1}]
# 第二次写:[{"a":1}][{"b":2}]   ← JSON 格式被破坏,读不回来了!

# ✅ 正确:用 "w"(覆盖模式)
with open("data.json", "w", encoding="utf-8") as f:
    json.dump(data, f, ensure_ascii=False, indent=2)
# data 里已经包含了旧+新数据,覆盖旧文件完全没问题

💡 直觉判断: JSON 整体存储 → 用 "w"。文本逐行追加 → 用 "a"

json.dump 的方向记忆

# 加载(启动时做一次)
json.load(f)       =  文件  →  内存

# 保存(改完数据后做一次)
json.dump(x, f)    =  内存  →  文件

四、面向对象模板

Day 4 的核心。class 不是神秘的东西,它只是把一组相关的数据和函数打包在一起。

直观理解:class 是"饼干模具"

# class 是"饼干模具":一个模具可以压出无数个饼干(对象)
class Student:             # 定义模具
    def __init__(self, n, c, m, e):  # __init__ 是"压饼干"时自动调用的
        self.name = n       # self.name = "这个饼干的名称"
        self.scores = {"语文": c, "数学": m, "英语": e}

    def average(self):      # 方法 = "这个饼干能做的事情"
        return sum(self.scores.values()) / 3

    def __str__(self):      # 决定 print(对象) 时显示什么
        return f"{self.name}:{self.scores},均分{self.average():.1f}"

# ── 使用 ──
s1 = Student("韩立", 85, 92, 78)  # 压出第一个饼干
s2 = Student("南宫婉", 90, 88, 95)  # 压出第二个饼干
print(s1.name)      # 取这个饼干的属性
print(s1.average()) # 调这个饼干的方法
print(s1)           # 自动调 __str__

class 的核心要点

  • __init__ 是构造函数:创建对象时自动执行,用来初始化属性
  • self 代表"这个对象自己":调用时自动传入,你不需要写
  • __str__ 用来控制打印显示:不加它 print(对象) 会显示 <Student object at xxx>
  • 方法(如 average)的第一个参数永远是 self
  • 调用方法时不用传 self:s1.average() 就行,不是 s1.average(self)

class 万能模板(直接复制改)

class XXX:
    """一句话描述这个类是干什么的"""
    def __init__(self, 参数1, 参数2):
        """初始化"""
        self.属性1 = 参数1
        self.属性2 = 参数2

    def 方法1(self):
        """功能描述"""
        pass

    def __str__(self):
        """控制打印显示"""
        return f"显示内容"

五、argparse模板

Day 5 的核心。argparse 让你的程序不仅能在交互模式下用,也能在命令行一次性传参。

import sys
import argparse

# ── 判断用户有没有传参 ──
if len(sys.argv) > 1:                       # 如果用户传了额外参数
    parser = argparse.ArgumentParser()      # 1. 创建解析器
    parser.add_argument("--action")         # 2. 声明参数(双横线)
    parser.add_argument("--name")
    parser.add_argument("--amount", type=int)   # 3. 指定类型
    args = parser.parse_args()              # 4. 解析参数

    # 5. 用 args.xxx 取值
    if args.action == "add":
        print(f"添加:{args.name}")
    elif args.action == "list":
        print("列出所有")

else:                                       # 没传参数 → 交互菜单
    while True:
        print("1. 添加  2. 列出  3. 退出")
        choice = input("> ")
        if choice == "1":
            name = input("名字:")
            print(f"添加:{name}")
        elif choice == "3":
            break

参数类型对照

parser.add_argument("--name")                      # 字符串(默认)
parser.add_argument("--age", type=int)                # 整数
parser.add_argument("--price", type=float)            # 小数
parser.add_argument("--verbose", action="store_true") # 开关(True/False)

⚠ argparse 不需要 class!

你之前问过"没有 class 怎么用 argparse"——答案:argparse 和 class 没任何关系!普通函数一样用。

def get_weather(city):
    """普通函数"""
    print(f"查询 {city} 的天气")

if len(sys.argv) > 1:
    parser = argparse.ArgumentParser()
    parser.add_argument("--city")
    args = parser.parse_args()
    get_weather(args.city)          # 直接调普通函数

sys.argv 的原理

# 终端输入:
# python test.py --action add --name 韩立

# sys.argv 的值是:
# ["test.py", "--action", "add", "--name", "韩立"]

sys.argv[0]    # "test.py"(程序自身的文件名)
sys.argv[1]    # "--action"
sys.argv[2]    # "add"
len(sys.argv)  # 5

# 所以:if len(sys.argv) > 1 → 用户传了额外参数吗?

六、Day 1-5 完整串联模板

前面所有内容的大集合:数据结构 + 文件 I/O + class + argparse + 菜单循环。
你以后写任何 CLI 工具都可以从这个模板改。复制就能用。

import json, os, sys, argparse

""" 记账 CLI — 你可以用这个当万能起点 """

# ── 1. 类定义 ──
class AccountBook:
    """账本类:封装所有记账操作"""
    def __init__(self):
        self.records = self._load()   # 启动时加载数据

    def _load(self):
        if os.path.exists("data.json"):
            with open("data.json", "r", encoding="utf-8") as f:
                return json.load(f)
        return []

    def _save(self):
        with open("data.json", "w", encoding="utf-8") as f:
            json.dump(self.records, f, ensure_ascii=False, indent=2)

    def add(self, category, amount):
        self.records.append({"类别": category, "金额": amount})
        self._save()                           # 改完立刻保存
        print(f"已记录:{category} {amount}元")

    def show_all(self):
        for i, r in enumerate(self.records, 1):
            print(f"{i}. {r['类别']} — {r['金额']}元")

    def total(self):
        s = sum(r["金额"] for r in self.records)
        print(f"总支出:{s}元")

# ── 2. 创建实例 ──
book = AccountBook()

# ── 3. 入口 ──
if len(sys.argv) > 1:
    # 命令行模式
    parser = argparse.ArgumentParser()
    parser.add_argument("--action")     # add / list / total
    parser.add_argument("--category")
    parser.add_argument("--amount", type=int)
    args = parser.parse_args()

    if args.action == "add":
        book.add(args.category, args.amount)
    elif args.action == "list":
        book.show_all()
    elif args.action == "total":
        book.total()
else:
    # 交互模式
    while True:
        print("\n1. 记一笔  2. 查看所有  3. 总支出  4. 退出")
        choice = input("> ")
        if choice == "1":
            cat = input("类别:"); amt = int(input("金额:"))
            book.add(cat, amt)
        elif choice == "2": book.show_all()
        elif choice == "3": book.total()
        elif choice == "4": print("再见!"); break
        else: print("输入错误")

💡 这个文件是你的"万能起点"。每次写新 CLI 工具,复制这个文件,改 class 名和功能就行。


七、API调用模板

Day 6 的核心。让程序连上互联网从 API 拿数据。万物皆可套这个流程。

API 调用的完整流程

import requests, os
from dotenv import load_dotenv

# ── 1. 读取配置 ──
load_dotenv()
API_KEY = os.getenv("API_KEY")
API_HOST = os.getenv("API_HOST")

# ── 2. 发送请求(固定三步) ──
headers = {"X-QW-Api-Key": API_KEY}    # 认证信息
url = f"https://{API_HOST}/v7/weather/now?location=101010100"
resp = requests.get(url, headers=headers)   # 发 GET 请求

# ── 3. 解析响应 ──
data = resp.json()                     # JSON → Python 字典
temp = data["now"]["temp"]
text = data["now"]["text"]
print(f"天气:{text},{temp}°C")

.env 文件格式

# .env 文件内容(和 main.py 放同一目录)
API_KEY=你拿到的Key
API_HOST=你拿到的Host

# 注意:= 后面不要加空格,不要加引号

两个 API 的串联(城市名 → 天气)

def get_weather(city):
    headers = {"X-QW-Api-Key": API_KEY}

    # 第 1 步:城市名 → 城市代码
    geo_url = f"https://{API_HOST}/geo/v2/city/lookup?location={city}"
    geo_data = requests.get(geo_url, headers=headers).json()
    city_id = geo_data["location"][0]["id"]

    # 第 2 步:城市代码 → 天气数据
    weather_url = f"https://{API_HOST}/v7/weather/now?location={city_id}"
    weather_data = requests.get(weather_url, headers=headers).json()

    # 第 3 步:提取信息
    temp = weather_data["now"]["temp"]
    text = weather_data["now"]["text"]
    feel = weather_data["now"]["feelsLike"]
    print(f"{city}:{text},{temp}°C(体感 {feel}°C)")

⚠ 区分大小写!

JSON 字段名严格区分大小写,写错了就 KeyError!

weather_data["now"]["feelsLike"]    # ✅ 正确,L 大写
weather_data["now"]["feelslike"]    # ❌ KeyError!全小写没有这个字段

# 不确定字段名时先 print 再写
print(weather_data)  # 先打印看原始 JSON

八、异步编程模板

Day 7 的核心。异步 = "不干等,同时做别的事"。适合同时查多个城市、多个 API。

异步的三把钥匙

# 钥匙 1:async def —— 声明这是一个异步函数
async def get_weather(city):
    ...

# 钥匙 2:await —— 等结果回来但不阻塞
async def get_weather(city):
    data = await client.get(url)  # 去干别的了,结果回来再继续

# 钥匙 3:asyncio.run() —— 异步程序的启动器
asyncio.run(main())  # 一个程序只调一次

异步批量天气查询(完整模板,可复用)

import os, time, asyncio
import httpx
from dotenv import load_dotenv

load_dotenv()
API_KEY = os.getenv("API_KEY")
API_HOST = os.getenv("API_HOST")

async def get_weather(city, client):
    headers = {"X-QW-Api-Key": API_KEY}
    geo_url = f"https://{API_HOST}/geo/v2/city/lookup?location={city}"
    geo_resp = await client.get(geo_url, headers=headers)
    city_id = geo_resp.json()["location"][0]["id"]

    weather_url = f"https://{API_HOST}/v7/weather/now?location={city_id}"
    weather_resp = await client.get(weather_url, headers=headers)
    data = weather_resp.json()
    print(f"{city}:{data['now']['text']},{data['now']['temp']}°C")

async def main():
    cities = ["北京", "上海", "广州", "深圳"]
    async with httpx.AsyncClient() as client:
        tasks = [get_weather(c, client) for c in cities]
        await asyncio.gather(*tasks)

if __name__ == "__main__":
    start = time.time()
    asyncio.run(main())
    print(f"总耗时:{time.time() - start:.2f}秒")

同步 vs 异步速度对比

# 同步:一个一个来,总耗时 = 每个耗时相加
for city in cities:
    get_weather(city)      # 等这个完,才开始下一个
# 5 个城市 ≈ 5 秒

# 异步:同时发请求,总耗时 ≈ 最慢那个城市
async with httpx.AsyncClient() as client:
    tasks = [get_weather(c, client) for c in cities]
    await asyncio.gather(*tasks)
# 5 个城市 ≈ 0.6 秒(快 7 倍!)

⚠ 重要:只建一次客户端

不要把 AsyncClient 写在函数里面!否则每个城市查两次天气就建了 10 次客户端,速度浪费。

# ❌ 错误
async def get(city):
    async with httpx.AsyncClient() as c:  # 每次都新建
        resp = await c.get(url)

# ✅ 正确
async def get(city, client):
    resp = await client.get(url)          # 复用传入的 client

async with httpx.AsyncClient() as client:  # 只建一次
    tasks = [get(c, client) for c in cities]
    await asyncio.gather(*tasks)

九、你踩过的所有坑汇总

这里记录了我从 Day 1 到 Day 7 实际出过的所有错误。如果你也遇到了类似的问题,直接对照看。

Day 1 — input() 忘了转 int

  • 症状:TypeError: str 和 int 不能比较
  • 原因:input() 返回字符串,不能直接和数字做运算
  • 解决int(input("提示"))
guess = int(input("猜数字:"))  # ✅

Day 1 — while 前忘了初始化变量

  • 症状:NameError: name "guess" is not defined
  • 原因:while 条件用的变量还没定义
  • 解决:循环前先赋值
guess = 0
while guess != answer:

Day 3 — JSON 保存用了 "a" 模式

  • 症状:JSONDecodeError,文件内容格式错乱
  • 原因:"a" 追加模式破坏 JSON 格式
  • 解决:永远用 "w"(覆盖)模式
with open("data.json", "w", encoding="utf-8") as f:   # ✅

Day 3 — 忘了调 save_data()

  • 症状:程序关了再打开,数据没了
  • 原因:改了内存里的数据,没写回文件
  • 解决:改完数据立刻调 save_data()
records.append(new)
save_data(records)  # ✅ 下一行就调

Day 4 — total 拼写错误

  • 症状:看着不对劲,但不报错
  • 原因:把 total 写成了 totle
  • 解决:写完注意编辑器红色波浪线
def total(self):    # 不是 totle

Day 5 — 以为 argparse 需要 class

  • 症状:不知道怎么把 argparse 和函数连起来
  • 原因:以为必须写成 对象.方法()
  • 解决:argparse 直接调普通函数就行
def f(x): ...
parser.parse_args()
f(args.x)

Day 6 — 字典字段名大小写

  • 症状:KeyError: "feelslike"
  • 原因:Python 区大小写,和 JSON 里的字段不一样
  • 解决:先 print(data) 看原始 JSON
data["now"]["feelsLike"]  # ✅ 不是 feelslike

Day 6 — 忘了 cd 到文件目录

  • 症状:can't open file
  • 原因:终端路径不是文件所在目录
  • 解决:先 cd 再 python
cd G:\PythonProject\xxx
python main.py

Day 7 — AsyncClient 每次新建

  • 症状:异步和同步速度差不多
  • 原因:每次请求新建客户端,开销大
  • 解决:建一次 client 传入函数
async with httpx.AsyncClient() as c:
    tasks = [f(x, c) for x in xs]

十、概念速查表

概念 一句话理解
列表 vs 字典 列表存多个东西(有顺序);字典存键值对(按名字查找)
json.load vs dump load=文件→内存(读);dump=内存→文件(写)
"r" / "w" / "a" r=读;w=写覆盖;a=写追加。JSON 永远用 w
同步 vs 异步 同步=等一个做完再做下一个;异步=同时发,谁先回来谁处理
def vs async def def=普通函数;async def=异步函数(里面有 await)
= vs == =赋值;==比较。写错不报错但逻辑错
: 和缩进 if/for/while/def/class 后面都有冒号,下一行缩进
self class 方法第一个参数,代表"我自己"。调用时不用传
init vs str init=创建时自动跑;str=print 时自动跑
.env 存 API Key,不写代码里。用 python-dotenv 读取
if name==main 只有直接运行本文件时才执行,被 import 时不执行

最后的话

这份笔记的核心就一句话:每次面对空白文件,先写骨架跑通,再一点一点往里填功能。

不要试图一次写完完整程序,先写 3 行跑一次,再写 3 行跑一次。

每天读一遍,读到这些模板能条件反射地写出来为止。


这是我的日常笔记,我感觉还行,每天都可以回来看一遍,感兴趣的小伙伴也可以去练练,实在不懂的,某seek,豆姐,某鸟教程看看就会了,反正做的时候没有模板我也是做不出来的,属于有想法,但是就差那临门一脚,只能看看能不能量变引起质变了,后面我每周都会把个人这周的学习笔记分享给大家的,大家觉得ok就点点赞留言留言,一起交流交流,或者有大佬(卖课的点击页面右上角谢谢~)能教教我提点我的最好了~~

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐