☰
Python语法快速入门指南
2026/10/12 14:02:30 网站建设 项目流程

前言


「快速入门」最大的陷阱,是把「语法速查」当成「上手」。查一次sorted的签名不难,难的是拿到一份陌生代码时知道从哪看起、写一个小工具时知道骨架怎么搭。这篇指南就按这两条线组织:上半篇给你能直接套用的骨架,下半篇给你一眼看懂别人代码的阅读顺序。


提前说明版本问题:Python 2.7 已于 2020 年 1 月 1 日停止维护。老资料里的print "x"、raw_input()、except X, e、d.iteritems()在 Python 3 里全部不能用。本文只写 Python 3,示例适用于 3.8 及以上。


另外纠正一个常见说法:「Python 是解释型语言,不需要编译」。CPython 是先把源码编译成字节码再由虚拟机执行的,dis.dis()能看到指令。知道你写的东西会先变成字节码,有助于理解为什么模块会被缓存成__pycache__里的.pyc。


一、五分钟核心语法速查




主题语法关键提醒



赋值a = 1;a, b = 1, 2是名字绑定,不是复制

输出print(x, sep=..., end=...)print是函数,不是语句

输入input("提示")返回str,务必转换

条件if / elif / else冒号 + 缩进,无switch

循环for x in iterable:/while cond:range左闭右开

函数def f(a, b=1, *args, **kw):默认参数只求值一次

类class C:/def __init__(self):首参是self

异常try / except X as e / finally不写裸except:

导入import x/from x import yimport会执行顶层代码

推导式[f(x) for x in xs if p(x)]有自己的作用域



二、五套实战骨架(可直接运行)


骨架一:脚本


最小可直接运行的脚本长这样:


# 适用于 Python 3.8+
"""一句话说明这个脚本做什么。"""

import sys


def main(argv):
if len(argv) != 2:
print(f"用法:python {argv[0]} 目标参数", file=sys.stderr)
return 2
print("收到:", argv[1])
return 0


if __name__ == "__main__":
raise SystemExit(main(sys.argv))

三个约定:main()接收参数列表并返回退出码;错误信息写到sys.stderr而不是stdout;raise SystemExit(main(...))把返回值当退出码。sys.argv[0]是脚本自身的名字。


骨架二:命令行工具


参数超过两个就别手撸sys.argv了:


# 适用于 Python 3.8+
import argparse


def build_parser():
parser = argparse.ArgumentParser(description="演示用命令行工具")
parser.add_argument("src", help="输入路径")
parser.add_argument("-o", "--output", default="-", help="输出路径,默认标准输出")
parser.add_argument("-n", "--count", type=int, default=10, help="处理条数")
parser.add_argument("-v", "--verbose", action="store_true", help="输出详细日志")
return parser


if __name__ == "__main__":
args = build_parser().parse_args()
print(args.src, args.output, args.count, args.verbose)

位置参数不带前缀;可选参数带-/--;type=int负责转换和报错;action="store_true"把开关变成布尔值。argparse还会自动生成-h帮助。


骨架三:文件处理


# 适用于 Python 3.8+
from pathlib import Path


def process(src: Path, dst: Path) -> int:
"""逐行处理,返回处理的行数。"""
count = 0
with src.open(encoding="utf-8") as fin, dst.open("w", encoding="utf-8") as fout:
for line in fin:
stripped = line.rstrip("\n")
if not stripped:
continue
fout.write(stripped.upper() + "\n")
count += 1
return count


if __name__ == "__main__":
print(process(Path("in.txt"), Path("out.txt")))

要点:with支持一行开两个文件(3.10 起还能写成带括号的多行形式);encoding必须显式写;大文件用for line in fin:惰性读,不要readlines()。


骨架四:异常与日志


# 适用于 Python 3.8+
import logging
import sys

logging.basicConfig(
level=logging.INFO,
format="%(asctime)s %(levelname)s %(name)s %(message)s",
stream=sys.stderr,
)
logger = logging.getLogger(__name__)


def divide(a, b):
if b == 0:
raise ValueError("除数不能为零")
return a / b


try:
result = divide(1, 0)
except ValueError as exc:
logger.warning("计算失败:%s", exc)
else:
print(result)
finally:
logger.info("结束")

用logger.warning("模板 %s", 值)而不是 f-string 拼好再传,这样日志级别被过滤时不会白白做字符串格式化。异常只捕获你真正能处理的那一层,捕获不了就让它往上抛。


骨架五:正则与 JSON


# 适用于 Python 3.8+
import json
import re

KV = re.compile(r"(\w+)=(\d+)")

