这是一份专为前端工程师设计的Python完整教程。通过JavaScript对比学习,让你快速掌握Python的所有核心语法。
随着ai普及,对程序员的要求会更高,全栈是趋势
对自己有比较清楚的认知,我大概率一直为牛马
预计学习时间:3-4小时
前置要求:熟悉JavaScript
核心概念:Python的变量不需要声明类型,赋值即创建。这和JavaScript的let类似,但更简洁。
// JavaScript - 需要关键字声明const PI = 3.14; // 常量(不可修改)let count = 0; // 变量(可修改)var oldStyle = 1; // 不推荐(作用域问题)// 试图修改常量会报错PI = 3.15; // ❌ TypeError: Assignment to constant variable# Python - 直接赋值即可PI = 3.14# 约定:大写表示常量(但实际可修改)count = 0# 变量old_style = 1# Python没有var,都是变量# Python没有真正的常量机制PI = 3.15# ✅ 可以修改,但不建议(靠约定)JavaScript的变量声明:
const:块级作用域,不可重新赋值(但对象属性可修改)let:块级作用域,可重新赋值var:函数作用域,存在变量提升问题Python的变量声明:
// JavaScript - 类型可变,但需要重新赋值let value = 42; // numbervalue = "hello"; // string - 可以,但TypeScript会报错value = [1, 2, 3]; // array - 可以# Python - 类型完全自由value = 42# intvalue = "hello"# str - 完全没问题value = [1, 2, 3] # list - 很自然value = {"key": "val"} # dict - 随便切换# 查看类型print(type(value)) # <class 'dict'>// JavaScript - 驼峰命名(camelCase)const userName = "张三";let userAge = 25;const MAX_SIZE = 100; // 常量用大写# Python - 蛇形命名(snake_case)user_name = "张三"user_age = 25MAX_SIZE = 100# 常量用大写# Python命名规范(PEP 8)# 变量和函数:lowercase_with_underscores# 类名:CapitalizedWords# 常量:UPPERCASE_WITH_UNDERSCORES// JavaScript - 解构赋值const [a, b, c] = [1, 2, 3];const {name, age} = {name: "张三", age: 25};// 交换变量需要临时变量let x = 1, y = 2;[x, y] = [y, x]; // ES6+ 支持# Python - 更简洁的多变量赋值a, b, c = 1, 2, 3# 多变量赋值name, age = "张三", 25# 同时赋值# 交换变量(Python特色)x, y = 1, 2x, y = y, x # 无需临时变量!# 解包(类似解构)first, *middle, last = [1, 2, 3, 4, 5]print(first) # 1print(middle) # [2, 3, 4]print(last) # 5// JavaScript - 常量配置const config = {API_URL: "https://api.example.com",TIMEOUT: 5000,MAX_RETRIES: 3};// 不能重新赋值config,但可以修改属性// config = {}; // ❌ 错误config.TIMEOUT = 10000; // ✅ 可以# Python - 常量配置(约定)# config.py 文件API_URL = "https://api.example.com"TIMEOUT = 5000MAX_RETRIES = 3# 使用from config import API_URL, TIMEOUT# 虽然可以修改,但不应该这样做# TIMEOUT = 10000 # ⚠️ 违反约定# 如果需要真正的常量,可以使用类classConfig: API_URL = "https://api.example.com" TIMEOUT = 5000def__setattr__(self, key, value):raise AttributeError("Constants are immutable")constlet/var | ||
const | ||
// JavaScript// 单行注释/* 多行注释 多行注释*//** * JSDoc 注释 * @param {string}name */# Python# 单行注释"""多行注释多行注释"""defgreet(name: str) -> str:""" 函数文档字符串(docstring) Args: name: 用户名 Returns: 问候语 """returnf"Hello, {name}"核心概念:Python的字符串功能非常强大,f-string(格式化字符串)几乎和JavaScript的模板字符串一样好用。
// JavaScript - 三种字符串定义方式const single = 'Hello'; // 单引号const double = "World"; // 双引号(推荐)const template = `Hello ${name}`; // 模板字符串(ES6+)// 多行字符串const multiLine = ` 第一行 第二行 第三行`;# Python - 也是三种方式single = 'Hello'# 单引号double = "World"# 双引号(推荐)f_string = f"Hello {name}"# f-string(Python 3.6+)# 多行字符串multi_line = """ 第一行 第二行 第三行"""# 也可以用三个单引号multi_line2 = ''' 这也是多行字符串'''// JavaScript - 模板字符串const name = "张三";const age = 25;// 方式1:模板字符串(推荐)const msg1 = `我叫${name},今年${age}岁`;// 方式2:字符串拼接(老式)const msg2 = "我叫" + name + ",今年" + age + "岁";// 方式3:表达式const msg3 = `明年我${age + 1}岁`;# Python - 多种格式化方式name = "张三"age = 25# 方式1:f-string(推荐,Python 3.6+)msg1 = f"我叫{name},今年{age}岁"# 方式2:format方法(Python 2.7+)msg2 = "我叫{},今年{}岁".format(name, age)msg3 = "我叫{name},今年{age}岁".format(name=name, age=age)# 方式3:百分号格式化(老式,不推荐)msg4 = "我叫%s,今年%d岁" % (name, age)# 方式4:字符串拼接msg5 = "我叫" + name + ",今年" + str(age) + "岁"# 注意:需要转换类型# f-string中的表达式msg6 = f"明年我{age + 1}岁"msg7 = f"名字长度:{len(name)}"// JavaScript - 字符串方法const text = " Hello World ";text.length; // 13 - 长度text.toUpperCase(); // " HELLO WORLD "text.toLowerCase(); // " hello world "text.trim(); // "Hello World"text.split(" "); // ["", "", "Hello", "World", "", ""]text.includes("Hello"); // truetext.startsWith(" H"); // truetext.endsWith("d "); // truetext.replace("Hello", "Hi"); // " Hi World "text.substring(2, 7); // "Hello"text.charAt(2); // "H"text.indexOf("World"); // 8# Python - 字符串方法(更丰富)text = " Hello World "len(text) # 13 - 长度(函数,不是方法)text.upper() # " HELLO WORLD "text.lower() # " hello world "text.strip() # "Hello World" - 去除两端空格text.lstrip() # "Hello World " - 去除左边空格text.rstrip() # " Hello World" - 去除右边空格text.split() # ["Hello", "World"] - 自动处理多个空格text.split(" ") # ["", "", "Hello", "World", "", ""]"Hello"in text # True - 成员检查text.startswith(" H") # Truetext.endswith("d ") # Truetext.replace("Hello", "Hi") # " Hi World "text[2:7] # "Hello" - 切片text[2] # "H" - 索引text.find("World") # 8 - 查找位置(找不到返回-1)text.index("World") # 8 - 查找位置(找不到抛异常)# Python特有的实用方法text.count("l") # 3 - 统计字符出现次数text.isdigit() # False - 是否全是数字text.isalpha() # False - 是否全是字母text.isalnum() # False - 是否全是字母或数字"-".join(["2026", "03", "17"]) # "2026-03-17" - 拼接text.capitalize() # " hello world " - 首字母大写text.title() # " Hello World " - 每个单词首字母大写// JavaScript - 使用substring/sliceconst text = "Hello World";text.substring(0, 5); // "Hello"text.slice(0, 5); // "Hello"text.slice(-5); // "World" - 倒数5个字符text.slice(6); // "World" - 从索引6开始// 没有简单的反转字符串方法text.split('').reverse().join(''); // "dlroW olleH"# Python - 切片功能超强大text = "Hello World"# 基本切片 [start:end:step]text[0:5] # "Hello" - 从索引0到5(不含5)text[:5] # "Hello" - 省略start,从头开始text[6:] # "World" - 省略end,到结尾text[:] # "Hello World" - 复制整个字符串# 负索引text[-5:] # "World" - 倒数5个字符text[:-6] # "Hello" - 到倒数第6个字符text[-1] # "d" - 最后一个字符# 步长(step)text[::2] # "HloWrd" - 每隔一个字符text[::-1] # "dlroW olleH" - 反转字符串!text[1:8:2] # "el o" - 从1到8,每隔一个# 实用技巧text[::1] # 正向复制text[::-1] # 反转text[1::2] # 奇数索引的字符text[::2] # 偶数索引的字符// JavaScript - 验证和清理用户输入functionvalidateEmail(email) { email = email.trim(); // 去空格if (!email.includes('@')) {returnfalse; }if (!email.endsWith('.com') && !email.endsWith('.cn')) {returnfalse; }returntrue;}// 提取文件名const path = "/Users/name/document.txt";const fileName = path.split('/').pop(); // "document.txt"# Python - 更简洁的字符串处理defvalidate_email(email): email = email.strip() # 去空格if'@'notin email:returnFalseifnot (email.endswith('.com') or email.endswith('.cn')):returnFalsereturnTrue# 提取文件名path = "/Users/name/document.txt"file_name = path.split('/')[-1] # "document.txt"# 或者使用pathlib(更专业)from pathlib import Pathfile_name = Path(path).name # "document.txt"// JavaScript - 格式化金额functionformatMoney(amount) {return`¥${amount.toFixed(2)}`;}console.log(formatMoney(1234.5)); // "¥1234.50"// 格式化日期const date = newDate();const formatted = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;# Python - 格式化金额defformat_money(amount):returnf"¥{amount:.2f}"# .2f 表示保留2位小数print(format_money(1234.5)) # "¥1234.50"# 格式化日期from datetime import datetimedate = datetime.now()formatted = date.strftime("%Y-%m-%d") # "2026-03-17"# f-string高级格式化price = 1234.5678print(f"{price:.2f}") # "1234.57" - 保留2位小数print(f"{price:,.2f}") # "1,234.57" - 千分位分隔print(f"{price:>10.2f}") # " 1234.57" - 右对齐,宽度10print(f"{price:<10.2f}") # "1234.57 " - 左对齐print(f"{price:^10.2f}") # " 1234.57 " - 居中对齐# 百分比ratio = 0.8567print(f"{ratio:.2%}") # "85.67%" - 百分比格式# 科学计数法big_num = 1234567890print(f"{big_num:e}") # "1.234568e+09"// JavaScript - 字符串不可变let str = "Hello";str[0] = "h"; // 无效,但不报错console.log(str); // 还是 "Hello"// 必须重新赋值str = "hello";# Python - 字符串也不可变text = "Hello"# text[0] = "h" # ❌ TypeError: 'str' object does not support item assignment# 必须创建新字符串text = "h" + text[1:] # "hello"# 或者转换成列表再修改chars = list(text)chars[0] = "h"text = "".join(chars) # "hello"\ | f"Hello {name}" | |
"""''' | ||
str.length | len(str) | |
str.includes() | in | |
slice() | [start:end:step] | |
[::-1] | ||
// JavaScriptif (age >= 18) {console.log("成年");} elseif (age >= 12) {console.log("青少年");} else {console.log("儿童");}// 三元运算符const status = age >= 18 ? "成年" : "未成年";# Python(注意缩进!)if age >= 18: print("成年")elif age >= 12: print("青少年")else: print("儿童")# 三元表达式status = "成年"if age >= 18else"未成年"核心概念:Python的for循环更像JavaScript的for...of,而不是传统的for(i=0; i<n; i++)。
// JavaScript - C风格for循环for (let i = 0; i < 5; i++) {console.log(i); // 0, 1, 2, 3, 4}// for...of(遍历值)const arr = [1, 2, 3];for (const item of arr) {console.log(item); // 1, 2, 3}// for...in(遍历索引,不推荐用于数组)for (const index in arr) {console.log(index); // "0", "1", "2" - 注意是字符串}// forEach(函数式)arr.forEach((item, index) => {console.log(index, item);});// while循环let i = 0;while (i < 5) {console.log(i); i++;}# Python - 没有C风格for,更像for...of# for + range(生成数字序列)for i in range(5): print(i) # 0, 1, 2, 3, 4# for...in(直接遍历元素)arr = [1, 2, 3]for item in arr: print(item) # 1, 2, 3# enumerate(带索引,类似forEach)for index, item in enumerate(arr): print(index, item) # 0 1, 1 2, 2 3# enumerate指定起始索引for index, item in enumerate(arr, start=1): print(index, item) # 1 1, 2 2, 3 3# while循环(和JS一样)i = 0while i < 5: print(i) i += 1# range(stop) - 从0到stop-1for i in range(5): print(i) # 0, 1, 2, 3, 4# range(start, stop) - 从start到stop-1for i in range(2, 5): print(i) # 2, 3, 4# range(start, stop, step) - 指定步长for i in range(0, 10, 2): print(i) # 0, 2, 4, 6, 8# 倒序for i in range(5, 0, -1): print(i) # 5, 4, 3, 2, 1# range是惰性的(不会立即生成所有数字)big_range = range(1000000) # 不占用太多内存print(list(range(5))) # 转换成列表:[0, 1, 2, 3, 4]// JavaScript - 遍历对象const user = {name: "张三", age: 25, city: "北京"};// 遍历键for (const key in user) {console.log(key);}// 遍历值for (const value ofObject.values(user)) {console.log(value);}// 遍历键值对for (const [key, value] ofObject.entries(user)) {console.log(key, value);}# Python - 遍历字典user = {"name": "张三", "age": 25, "city": "北京"}# 遍历键(默认)for key in user: print(key)# 明确遍历键for key in user.keys(): print(key)# 遍历值for value in user.values(): print(value)# 遍历键值对(推荐)for key, value in user.items(): print(f"{key}: {value}")// JavaScript - break和continuefor (let i = 0; i < 10; i++) {if (i === 3) continue; // 跳过3if (i === 7) break; // 到7就停止console.log(i); // 0, 1, 2, 4, 5, 6}# Python - break、continue和elsefor i in range(10):if i == 3:continue# 跳过3if i == 7:break# 到7就停止 print(i) # 0, 1, 2, 4, 5, 6# Python特有:for...else(循环正常结束时执行)for i in range(5):if i == 10: # 永远不会满足breakelse: print("循环正常结束") # 会执行# 实战:查找元素deffind_element(arr, target):for item in arr:if item == target: print(f"找到了: {item}")breakelse: print("没找到") # 只有没break时才执行// JavaScript - 嵌套循环for (let i = 1; i <= 3; i++) {for (let j = 1; j <= 3; j++) {console.log(`${i} x ${j} = ${i * j}`); }}// 生成二维数组const matrix = [];for (let i = 0; i < 3; i++) {const row = [];for (let j = 0; j < 3; j++) { row.push(i * 3 + j); } matrix.push(row);}# Python - 嵌套循环for i in range(1, 4):for j in range(1, 4): print(f"{i} x {j} = {i * j}")# 生成二维数组(列表推导式更简洁)# 传统方式matrix = []for i in range(3): row = []for j in range(3): row.append(i * 3 + j) matrix.append(row)# 列表推导式(一行搞定)matrix = [[i * 3 + j for j in range(3)] for i in range(3)]# [[0, 1, 2], [3, 4, 5], [6, 7, 8]]# 案例1:过滤和转换数据users = [ {"name": "张三", "age": 25, "active": True}, {"name": "李四", "age": 17, "active": False}, {"name": "王五", "age": 30, "active": True}]# 找出所有活跃的成年用户active_adults = []for user in users:if user["age"] >= 18and user["active"]: active_adults.append(user["name"])print(active_adults) # ['张三', '王五']# 案例2:统计分类scores = [85, 92, 78, 95, 88, 65, 90]grades = {"A": 0, "B": 0, "C": 0}for score in scores:if score >= 90: grades["A"] += 1elif score >= 80: grades["B"] += 1else: grades["C"] += 1print(grades) # {'A': 3, 'B': 3, 'C': 1}# 案例3:二维数组操作matrix = [ [1, 2, 3], [4, 5, 6], [7, 8, 9]]# 遍历所有元素for row in matrix:for num in row: print(num, end=" ") # 1 2 3 4 5 6 7 8 9 print() # 换行# 按列遍历(使用zip)for col in zip(*matrix): print(col) # (1, 4, 7), (2, 5, 8), (3, 6, 9)# 理解迭代器numbers = [1, 2, 3]# 获取迭代器iterator = iter(numbers)# 手动迭代print(next(iterator)) # 1print(next(iterator)) # 2print(next(iterator)) # 3# print(next(iterator)) # StopIteration异常# for循环的本质就是使用迭代器# 以下代码等价:for num in numbers: print(num)# 等价于:iterator = iter(numbers)whileTrue:try: num = next(iterator) print(num)except StopIteration:break# zip - 并行遍历多个序列names = ["张三", "李四", "王五"]ages = [25, 30, 28]cities = ["北京", "上海", "广州"]for name, age, city in zip(names, ages, cities): print(f"{name}, {age}岁, 来自{city}")# 转换成字典user_dict = dict(zip(names, ages))# {'张三': 25, '李四': 30, '王五': 28}# enumerate - 带索引遍历tasks = ["写代码", "测试", "部署"]for index, task in enumerate(tasks, start=1): print(f"{index}. {task}")# 1. 写代码# 2. 测试# 3. 部署# reversed - 反向遍历for num in reversed(range(5)): print(num) # 4, 3, 2, 1, 0# sorted - 排序后遍历numbers = [3, 1, 4, 1, 5]for num in sorted(numbers): print(num) # 1, 1, 3, 4, 5import time# 方式1:传统循环start = time.time()squares1 = []for i in range(1000000): squares1.append(i ** 2)print(f"循环耗时: {time.time() - start:.3f}秒")# 方式2:列表推导式(更快)start = time.time()squares2 = [i ** 2for i in range(1000000)]print(f"推导式耗时: {time.time() - start:.3f}秒")# 方式3:生成器(最省内存)start = time.time()squares3 = (i ** 2for i in range(1000000))# 只创建生成器,不计算值print(f"生成器耗时: {time.time() - start:.6f}秒")for(let i=0; i<n; i++) | for i in range(n) | |
for...of | for item in list | |
forEach((item, i)) | enumerate() | |
continue | continue | |
break | break | |
for...else | ||
zip() |
// JavaScriptconst integer = 42;const float = 3.14;const hex = 0xFF;const binary = 0b1010;# Pythoninteger = 42float_num = 3.14hex_num = 0xFFbinary = 0b1010# Python 特有:大整数支持big_number = 99999999999999999999999999999// JavaScriptconst isTrue = true;const isFalse = false;// 假值:false, 0, "", null, undefined, NaNif (!value) {console.log("假值");}# Pythonis_true = True# 注意:首字母大写!is_false = False# 假值:False, 0, "", None, [], {}ifnot value: print("假值")// JavaScriptconst arr = [1, 2, 3, 4, 5];// 常用方法arr.push(6); // 添加元素arr.pop(); // 删除最后一个arr.shift(); // 删除第一个arr.unshift(0); // 开头添加arr.slice(1, 3); // 切片arr.map(x => x * 2); // 映射arr.filter(x => x > 2); // 过滤arr.reduce((a, b) => a + b); // 归约# Pythonarr = [1, 2, 3, 4, 5]# 常用方法arr.append(6) # 添加元素arr.pop() # 删除最后一个arr.pop(0) # 删除第一个arr.insert(0, 0) # 指定位置插入arr[1:3] # 切片[x * 2for x in arr] # 列表推导式(映射)[x for x in arr if x > 2] # 列表推导式(过滤)sum(arr) # 求和# 列表推导式(Python 特色)squares = [x**2for x in range(10)] # [0, 1, 4, 9, 16, ...]evens = [x for x in range(10) if x % 2 == 0] # [0, 2, 4, 6, 8]// JavaScriptconst user = {name: "张三",age: 25,skills: ["React", "Vue"]};// 访问user.name; // "张三"user["age"]; // 25// 方法Object.keys(user); // ["name", "age", "skills"]Object.values(user); // ["张三", 25, [...]]# Pythonuser = {"name": "张三","age": 25,"skills": ["React", "Vue"]}# 访问user["name"] # "张三"user.get("age") # 25(推荐,不存在返回 None)# 方法user.keys() # dict_keys(['name', 'age', 'skills'])user.values() # dict_values([...])user.items() # dict_items([('name', '张三'), ...])# 字典推导式squares = {x: x**2for x in range(5)} # {0: 0, 1: 1, 2: 4, ...}// JavaScriptconstset = new Set([1, 2, 2, 3]); // Set {1, 2, 3}set.add(4);set.has(2); // trueset.delete(1);# Pythonmy_set = {1, 2, 2, 3} # {1, 2, 3}my_set.add(4)2in my_set # Truemy_set.remove(1)# 集合操作a = {1, 2, 3}b = {3, 4, 5}a | b # 并集 {1, 2, 3, 4, 5}a & b # 交集 {3}a - b # 差集 {1, 2}// JavaScriptlet value = null; // 空值let value2 = undefined; // 未定义# Pythonvalue = None# 唯一的空值(类似 null)# 检查if value isNone: print("空值")if value: # None 是假值 print("有值")// JavaScriptfunctionadd(a, b) {return a + b;}// 箭头函数const add = (a, b) => a + b;// 默认参数functiongreet(name = "Guest") {return`Hello, ${name}`;}# Pythondefadd(a, b):return a + b# 默认参数defgreet(name="Guest"):returnf"Hello, {name}"# Lambda(类似箭头函数)add = lambda a, b: a + b// JavaScriptfunctionprocess(required, optional = "default", ...rest) {console.log(required, optional, rest);}process(1, 2, 3, 4, 5); // 1 2 [3, 4, 5]# Pythondefprocess(required, optional="default", *args, **kwargs): print(required, optional, args, kwargs)process(1, 2, 3, 4, key="value") # 1 2 (3, 4) {'key': 'value'}# *args: 可变位置参数(元组)# **kwargs: 可变关键字参数(字典)// JavaScript (TypeScript)functionadd(a: number, b: number): number{return a + b;}# Pythondefadd(a: int, b: int) -> int:return a + b# 复杂类型from typing import List, Dict, Optionaldefprocess_users( users: List[Dict[str, str]]) -> Optional[str]:return users[0]["name"] if users elseNone// JavaScriptclassUser{constructor(name, age) {this.name = name;this.age = age; } greet() {return`Hello, I'm ${this.name}`; }static createGuest() {returnnew User("Guest", 0); }}const user = new User("张三", 25);# PythonclassUser:def__init__(self, name, age): self.name = name self.age = agedefgreet(self):returnf"Hello, I'm {self.name}" @staticmethoddefcreate_guest():return User("Guest", 0)user = User("张三", 25)// JavaScriptclassAdminextendsUser{constructor(name, age, role) {super(name, age);this.role = role; } manageUsers() {return"Managing users..."; }}# PythonclassAdmin(User):def__init__(self, name, age, role): super().__init__(name, age) self.role = roledefmanage_users(self):return"Managing users..."// JavaScriptclassUser{ #password; // 私有字段constructor(password) {this.#password = password; }}# PythonclassUser:def__init__(self, password): self.__password = password # 双下划线表示私有 self._internal = "internal"# 单下划线表示内部使用(约定)// JavaScriptfunctionfetchData() {returnnewPromise((resolve, reject) => { setTimeout(() => { resolve("Data"); }, 1000); });}fetchData() .then(data =>console.log(data)) .catch(err =>console.error(err));# Pythonimport asyncioasyncdeffetch_data():await asyncio.sleep(1)return"Data"# 运行asyncio.run(fetch_data())// JavaScriptasyncfunctiongetData() {try {const data1 = await fetch('/api/data1');const data2 = await fetch('/api/data2');return [data1, data2]; } catch (error) {console.error(error); }}# Pythonasyncdefget_data():try: data1 = await client.get('/api/data1') data2 = await client.get('/api/data2')return [data1, data2]except Exception as error: print(error)// JavaScriptasyncfunctiongetAll() {const [data1, data2] = awaitPromise.all([ fetch('/api/data1'), fetch('/api/data2') ]);}# Pythonasyncdefget_all(): data1, data2 = await asyncio.gather( client.get('/api/data1'), client.get('/api/data2') )// JavaScript// exportexportconst PI = 3.14;exportfunctionadd(a, b) { return a + b; }exportdefaultclassUser{}// importimport User, { PI, add } from'./user';import * as Utils from'./utils';# Python# 文件:user.pyPI = 3.14defadd(a, b):return a + bclassUser:pass# 文件:main.pyfrom user import PI, add, Userimport user # 导入整个模块from user import * # 导入所有(不推荐)# JavaScriptnpm install axiosnpm install --save-dev jest# Pythonpip install requestspip install pytest核心概念:Python用点号表示模块路径,对应文件系统的目录结构。
项目目录/├── app/│ ├── __init__.py ← 标记为Python包│ ├── routers/│ │ ├── __init__.py│ │ ├── user_router.py│ │ └── order_router.py│ └── services/│ ├── __init__.py│ └── user_service.py# 导入语法 → 文件路径对应关系from app.routers.user_router import router# └─┬┘ └──┬──┘ └────┬─────┘# 目录 目录 文件名# 对应文件:app/routers/user_router.pyfrom app.services.user_service import UserService# 对应文件:app/services/user_service.py__init__.py 的作用# __init__.py 是包的标识文件# 1. 标记目录为Python包app/├── __init__.py ← 有这个文件,app才是包└── module.py# 2. 简化导入(可选)# app/routers/__init__.pyfrom .user_router import router as user_routerfrom .order_router import router as order_router# 现在可以这样导入from app.routers import user_router, order_router# 而不是# from app.routers.user_router import router# from app.routers.order_router import router// JavaScript// 方式1:导入具体内容(推荐)import { Router, middleware } from'./express';// 方式2:导入默认导出import express from'express';// 方式3:导入整个模块import * as Express from'express';// 方式4:别名导入import { Router as ExpressRouter } from'./express';# Python# 方式1:导入具体内容(推荐)from fastapi import APIRouter, Depends# 方式2:导入整个模块import fastapirouter = fastapi.APIRouter()# 方式3:导入所有(不推荐)from fastapi import *# 方式4:别名导入from fastapi import APIRouter as Routerfrom datetime import datetime as dt# 方式5:相对导入(包内使用)from .user_router import router # 当前目录from ..services import UserService # 上级目录from ...utils import helper # 上上级目录# === 案例1:main.py 中的导入 ===# 文件:app/main.py(主应用)# 从项目模块导入from app.routers import user_router, order_router# └────┬─────┘ └─────┬──────┘# 包路径 模块名(文件名)# 等价于导入了两个文件:# - app/routers/user_router.py# - app/routers/order_router.py# 使用app.include_router(user_router.router) # 访问模块的router属性app.include_router(order_router.router) # 访问模块的router属性app.include_router(order_router.public_router) # 访问另一个router# === 案例2:理解FastAPI路由注册 ===# 文件:app/routers/user_router.pyfrom fastapi import APIRouterrouter = APIRouter( prefix="/users", # 路径前缀 tags=["用户管理"] # API文档标签)@router.get("/list") # 定义接口方法asyncdefget_user_list():return {"data": []}# 在 main.py 中注册from app.routers import user_routerapp.include_router(user_router.router)# 最终接口路径 = prefix + 方法路径# = /users + /list# = /users/list# === my_router.py 文件 ==="""路由模块示例"""# ✅ 公开API(推荐导入)router = APIRouter()logger = get_logger()PUBLIC_CONSTANT = 100defpublic_function():"""这是公开函数"""passclassPublicService:"""这是公开类"""pass# ⚠️ 内部使用(不建议导入)_internal_config = {"key": "value"}def_internal_helper():"""内部辅助函数,不要在外部使用"""pass# ❌ 私有(不应该导入)__private_data = "secret"def__private_method():"""私有方法"""pass# 📋 明确声明公开API(推荐)__all__ = ['router','logger','PUBLIC_CONSTANT','public_function','PublicService']# === 在其他文件中使用 ===# ✅ 推荐:只导入公开APIfrom my_router import router, PUBLIC_CONSTANT# ✅ 可以:导入整个模块import my_routermy_router.routermy_router.public_function()# ⚠️ 技术上可行,但不建议from my_router import _internal_helper # 违反约定# ✅ 遵循__all__from my_router import * # 只导入__all__中声明的内容# === 推荐的导入顺序(PEP 8规范) ===# 1. 标准库导入import osimport sysfrom datetime import datetimefrom typing import List, Dict, Optional# 2. 第三方库导入from fastapi import APIRouter, Dependsimport requestsfrom sqlalchemy import Column, String# 3. 本地模块导入from app.routers import user_routerfrom app.services.user_service import UserServicefrom app.utils.logger import get_logger# 每组之间空一行// JavaScript: package.json{"name": "my-project","version": "1.0.0","dependencies": {"axios": "^1.0.0", // ^ 表示兼容版本"express": "~4.18.0"// ~ 表示补丁版本 },"devDependencies": {"jest": "^29.0.0" }}# Python: requirements.txt(更简单)# 生产依赖requests==2.32.5# == 表示精确版本fastapi>=0.115.0# >= 表示最小版本sqlalchemy~=2.0.0# ~= 表示兼容版本# 开发依赖(通常单独一个文件)# requirements-dev.txtpytest>=7.0.0black==23.0.0# === 项目结构 ===my_project/├── app/│ ├── __init__.py│ ├── main.py│ ├── routers/│ │ ├── __init__.py│ │ └── api_router.py│ └── services/│ ├── __init__.py│ └── user_service.py└── utils/ ├── __init__.py └── helper.py# === app/routers/api_router.py ===from fastapi import APIRouterfrom ..services.user_service import UserService # 相对导入(上级目录)from ...utils.helper import format_date # 上上级目录router = APIRouter()user_service = UserService()@router.get("/users")defget_users(): users = user_service.get_all()return {"data": users}# === app/main.py ===from fastapi import FastAPIfrom .routers.api_router import router # 相对导入(当前包内)app = FastAPI()app.include_router(router)| 导出方式 | ||
| 私有约定 | ||
| 路径语法 | ./path/file | path.module |
| 批量导入 | import * | from module import * |
| 明确API | __all__ | |
| 包标识 | package.json | __init__.py |
// JavaScriptconst axios = require('axios');const response = await axios.get('https://api.example.com/data');const data = response.data;# Pythonimport requestsresponse = requests.get('https://api.example.com/data')data = response.json()# 异步版本import httpxasyncdeffetch():asyncwith httpx.AsyncClient() as client: response = await client.get('https://api.example.com/data')return response.json()// JavaScriptconst obj = { name: "张三" };const json = JSON.stringify(obj);const parsed = JSON.parse(json);# Pythonimport jsonobj = {"name": "张三"}json_str = json.dumps(obj)parsed = json.loads(json_str)// JavaScriptconst now = newDate();const timestamp = Date.now();const formatted = now.toISOString();# Pythonfrom datetime import datetimenow = datetime.now()timestamp = datetime.timestamp(now)formatted = now.isoformat()# 日期计算from datetime import timedeltatomorrow = now + timedelta(days=1)// JavaScript (Node.js)const fs = require('fs');// 读文件const content = fs.readFileSync('file.txt', 'utf8');// 写文件fs.writeFileSync('file.txt', 'Hello');# Python# 读文件with open('file.txt', 'r', encoding='utf-8') as f: content = f.read()# 写文件with open('file.txt', 'w', encoding='utf-8') as f: f.write('Hello')# with 语句自动关闭文件(类似 try-finally)# Python 用缩进表示代码块(没有大括号)ifTrue: print("缩进4个空格")ifTrue: print("缩进8个空格")# ❌ 错误:缩进不一致ifTrue: print("2个空格") print("4个空格") # 报错!// JavaScriptconst userName = "张三"; // 驼峰命名functiongetUserName() {} // 驼峰命名classUserManager{} // 大驼峰# Pythonuser_name = "张三"# 下划线命名defget_user_name():# 下划线命名passclassUserManager:# 大驼峰pass# 常量MAX_SIZE = 100# 全大写// JavaScriptif (value) {} // 空字符串、0、null、undefined 都是假// Pythonif value: // None、0、""、[]、{}、False 都是假// JavaScripta === b // 严格相等a == b // 宽松相等(类型转换)# Pythona == b # 相等(值比较)a is b # 同一对象(引用比较)# 例子a = [1, 2]b = [1, 2]a == b # True(值相同)a is b # False(不是同一对象)// JavaScript[1, 2, 3].map(x => x * 2) // [2, 4, 6]# Python 方案1:列表推导式(推荐)[x * 2for x in [1, 2, 3]]# 方案2:map + lambdalist(map(lambda x: x * 2, [1, 2, 3]))# 方案3:自己实现defmy_map(func, arr): result = []for item in arr: result.append(func(item))return resultmy_map(lambda x: x * 2, [1, 2, 3])// JavaScriptfunctiondebounce(func, delay) {let timer;returnfunction(...args) { clearTimeout(timer); timer = setTimeout(() => func(...args), delay); };}# Pythonimport timefrom threading import Timerdefdebounce(func, delay): timer = Nonedefwrapper(*args, **kwargs):nonlocal timerif timer: timer.cancel() timer = Timer(delay, func, args, kwargs) timer.start()return wrapper// JavaScriptconst deepClone = (obj) =>JSON.parse(JSON.stringify(obj));# Pythonimport copy# 方法1:内置函数deep_clone = copy.deepcopy(obj)# 方法2:JSON(和 JS 一样)import jsondeep_clone = json.loads(json.dumps(obj))console.log() | print() | |
arr.length | len(arr) | |
typeof x | type(x) | |
String(x) | str(x) | |
Number(x) | int(x)float(x) | |
Math.floor() | int() | |
Math.pow(2, 3) | 2 ** 3 | |
5 % 2 | 5 % 2 | |
&& | and | |
|| | or | |
! | not | |
=== | == | |
!== | != | |
arr.includes(x) | x in arr |
核心概念:APIRouter是FastAPI的路由分组器,类似Express的Router或React Router的路由配置。
// Express.js - 你可能见过的后端路由const express = require('express');const router = express.Router();// 路由前缀router.use('/api/users');// 定义接口router.get('/', (req, res) => { res.json({ users: [] });});router.post('/', (req, res) => { res.json({ message: "Created" });});// 注册到主应用app.use(router);// 最终路径:/api/users/# FastAPI - Python后端路由from fastapi import APIRouter# 创建路由器(指定前缀和标签)router = APIRouter( prefix="/api/users", # 路由前缀 tags=["用户管理"] # Swagger文档分类标签)# 定义接口@router.get("/")asyncdefget_users():return {"users": []}@router.post("/")asyncdefcreate_user(user: UserCreate):return {"message": "Created"}# 注册到主应用(在app.py中)app.include_router(router)# 最终路径:/api/users/完整URL = 应用前缀 + Router前缀 + 方法路径示例:= (可选) + /api/users + /list= /api/users/list# === main.py - 主应用 ===from fastapi import FastAPIfrom routers import user_router, product_routerapp = FastAPI()# 场景1:直接注册(无额外前缀)app.include_router(user_router.router)# user_router的接口:/api/users/xxx# 场景2:添加统一前缀app.include_router( product_router.router, prefix="/v1"# 添加版本前缀)# product_router的接口:/v1/api/products/xxx# === user_router.py - 用户路由 ===router = APIRouter( prefix="/api/users", # Router前缀 tags=["用户管理"])@router.get("/list") # 方法路径asyncdefget_user_list():return {"users": []}# 完整路径:/api/users/list@router.get("/{user_id}") # 路径参数asyncdefget_user(user_id: str):return {"user_id": user_id}# 完整路径:/api/users/123# 访问:GET /api/users/123# === product_router.py - 产品路由 ===router = APIRouter( prefix="/api/products", tags=["产品管理"])@router.get("/")asyncdefget_products():return {"products": []}# 注册时添加了/v1前缀# 完整路径:/v1/api/products/# === message_router.py ===from fastapi import APIRouter, Depends# Router 1:需要认证的接口auth_router = APIRouter( prefix="/api/private", tags=["私有接口"])@auth_router.post("/message")asyncdefprivate_message( content: str, user_id: str = Depends(get_current_user)# 需要登录):return {"message": f"用户{user_id}说:{content}"}# 完整路径:/api/private/message# 访问时需要:Authorization: Bearer <token># Router 2:公开接口(不需要认证)public_router = APIRouter( prefix="/api/public", tags=["公开接口"])@public_router.post("/message")asyncdefpublic_message(content: str):return {"message": f"访客说:{content}"}# 完整路径:/api/public/message# 访问时不需要token# === main.py - 主应用 ===app = FastAPI()app.include_router(auth_router) # 注册认证路由app.include_router(public_router) # 注册公开路由# 现在有两个消息接口:# POST /api/private/message - 需要登录# POST /api/public/message - 不需要登录# 路径参数(Path Parameter)- 类似RESTful风格@router.get("/users/{user_id}")asyncdefget_user(user_id: str):return {"user_id": user_id}# 访问:GET /users/123# user_id = "123"# 查询参数(Query Parameter)@router.get("/users")asyncdefsearch_users( name: str = None, # 可选参数 age: int = None, limit: int = 10# 默认值):return {"name": name, "age": age}# 访问:GET /users?name=张三&age=25&limit=20# 请求体(Request Body)from pydantic import BaseModelclassCreateUserRequest(BaseModel): name: str email: str age: int@router.post("/users")asyncdefcreate_user(user: CreateUserRequest):return {"message": f"创建用户: {user.name}"}# 访问:POST /users# Body: {"name": "张三", "email": "...", "age": 25}# 定义多个路由组user_router = APIRouter(prefix="/users", tags=["用户管理"])product_router = APIRouter(prefix="/products", tags=["产品管理"])order_router = APIRouter(prefix="/orders", tags=["订单管理"])# 在Swagger文档(/docs)中,接口会按标签分组显示:# 📁 用户管理# - GET /users# - POST /users# - DELETE /users/{id}# 📁 产品管理# - GET /products# - POST /products# 📁 订单管理# - GET /orders# - POST /orders// 前端代码// 调用接口1:公开消息(不需要token)asyncfunctionpublicMessage(content) {const response = await fetch('/api/public/message', {method: 'POST',headers: {'Content-Type': 'application/json' },body: JSON.stringify({ content }) });return response.json();}// 调用接口2:私有消息(需要token)asyncfunctionprivateMessage(content, token) {const response = await fetch('/api/private/message', {method: 'POST',headers: {'Content-Type': 'application/json','Authorization': `Bearer ${token}`// 携带token },body: JSON.stringify({ content }) });return response.json();}# === user_router.py - 用户管理路由 ===from fastapi import APIRouter, HTTPException, Queryfrom pydantic import BaseModelfrom typing import List, Optional# 创建路由器router = APIRouter( prefix="/api/users", tags=["用户管理"], responses={404: {"description": "用户不存在"}})# 请求/响应模型classUser(BaseModel): id: str name: str email: str age: intclassCreateUserRequest(BaseModel): name: str email: str age: int# 模拟数据库USERS_DB = []# 接口1:获取用户列表@router.get("/", response_model=List[User])asyncdefget_users( skip: int = Query(0, ge=0, description="跳过数量"), limit: int = Query(10, ge=1, le=100, description="每页数量")):""" 获取用户列表 - skip: 跳过的数量(分页用) - limit: 返回的数量(最多100) """return USERS_DB[skip:skip+limit]# 接口2:获取单个用户@router.get("/{user_id}", response_model=User)asyncdefget_user(user_id: str):"""根据ID获取用户""" user = next((u for u in USERS_DB if u["id"] == user_id), None)ifnot user:raise HTTPException(status_code=404, detail="用户不存在")return user# 接口3:创建用户@router.post("/", response_model=User)asyncdefcreate_user(user: CreateUserRequest):"""创建新用户""" new_user = {"id": str(len(USERS_DB) + 1), **user.dict() } USERS_DB.append(new_user)return new_user# 接口4:删除用户@router.delete("/{user_id}")asyncdefdelete_user(user_id: str):"""删除用户"""global USERS_DB USERS_DB = [u for u in USERS_DB if u["id"] != user_id]return {"message": "删除成功"}# === 在 app.py 中注册 ===app.include_router(router)# === 可访问的接口 ===# GET /api/users/ - 获取列表# GET /api/users/123 - 获取单个# POST /api/users/ - 创建# DELETE /api/users/123 - 删除| 路由分组 | express.Router() | APIRouter() |
| 路径前缀 | router.use('/prefix') | prefix="/prefix" |
| 文档标签 | tags=["标签"] | |
| 导入模块 | import router from './file' | from path import router |
| 模块内容 | ||
| 私有约定 |
核心概念:Python最优雅的特性之一,可以用一行代码完成复杂的列表操作。
// JavaScript - 传统方式const numbers = [1, 2, 3, 4, 5];// 平方const squares = numbers.map(x => x ** 2);// 筛选偶数const evens = numbers.filter(x => x % 2 === 0);// 筛选+转换const doubledEvens = numbers .filter(x => x % 2 === 0) .map(x => x * 2);# Python - 列表推导式numbers = [1, 2, 3, 4, 5]# 平方(基本语法:[表达式 for 变量 in 可迭代对象])squares = [x ** 2for x in numbers] # [1, 4, 9, 16, 25]# 筛选偶数(带条件:[表达式 for 变量 in 可迭代对象 if 条件])evens = [x for x in numbers if x % 2 == 0] # [2, 4]# 筛选+转换(一行搞定)doubled_evens = [x * 2for x in numbers if x % 2 == 0] # [4, 8]# 嵌套循环matrix = [[1, 2], [3, 4], [5, 6]]flat = [num for row in matrix for num in row] # [1, 2, 3, 4, 5, 6]# 条件表达式labels = ["偶数"if x % 2 == 0else"奇数"for x in numbers]# ['奇数', '偶数', '奇数', '偶数', '奇数']实战案例:处理API数据
# 从API返回的用户列表中提取成年人的名字users = [ {"name": "张三", "age": 25}, {"name": "李四", "age": 17}, {"name": "王五", "age": 30}]# 传统方式adult_names = []for user in users:if user["age"] >= 18: adult_names.append(user["name"])# 列表推导式(一行搞定)adult_names = [user["name"] for user in users if user["age"] >= 18]# ['张三', '王五']// JavaScriptconst numbers = [1, 2, 3, 4, 5];// 创建字典const squares = Object.fromEntries( numbers.map(x => [x, x ** 2]));// {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}// 去重const unique = [...new Set([1, 2, 2, 3, 3, 3])];# Python - 字典推导式numbers = [1, 2, 3, 4, 5]# 字典推导式squares = {x: x ** 2for x in numbers}# {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}# 筛选条件even_squares = {x: x ** 2for x in numbers if x % 2 == 0}# {2: 4, 4: 16}# 集合推导式unique = {x % 3for x in range(10)} # {0, 1, 2}# 实战:转换键值对scores = {"语文": 85, "数学": 90, "英语": 88}grades = {subject: "A"if score >= 90else"B"for subject, score in scores.items()}# {'语文': 'B', '数学': 'A', '英语': 'B'}核心概念:节省内存的迭代器,只在需要时生成值。
// JavaScript - 生成器function* numberGenerator() {for (let i = 0; i < 5; i++) {yield i; }}const gen = numberGenerator();console.log(gen.next().value); // 0console.log(gen.next().value); // 1# Python - 生成器(更常用)# 方式1:生成器函数defnumber_generator():for i in range(5):yield igen = number_generator()print(next(gen)) # 0print(next(gen)) # 1# 方式2:生成器表达式(类似列表推导式,但用圆括号)squares = (x ** 2for x in range(1000000)) # 不占用太多内存print(next(squares)) # 0print(next(squares)) # 1# 实战:读取大文件defread_large_file(file_path):"""逐行读取大文件,不会一次性加载到内存"""with open(file_path) as f:for line in f:yield line.strip()# 使用for line in read_large_file('huge_file.txt'): process(line) # 每次只处理一行核心概念:修改函数行为的高阶函数,类似JavaScript的高阶组件。
// JavaScript - 高阶函数functionlogTime(func) {returnfunction(...args) {const start = Date.now();const result = func(...args);console.log(`执行时间: ${Date.now() - start}ms`);return result; };}// 使用const slowFunction = logTime(function(n) {// 耗时操作return n * 2;});# Python - 装饰器(语法糖)import timedeflog_time(func):"""装饰器:记录函数执行时间"""defwrapper(*args, **kwargs): start = time.time() result = func(*args, **kwargs) print(f"执行时间: {time.time() - start:.2f}秒")return resultreturn wrapper# 使用装饰器(@语法)@log_timedefslow_function(n): time.sleep(1)return n * 2# 调用时自动记录时间result = slow_function(5) # 打印: 执行时间: 1.00秒# 等价于slow_function = log_time(slow_function)实战案例:多个装饰器
defrequire_auth(func):"""装饰器:检查用户是否登录"""defwrapper(*args, **kwargs):ifnot is_logged_in():raise Exception("请先登录")return func(*args, **kwargs)return wrapperdeflog_action(func):"""装饰器:记录操作日志"""defwrapper(*args, **kwargs): print(f"调用函数: {func.__name__}") result = func(*args, **kwargs) print(f"返回结果: {result}")return resultreturn wrapper# 多个装饰器(从下往上执行)@log_action@require_authdefdelete_user(user_id):returnf"删除用户 {user_id}"# 等价于# delete_user = log_action(require_auth(delete_user))核心概念:自动管理资源(如文件、数据库连接),确保正确清理。
// JavaScript - 手动管理资源const fs = require('fs');// 必须手动关闭const file = fs.openSync('file.txt', 'r');try {const content = fs.readFileSync(file, 'utf8');console.log(content);} finally { fs.closeSync(file); // 确保关闭}# Python - with语句自动管理# 文件操作(自动关闭)with open('file.txt', 'r', encoding='utf-8') as f: content = f.read() print(content)# 离开with块后,文件自动关闭# 多个资源with open('input.txt') as infile, open('output.txt', 'w') as outfile: content = infile.read() outfile.write(content.upper())# 数据库连接示例with get_db_connection() as conn: cursor = conn.cursor() cursor.execute("SELECT * FROM users") results = cursor.fetchall()# 连接自动关闭# 自定义上下文管理器classTimer:def__enter__(self): self.start = time.time()return selfdef__exit__(self, *args): print(f"耗时: {time.time() - self.start:.2f}秒")# 使用with Timer(): time.sleep(1) print("执行任务")# 输出: 耗时: 1.00秒"""需求:从API获取用户数据,筛选成年用户,按年龄排序,生成报告"""import requestsfrom typing import List, Dictfrom datetime import datetimeclassUserDataProcessor:def__init__(self, api_url: str): self.api_url = api_urldeffetch_users(self) -> List[Dict]:"""获取用户数据""" response = requests.get(self.api_url)return response.json()deffilter_adults(self, users: List[Dict]) -> List[Dict]:"""筛选成年用户(使用列表推导式)"""return [user for user in users if user.get('age', 0) >= 18]defsort_by_age(self, users: List[Dict]) -> List[Dict]:"""按年龄排序"""return sorted(users, key=lambda u: u['age'], reverse=True)defgenerate_report(self, users: List[Dict]) -> str:"""生成报告""" report = ["=" * 50,f"用户报告 - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}","=" * 50,f"总人数: {len(users)}","" ]for i, user in enumerate(users, 1): report.append(f"{i}. {user['name']} - {user['age']}岁 "f"({user.get('email', '无邮箱')})" )return"\n".join(report)defprocess(self):"""主流程""" print("正在获取数据...") users = self.fetch_users() print("正在筛选成年用户...") adults = self.filter_adults(users) print("正在排序...") sorted_users = self.sort_by_age(adults) print("正在生成报告...") report = self.generate_report(sorted_users)# 保存报告with open('user_report.txt', 'w', encoding='utf-8') as f: f.write(report) print("报告已保存到 user_report.txt")return report# 使用processor = UserDataProcessor('https://api.example.com/users')report = processor.process()print(report)"""需求:读取YAML配置文件,支持环境变量替换,提供便捷访问"""import osimport yamlfrom typing import AnyclassConfigManager:def__init__(self, config_file: str, env: str = 'dev'): self.config_file = config_file self.env = env self.config = self._load_config()def_load_config(self) -> dict:"""加载配置文件"""with open(self.config_file, 'r', encoding='utf-8') as f: config = yaml.safe_load(f)# 替换环境变量return self._replace_env_vars(config)def_replace_env_vars(self, obj: Any) -> Any:"""递归替换环境变量"""if isinstance(obj, dict):return {k: self._replace_env_vars(v) for k, v in obj.items()}elif isinstance(obj, list):return [self._replace_env_vars(item) for item in obj]elif isinstance(obj, str) and obj.startswith('${') and obj.endswith('}'):# ${ENV_VAR} 格式 var_name = obj[2:-1]return os.getenv(var_name, obj)return objdefget(self, key: str, default: Any = None) -> Any:"""获取配置值(支持点号分隔的路径)""" keys = key.split('.') value = self.configfor k in keys:if isinstance(value, dict): value = value.get(k)if value isNone:return defaultelse:return defaultreturn valuedef__getitem__(self, key: str) -> Any:"""支持字典式访问"""return self.get(key)# 使用config = ConfigManager('config.yaml')# 获取配置db_host = config.get('database.host', 'localhost')api_key = config['api.key']print(f"数据库地址: {db_host}")print(f"API密钥: {api_key}")# ❌ 错误示例defadd_item(item, items=[]): items.append(item)return items# 问题:默认参数只创建一次print(add_item(1)) # [1]print(add_item(2)) # [1, 2] - 不是 [2]!# ✅ 正确做法defadd_item(item, items=None):if items isNone: items = [] items.append(item)return itemsprint(add_item(1)) # [1]print(add_item(2)) # [2] - 正确# ❌ 错误示例functions = []for i in range(3): functions.append(lambda: i)# 所有函数都返回2(最后的i值)for func in functions: print(func()) # 2, 2, 2# ✅ 正确做法1:使用默认参数functions = []for i in range(3): functions.append(lambda x=i: x)for func in functions: print(func()) # 0, 1, 2# ✅ 正确做法2:使用列表推导式functions = [lambda x=i: x for i in range(3)]import copy# 浅拷贝original = [[1, 2], [3, 4]]shallow = original.copy() # 或 original[:]shallow[0][0] = 999print(original) # [[999, 2], [3, 4]] - 被修改了!# 深拷贝original = [[1, 2], [3, 4]]deep = copy.deepcopy(original)deep[0][0] = 999print(original) # [[1, 2], [3, 4]] - 没被修改立即实践:
# 练习1:写一个函数,统计字符串中每个字符出现的次数defcount_chars(text):return {char: text.count(char) for char in set(text)}# 练习2:写一个装饰器,让函数重试3次defretry(times=3):defdecorator(func):defwrapper(*args, **kwargs):for i in range(times):try:return func(*args, **kwargs)except Exception as e:if i == times - 1:raise print(f"重试 {i+1}/{times}")return wrapperreturn decorator# 练习3:用with语句实现一个计时器classTimer:def__enter__(self):import time self.start = time.time()return selfdef__exit__(self, *args): print(f"耗时: {time.time() - self.start:.2f}秒")记住:编程语言只是工具,重要的是解决问题的思维方式!