🐍 Python 语法全景图:一个 print() 引发的深度探索
摘要 :从一个简单的
print()函数签名出发,深入剖析 Python 的参数系统、对象模型、self机制、推导式、装饰器等核心语法特性,帮你建立完整的 Python 语法知识体系。
📑 目录
- [print() 函数签名:一个窗口看 Python 参数体系](#print() 函数签名:一个窗口看 Python 参数体系 "#%E4%B8%80print-%E5%87%BD%E6%95%B0%E7%AD%BE%E5%90%8D%E4%B8%80%E4%B8%AA%E7%AA%97%E5%8F%A3%E7%9C%8B-python-%E5%8F%82%E6%95%B0%E4%BD%93%E7%B3%BB")
- [Python 对象模型:一切皆对象](#Python 对象模型:一切皆对象 "#%E4%BA%8Cpython-%E5%AF%B9%E8%B1%A1%E6%A8%A1%E5%9E%8B%E4%B8%80%E5%88%87%E7%9A%86%E5%AF%B9%E8%B1%A1")
- [数据结构与推导式:Python 的标志性语法](#数据结构与推导式:Python 的标志性语法 "#%E4%B8%89%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E6%8E%A8%E5%AF%BC%E5%BC%8Fpython-%E7%9A%84%E6%A0%87%E5%BF%97%E6%80%A7%E8%AF%AD%E6%B3%95")
- 函数进阶:装饰器、闭包与生成器
- [面向对象:self、init 与魔术方法](#面向对象:self、init 与魔术方法 "#%E4%BA%94%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1selfinit-%E4%B8%8E%E9%AD%94%E6%9C%AF%E6%96%B9%E6%B3%95")
- [name 与模块化:Python 项目的入口机制](#name 与模块化:Python 项目的入口机制 "#name-%E4%B8%8E%E6%A8%A1%E5%9D%97%E5%8C%96python-%E9%A1%B9%E7%9B%AE%E7%9A%84%E5%85%A5%E5%8F%A3%E6%9C%BA%E5%88%B6")
- [现代 Python 语法糖:让代码更简洁](#现代 Python 语法糖:让代码更简洁 "#%E5%85%AD%E7%8E%B0%E4%BB%A3-python-%E8%AF%AD%E6%B3%95%E7%B3%96%E8%AE%A9%E4%BB%A3%E7%A0%81%E6%9B%B4%E7%AE%80%E6%B4%81")
- 异常处理:优雅地处理错误
- 综合实战:用所学知识构建一个简易工具
📌 前言
很多 Python 开发者写了好几年代码,可能都没认真看过 print() 函数的完整签名:
python
print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)
但就是这么一行签名,背后藏着 Python 语法的精髓------可变参数、关键字参数、默认值、文件对象、缓冲机制......
今天我们就从这个 print() 出发,一路延伸到 Python 语法的方方面面,帮你把零散的知识点串成体系。
🎯 本文适合谁
- 🔰 有基础但想系统梳理 Python 语法的开发者
- 💼 准备面试需要全面复习 Python 基础的同学
- 🚀 想从其他语言转 Python,快速掌握核心特性的工程师
- 📚 对 Python 设计哲学感兴趣的好奇宝宝
📚 一、print() 函数签名:一个窗口看 Python 参数体系
1.1 完整签名拆解
python
print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
*objects |
可变位置参数 | 无 | 一个或多个要输出的对象,自动转为字符串 |
sep |
str | ' ' |
多个对象之间的分隔符 |
end |
str | '\n' |
输出末尾追加的字符串 |
file |
文件对象 | sys.stdout |
输出的目标流(必须有 write() 方法) |
flush |
bool | False |
是否强制刷新输出缓冲区 |
1.2 可变位置参数 *args
python
print("a", "b", "c") # *objects 接收任意数量的位置参数
用 * 前缀表示,会把多个位置参数打包成一个元组 。命名不固定,常见约定是 *args。
python
def demo(*args):
print(type(args)) # <class 'tuple'>
print(args) # (1, 2, 3)
demo(1, 2, 3)
1.3 关键字参数 + 默认值
python
print("a", "b", sep="-", end="!")
# 输出: a-b!
调用时可以用 参数名=值 的形式显式指定,定义时可以给默认值,调用时可不传。
1.4 参数定义的顺序规则
Python 函数参数定义有严格的顺序:
python
def func(a, b, *args, c=10, **kwargs):
pass
# 位置参数 → *args → 关键字参数 → **kwargs
💡 记住这个顺序:位置参数 → 可变位置参数 → 关键字参数 → 可变关键字参数
1.5 可变关键字参数 **kwargs
python
def demo(**kwargs):
print(type(kwargs)) # <class 'dict'>
print(kwargs) # {'name': '旺财', 'age': 3}
demo(name="旺财", age=3)
用 ** 前缀表示,会把多个关键字参数打包成一个字典。
📚 二、Python 对象模型:一切皆对象
2.1 什么是对象?
在 Python 中,一切皆对象(Everything is an object)。
对象 = 数据(属性) + 行为(方法),是内存中实际存在的实体。
python
# 数字也是对象,有方法!
n = 42
print(n.bit_length()) # 6
# 字符串也是对象
s = "hello"
print(s.upper()) # HELLO
# 函数也是对象,可以挂载属性
def foo():
pass
foo.description = "这是一个函数"
print(foo.description)
# 类本身也是对象(元类的实例)
print(type(Dog)) # <class 'type'>
# 模块也是对象
import math
print(type(math)) # <class 'module'>
2.2 对象的三个核心特征
| 特征 | 获取方式 | 说明 |
|---|---|---|
| 身份(identity) | id(obj) |
对象的唯一内存地址 |
| 类型(type) | type(obj) |
对象所属的类 |
| 值(value) | 对象本身 | 存储的数据 |
python
a = [1, 2, 3]
print(id(a)) # 身份:内存地址
print(type(a)) # 类型:<class 'list'>
print(a) # 值:[1, 2, 3]
2.3 变量是引用,不是容器
这是 Python 新手最容易踩的坑:
python
a = [1, 2, 3]
b = a # b 和 a 指向同一个对象
b.append(4)
print(a) # [1, 2, 3, 4] ------ a 也变了!
⚠️ 变量不是对象本身,变量只是贴在对象上的"标签"(引用)。 修改对象时,所有指向它的变量都会看到变化。
2.4 可变对象 vs 不可变对象
| 类型 | 是否可变 | 例子 |
|---|---|---|
| 不可变对象 | 创建后值不能改 | int、float、str、tuple、bool、frozenset |
| 可变对象 | 创建后值可以改 | list、dict、set、自定义类实例 |
python
# 不可变:看起来"修改",其实是创建了新对象
s = "abc"
s = s.upper() # 不是改原字符串,而是返回新字符串对象
# 可变:直接修改原对象
lst = [1, 2, 3]
lst.append(4) # 原列表被修改
📚 三、数据结构与推导式:Python 的标志性语法
3.1 四大内置容器
| 类型 | 字面量 | 有序 | 可变 | 例子 |
|---|---|---|---|---|
| 列表 list | [] |
✅ | ✅ | [1, 2, 3] |
| 元组 tuple | () |
✅ | ❌ | (1, 2, 3) |
| 字典 dict | {} |
✅(3.7+) | ✅ | {"a": 1} |
| 集合 set | {} |
❌ | ✅ | {1, 2, 3} |
3.2 切片操作:序列类型的通用语法
python
lst = [0, 1, 2, 3, 4, 5]
lst[1:4] # [1, 2, 3] 从索引1到3
lst[::2] # [0, 2, 4] 步长为2
lst[::-1] # [5, 4, 3, 2, 1] 反转
lst[-1] # 5 最后一个元素
3.3 推导式:一行代码表达复杂逻辑
推导式是 Python 最具标志性的语法之一,简洁且高效:
python
# 列表推导式
squares = [x**2 for x in range(10)]
# [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
# 带条件的列表推导式
evens = [x for x in range(10) if x % 2 == 0]
# 字典推导式
square_dict = {x: x**2 for x in range(5)}
# 集合推导式
unique = {x % 3 for x in range(10)} # {0, 1, 2}
# 生成器推导式(惰性计算,节省内存)
gen = (x**2 for x in range(10))
3.4 解包操作:优雅的数据拆分
python
# 元组/列表解包
a, b, c = (1, 2, 3)
a, *rest = [1, 2, 3, 4] # a=1, rest=[2, 3, 4]
# 字典解包
d1 = {"a": 1}
d2 = {"b": 2}
merged = {**d1, **d2} # {"a": 1, "b": 2}
# 函数调用解包
args = (1, 2, 3)
print(*args) # 等同于 print(1, 2, 3)
📚 四、函数进阶:装饰器、闭包与生成器
4.1 Lambda 匿名函数
python
add = lambda x, y: x + y
print(add(3, 5)) # 8
# 常用于排序、映射
points = [(1, 2), (3, 1), (5, 4)]
points.sort(key=lambda p: p[1])
# [(3, 1), (1, 2), (5, 4)]
4.2 高阶函数:map / filter / reduce / zip
python
# map ------ 映射
list(map(lambda x: x*2, [1, 2, 3])) # [2, 4, 6]
# filter ------ 过滤
list(filter(lambda x: x > 0, [-1, 2, -3, 4])) # [2, 4]
# reduce ------ 归约
from functools import reduce
reduce(lambda x, y: x + y, [1, 2, 3, 4]) # 10
# zip ------ 配对
list(zip([1, 2, 3], ["a", "b", "c"]))
# [(1, 'a'), (2, 'b'), (3, 'c')]
4.3 装饰器:不修改原函数,为其增加功能
装饰器是 Python 中最优雅的设计模式之一:
python
import time
import functools
def timer(func):
@functools.wraps(func) # ⚠️ 必须加!保留原函数的元信息(名称、文档等)
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
print(f"{func.__name__} 耗时: {time.time()-start:.4f}s")
return result
return wrapper
@timer # 等同于 slow_func = timer(slow_func)
def slow_func():
time.sleep(1)
slow_func()
print(slow_func.__name__) # slow_func(如果没有 @wraps,会变成 wrapper)
💡 装饰器的本质 :
@timer语法糖等价于slow_func = timer(slow_func),它接收一个函数,返回一个增强后的新函数。
⚠️ 踩坑提醒 :不加@functools.wraps(func)会导致原函数的__name__、__doc__等元信息丢失。我曾经在项目中因为漏掉这个,导致 Flask 路由注册全部指向同一个函数名,排查了两个小时才发现。记住:写装饰器,第一行就写@wraps。
4.4 闭包与作用域(LEGB 规则)
Python 查找变量的顺序:Local → Enclosing → Global → Built-in
python
def outer():
x = 10 # Enclosing 作用域
def inner():
print(x) # 从闭包中捕获 x
return inner
f = outer()
f() # 10
4.5 生成器:用 yield 实现惰性计算
python
def countdown(n):
while n > 0:
yield n
n -= 1
for num in countdown(3):
print(num) # 3, 2, 1
生成器不会一次性把所有值加载到内存,而是用到时才计算,非常适合处理大数据流。
📚 五、面向对象:self、init 与魔术方法
5.1 self 到底是什么?
很多从 Java/C++ 转来的同学会疑惑:为什么 Python 的实例方法必须显式写 self,而 Java 的 this 不需要?
python
class Dog:
def __init__(self, name):
self.name = name # self 指向正在被创建的实例
def bark(self):
print(f"{self.name}: 汪汪!")
dog = Dog("旺财")
dog.bark() # 旺财: 汪汪!
self 的本质 :它就是实例对象自身的引用 。当你调用 dog.bark() 时,Python 会自动把 dog 作为第一个参数传入,所以 bark(self) 里的 self 就是 dog。
🤔 为什么 Python 选择显式写
self?Python 的设计哲学是 "Explicit is better than implicit"(显式优于隐式) 。显式声明
self让你一眼就能区分实例属性和局部变量,也让方法的定义和调用保持一致性------虽然写起来多了几个字母,但代码的可读性和确定性更高。
常见错误:忘记写 self
python
class Dog:
def bark(): # ❌ 忘记 self
print("汪汪")
dog = Dog()
dog.bark() # TypeError: bark() takes 0 positional arguments but 1 was given
Python 报错说"bark 需要 0 个参数但给了 1 个"------因为 dog.bark() 等价于 Dog.bark(dog),dog 被传进去了但函数签名里没有 self 来接收。
5.2 init:构造函数的正确打开方式
__init__ 是 Python 中最常用的魔术方法,负责初始化新创建的实例:
python
class Dog:
def __init__(self, name, age=0): # 支持默认参数
self.name = name
self.age = age
dog = Dog("旺财", 3)
init vs new 的区别:
__new__ |
__init__ |
|
|---|---|---|
| 作用 | 创建实例(分配内存) | 初始化实例(设置属性) |
| 第一个参数 | cls(类本身) |
self(实例) |
| 调用时机 | 在 __init__ 之前 |
在 __new__ 之后 |
| 何时重写 | 单例模式、不可变类型子类化 | 日常开发几乎只用这个 |
python
class Singleton:
_instance = None
def __new__(cls, *args, **kwargs):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
def __init__(self, name):
self.name = name
a = Singleton("A")
b = Singleton("B")
print(a is b) # True ------ 同一个实例!
print(a.name) # B ------ __init__ 被调用了两次
⚠️ 经典踩坑:可变默认参数
python# ❌ 错误写法:所有实例共享同一个列表! class BadExample: def __init__(self, items=[]): # 默认参数在定义时求值,只创建一次 self.items = items a = BadExample() a.items.append(1) b = BadExample() print(b.items) # [1] ------ b 居然看到了 a 添加的元素! # ✅ 正确写法 class GoodExample: def __init__(self, items=None): self.items = items if items is not None else []
继承中的 init 调用链:
python
class Animal:
def __init__(self, name):
self.name = name
class Dog(Animal):
def __init__(self, name, breed):
super().__init__(name) # 调用父类的 __init__
self.breed = breed
dog = Dog("旺财", "柴犬")
print(dog.name) # 旺财
print(dog.breed) # 柴犬
5.3 封装:属性访问控制
python
class Account:
def __init__(self):
self._balance = 0 # 单下划线:约定为"私有"
@property
def balance(self): # getter
return self._balance
@balance.setter
def balance(self, value): # setter
if value < 0:
raise ValueError("余额不能为负")
self._balance = value
acc = Account()
acc.balance = 100
print(acc.balance) # 100
5.4 方法分类
python
class MyClass:
def instance_method(self): # 实例方法:第一个参数是 self
pass
@classmethod
def class_method(cls): # 类方法:第一个参数是 cls
pass
@staticmethod
def static_method(): # 静态方法:无强制参数
pass
5.5 多继承与 MRO
python
class A: pass
class B(A): pass
class C(A): pass
class D(B, C): pass
print(D.__mro__)
# (<class 'D'>, <class 'B'>, <class 'C'>, <class 'A'>, <class 'object'>)
Python 使用 C3 线性化算法确定方法解析顺序(MRO),解决了菱形继承问题。
🤔 为什么 Python 支持多继承而 Java 不允许? Python 选择了灵活性------通过 MRO 算法保证方法调用的确定性。但实践中,优先使用组合而非多继承,多继承更适合 Mixin 模式。
5.6 魔术方法一览
| 方法 | 触发场景 |
|---|---|
__init__ |
对象创建时(初始化) |
__new__ |
对象分配内存(创建实例) |
__str__ / __repr__ |
print() / 交互模式显示 |
__len__ |
len(obj) |
__getitem__ / __setitem__ |
obj[key] 读写 |
__iter__ / __next__ |
for 循环迭代 |
__enter__ / __exit__ |
with 语句 |
__call__ |
obj() 调用 |
__eq__ / __lt__ 等 |
比较运算符 |
📚 六、name 与模块化:Python 项目的入口机制
6.1 name 是什么?
__name__ 是 Python 的一个内置属性 ,每个 .py 文件(模块)都有。它的值取决于文件是如何被使用的:
python
# my_module.py
print(f"__name__ = {__name__}")
def hello():
print("Hello!")
python
# 直接运行 my_module.py
# 输出:__name__ = __main__
# 在另一个文件中导入
import my_module
# 输出:__name__ = my_module
| 场景 | __name__ 的值 |
|---|---|
文件被直接运行(python my_module.py) |
"__main__" |
文件被导入(import my_module) |
"my_module"(模块名) |
6.2 if name == "main":控制代码执行时机
这是 Python 项目中最常见的模式之一,用于区分"被直接运行"和"被导入":
python
# calculator.py
def add(a, b):
return a + b
def subtract(a, b):
return a - b
# 只在直接运行时执行,被导入时不执行
if __name__ == "__main__":
print(add(1, 2)) # 3
print(subtract(5, 3)) # 2
为什么需要这个?
python
# main.py
import calculator
result = calculator.add(10, 20) # ✅ 只导入函数,不会触发测试代码
如果没有 if __name__ == "__main__" 守卫,每次 import calculator 都会执行 print(add(1, 2))------这不是我们想要的。
💡 实际项目中的典型用法:
- 单元测试 :把测试代码放在
if __name__ == "__main__"里,模块被导入时不会执行测试- 脚本入口:CLI 工具的启动代码放在这个守卫里
- 调试代码:临时的调试 print 可以放在这里,不会污染导入方
python
# 一个完整的 CLI 脚本模板
import argparse
def process_data(data, verbose=False):
"""核心业务逻辑"""
result = data.upper()
if verbose:
print(f"处理结果: {result}")
return result
def main():
parser = argparse.ArgumentParser(description="数据处理工具")
parser.add_argument("data", help="要处理的数据")
parser.add_argument("-v", "--verbose", action="store_true")
args = parser.parse_args()
result = process_data(args.data, verbose=args.verbose)
print(result)
if __name__ == "__main__":
main()
📚 七、现代 Python 语法糖:让代码更简洁
7.1 f-string 格式化字符串(3.6+)
python
name = "旺财"
age = 3
print(f"{name} {age}岁") # 旺财 3岁
print(f"{2 + 2 = }") # 2 + 2 = 4(3.8+ 调试语法)
7.2 海象运算符 := (3.8+)
在表达式中同时赋值和使用:
python
# 传统写法
line = input()
while line != "quit":
print(line)
line = input()
# 海象运算符写法
while (line := input()) != "quit":
print(line)
7.3 dataclass(3.7+)
自动生成 __init__、__repr__ 等样板代码:
python
from dataclasses import dataclass
@dataclass
class User:
name: str
age: int
email: str = ""
u = User("张三", 25)
print(u) # User(name='张三', age=25, email='')
7.4 match-case 模式匹配(3.10+)
python
def http_error(status):
match status:
case 200:
return "OK"
case 404:
return "Not Found"
case 500 | 503:
return "Server Error"
case _:
return "Unknown"
7.5 类型注解(3.5+)
python
def greet(name: str) -> str:
return f"Hello, {name}"
# Python 3.10+ 简化写法
def func(x: int | None) -> list[int]:
...
7.6 上下文管理器与 with 语句
python
# 基于类实现
class MyContext:
def __enter__(self):
print("进入")
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print("退出")
return False
# 基于生成器(更简洁)
from contextlib import contextmanager
@contextmanager
def my_context():
print("进入")
yield
print("退出")
📚 八、异常处理:优雅地处理错误
python
try:
result = 10 / 0
except ZeroDivisionError as e:
print(f"除零错误: {e}")
except (TypeError, ValueError) as e:
print(f"类型或值错误: {e}")
else:
print("没有异常时执行")
finally:
print("无论是否异常都执行")
# 自定义异常
class MyError(Exception):
pass
raise MyError("自定义错误信息")
💡 try/except/else/finally 四兄弟各有分工:
except捕获异常,else在无异常时执行,finally无论如何都执行(常用于资源清理)。
💡 九、重点总结
从一个 print() 函数出发,我们串起了 Python 语法的几大支柱:
| 语法特性 | 核心要点 |
|---|---|
| 函数参数系统 | *args / **kwargs / 默认值 / 关键字参数 |
| 对象模型 | 一切皆对象,变量是引用,可变 vs 不可变 |
| self 与 init | self 是实例引用,init 初始化实例,可变默认参数陷阱 |
| name 与模块化 | if __name__ == "__main__" 控制模块入口 |
| 数据结构 | list / dict / set / tuple,切片,推导式,解包 |
| 函数式编程 | lambda / map / filter / 装饰器(+wraps) / 生成器 / 闭包 |
| 面向对象 | 封装 / 继承 / 多态 / 魔术方法 / MRO |
| 现代语法糖 | f-string / 海象运算符 / dataclass / match-case / 类型注解 |
| 工程化支撑 | 异常处理 / 上下文管理器 / 模块包管理 |
Python 的设计哲学是 「简洁而强大」------用最少的代码表达最复杂的逻辑。这些语法特性不是孤立的,它们相互配合,构成了 Python 独特的编程范式。
🛠️ 十、综合实战:用所学知识构建一个简易缓存装饰器
学了这么多语法特性,最后我们用一个实战案例把它们串起来。下面实现一个带 TTL(过期时间)和日志的缓存装饰器:
python
import time
import functools
from datetime import datetime
# ========== 1. 装饰器 + functools.wraps(4.3 节) ==========
def cache_with_ttl(ttl_seconds=60):
"""带过期时间的缓存装饰器(装饰器工厂:外层接收参数,内层接收函数)"""
def decorator(func):
cache = {} # 闭包捕获的变量(4.4 节)
@functools.wraps(func) # 保留原函数元信息
def wrapper(*args, **kwargs): # 可变参数(1.2 节)
key = (args, tuple(sorted(kwargs.items())))
# 上下文管理器思路:检查缓存是否过期
if key in cache:
result, timestamp = cache[key]
if time.time() - timestamp < ttl_seconds:
print(f"[缓存命中] {func.__name__}{args}")
return result
else:
del cache[key] # 过期清除
# 调用原函数并缓存结果
result = func(*args, **kwargs)
cache[key] = (result, time.time())
print(f"[缓存写入] {func.__name__}{args}")
return result
wrapper.cache_clear = lambda: cache.clear() # 动态属性(对象特性,2.1 节)
return wrapper
return decorator
# ========== 2. 类 + self + __init__ + __str__(5.1、5.2 节) ==========
class APIClient:
"""模拟 API 客户端"""
def __init__(self, base_url: str, timeout: int = 30): # __init__ + 默认参数
self.base_url = base_url
self.timeout = timeout
self._request_count = 0 # 私有属性(5.3 节)
@property
def request_count(self) -> int: # @property + 类型注解(7.5 节)
return self._request_count
def __str__(self) -> str: # 魔术方法(5.6 节)
return f"APIClient({self.base_url}, 请求次数={self._request_count})"
@cache_with_ttl(ttl_seconds=10) # 装饰器应用(4.3 节)
def get_user(self, user_id: int) -> dict:
"""模拟 API 调用(实际项目中会用 requests)"""
self._request_count += 1
time.sleep(0.5) # 模拟网络延迟
return {"id": user_id, "name": f"用户{user_id}"}
# ========== 3. 异常处理 + with 语句(8 节、7.6 节) ==========
def safe_api_call(client: APIClient, user_id: int):
"""带异常处理的安全调用"""
try:
result = client.get_user(user_id)
except Exception as e: # 通用异常捕获
print(f"❌ 请求失败: {e}")
return None
else:
print(f"✅ 请求成功: {result}")
return result
finally:
print(f"📊 当前请求次数: {client.request_count}")
# ========== 4. if __name__ == "__main__"(6.2 节) ==========
if __name__ == "__main__":
# f-string 格式化(7.1 节)
client = APIClient("https://api.example.com")
print(f"客户端信息: {client}")
# 第一次调用:缓存写入
safe_api_call(client, 1)
# 第二次调用:缓存命中(不会真正调用 API)
safe_api_call(client, 1)
# 不同参数:缓存未命中
safe_api_call(client, 2)
运行输出:
css
客户端信息: APIClient(https://api.example.com, 请求次数=0)
[缓存写入] get_user(1,)
✅ 请求成功: {'id': 1, 'name': '用户1'}
📊 当前请求次数: 1
[缓存命中] get_user(1,)
✅ 请求成功: {'id': 1, 'name': '用户1'}
📊 当前请求次数: 1
[缓存写入] get_user(2,)
✅ 请求成功: {'id': 2, 'name': '用户2'}
📊 当前请求次数: 2
💡 这个小案例用到了本文讲过的 :装饰器 +
functools.wraps、*args/**kwargs、闭包、类定义、self/__init__、@property、魔术方法__str__、异常处理、if __name__ == "__main__"、f-string、类型注解------一个案例串联了 10+ 个语法特性。
🔗 参考资料
- Python 官方文档 - Built-in Functions
- Python 官方文档 - Data Model
- PEP 572 - Assignment Expressions (海象运算符)
- PEP 557 - Data Classes
- PEP 318 - Decorators
💬 交流讨论
看到这里,不妨来挑战一下:
- 🧠 面试题 :
__init__和__new__的区别是什么?什么场景需要重写__new__? - 💬 评论区打卡 :你在项目中踩过最深的 Python 坑是什么?(我先来:装饰器没加
@wraps导致 Flask 路由全乱了 😂) - ⭐ 觉得有收获的话,点个收藏,下次面试前翻出来复习会感谢自己的!
📖 下一篇预告:《Python 高级特性:迭代器协议、描述符、元类------从"会用"到"懂原理"》敬请期待!