text = "set width=20 and height=10"
print(KV.findall(text)) # [('width', '20'), ('height', '10')]
print(re.sub(r"\d+", "#", text)) # set width=# and height=#
print(re.search(r"\d+", text).group())

payload = json.dumps({"名字": "小明"}, ensure_ascii=False, indent=2)
print(payload)
print(json.loads(payload)["名字"])

re.compile后复用模式对象,比每次调用re.findall传字符串更清晰。re.findall的签名是re.findall(pattern, string, flags=0),有捕获组时返回元组列表;re.sub是re.sub(pattern, repl, string, count=0, flags=0)。json.dumps的ensure_ascii默认是True,中文会变成\uXXXX。


三、几个必须先分清的点


re.match与re.search不一样




函数从哪里开始匹配是否需要整串匹配



re.match只在字符串开头否,只要求开头匹配

re.search任意位置否

re.fullmatch整串是



# 适用于 Python 3.8+
import re

print(bool(re.match(r"\d+", "abc123"))) # False,开头不是数字
print(bool(re.search(r"\d+", "abc123"))) # True
print(bool(re.fullmatch(r"\d+", "123"))) # True
print(bool(re.fullmatch(r"\d+", "123abc"))) # False

用re.match(pattern, s)却期望「整串是数字」是高频错误,正确工具是re.fullmatch。另外不要用正则解析 HTML 或 JSON——那是另一类工具的事。


四、八步读懂一份陌生的 Python 代码


拿到别人写的脚本,按这个顺序看,比从第一行读起快得多:



  1. 看有没有if __name__ == "__main__":,找到真正的入口。

  2. 看 import:标准库 / 第三方 / 本地三组,能大致判断它在干什么。

  3. 看顶层常量与配置:大写名字通常是常量。

  4. 看def的签名:参数名和默认值比函数体更能说明接口。

  5. 看类型标注(如果有):def f(x: int) -> str:直接告诉你不该传什么。

  6. 看class的__init__:实例属性全在那里。

  7. 看异常处理:except捕获什么,说明作者预见什么失败。

  8. 最后才看循环与分支的细节。


# 适用于 Python 3.8+
from dataclasses import dataclass


@dataclass
class Job:
name: str
retries: int = 3
tags: tuple = ()

def label(self) -> str:
return f"{self.name}({self.retries})"


print(Job("backup", tags=("nightly",)))

类型标注和dataclasses是阅读代码时最省力的线索:@dataclass会自动生成__init__、__repr__、__eq__,所以类体里看不到构造逻辑是正常的,不必到处找。


常见坑点



  1. ❌ 用re.match(r"\d+", s)判断「整个字符串是数字」 ✅re.match只要求开头匹配,"123abc"也会通过;要整串匹配用re.fullmatch。

  2. ❌ 以为input()返回数字 ✅ 它永远返回str,input() + 1会抛TypeError;先转换并处理ValueError。

  3. ❌ 用logging.warning(f"值 {v}")图省事 ✅ 写logging.warning("值 %s", v),让格式化在级别过滤之后才发生。

  4. ❌ 在脚本里直接用sys.argv[1]✅ 参数缺失会抛IndexError;用argparse或先检查len(sys.argv)。

  5. ❌ 打开文件不写encoding✅ 默认编码是平台相关的,跨平台必须写encoding="utf-8"。

  6. ❌ 照着老资料写except ValueError, e:✅ 这是 Python 2 语法,早已移除;Python 3 写except ValueError as e:。

  7. ❌ 用裸except:让脚本「不崩」 ✅ 它会吞掉KeyboardInterrupt和SystemExit,脚本会变成 Ctrl+C 都杀不掉的僵尸;至少写except Exception:。

  8. ❌ 认为import不会执行任何代码 ✅import会执行模块顶层语句,有副作用的代码要放进main()并用if __name__ == "__main__":保护。


总结




需求直接套用的骨架关键点



写脚本main(argv)+raise SystemExit(...)返回退出码,错误走 stderr

收参数argparse.ArgumentParsertype=负责转换与报错

处理文件with src.open(encoding="utf-8") as fin:显式编码,惰性逐行

打日志logging.getLogger(__name__)用%s占位,不用 f-string

匹配文本re.compile+fullmatch/search分清 match 与 fullmatch

序列化json.dumps(..., ensure_ascii=False)中文要关掉 ASCII 转义

读代码入口 → import → 签名 → 类 → 异常别从第一行硬读



快速入门的正确姿势,不是把语法表背下来,而是记住几个能改就用的骨架,再带着「名字绑定不是复制」「input()返回字符串」「re.match不要求整串匹配」这三类高频陷阱去读别人的代码。骨架省下的是敲键盘的时间,陷阱省下的是调试的时间。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询