第2章: 语法基础 — 从"看起来一样"到"完全不同"
Java/Kotlin 开发者看 Python 代码,第一反应往往是"这不就是去掉分号和类型声明吗?"。
错。大量语法元素看起来像但行为完全不同。本章逐个拆解,每个知识点都给出 JVM 对比、Python demo、核心差异和陷阱。
2.1 缩进即语法: 没有大括号
Java/Kotlin 对比
public class Example {
public void greet(String name) {
if (name != null) {
System.out.println("Hello, " + name);
if (name.length() > 5) {
System.out.println("Long name!");
}
} else {
System.out.println("Hello, stranger");
}
}
}
fun greet(name: String?) {
if (name != null) {
println("Hello, $name")
if (name.length > 5) {
println("Long name!")
}
} else {
println("Hello, stranger")
}
}
Python 实现
def greet(name):
if name is not None:
print(f"Hello, {name}")
if len(name) > 5:
print("Long name!")
else:
print("Hello, stranger")
long_string = "This is a very long string " \
"that spans multiple lines"
result = (1 + 2 + 3 +
4 + 5 + 6)
names = [
"Alice",
"Bob",
"Charlie",
]
data = {
"name": "Alice",
"age": 30,
"email": "alice@example.com",
}
result = some_function(
arg1="value1",
arg2="value2",
arg3="value3",
)
class EmptyClass:
pass
def todo_function():
pass
if condition:
pass
核心差异
| 维度 | Java/Kotlin | Python |
|---|
| 代码块界定 | {} | 缩进(4空格) |
| 缩进作用 | 纯风格 | 语法的一部分 |
| 空代码块 | {} | pass |
| 多行语句 | 自动(; 分隔) | \ 或括号隐式续行 |
| 混用 Tab/空格 | 无影响 | Python 3 报错 |
常见陷阱
x = 10
if x > 5: print("big")
else: print("small")
何时使用
- 缩进: 永远用 4 空格,配置编辑器 Tab 键转 4 空格
- 括号续行: 列表、字典、函数调用、长表达式——优先用括号续行
- 反斜杠: 只在没有括号可用时(如
assert 语句)才用
- pass: 定义接口、抽象基类、TODO 占位
2.2 变量与赋值: 名字绑定 vs 变量声明
Java/Kotlin 对比
String name = "Alice";
int count = 42;
final String GREETING = "Hello";
int a = 1, b = 2, c = 3;
val name = "Alice"
var count = 42
val a = 1; val b = 2; val c = 3
Python 实现
name = "Alice"
name = 42
name = [1, 2, 3]
a = b = c = 0
print(a, b, c)
a = b = c = []
a.append(1)
print(b)
x, y, z = 1, 2, 3
print(x, y, z)
x, y = y, x
print(x, y)
first, *rest = [1, 2, 3, 4, 5]
print(first)
print(rest)
head, *middle, tail = [1, 2, 3, 4, 5]
print(head)
print(middle)
print(tail)
data = {"name": "Alice", "age": 30}
for key, value in data.items():
print(f"{key}: {value}")
count = 0
count += 1
count *= 2
count //= 3
count **= 2
MAX_RETRIES = 3
DEFAULT_TIMEOUT = 30
API_BASE_URL = "https://api.example.com"
MAX_RETRIES = 5
核心差异
| 维度 | Java/Kotlin | Python |
|---|
| 赋值语义 | 内存分配 + 类型绑定 | 名字绑定(标签贴到对象上) |
| 类型约束 | 编译器强制 | 无(运行时检查) |
| 重新赋值不同类型 | 编译错误 | 完全合法 |
| 多重赋值 | 不支持(或有限解构) | 链式赋值、元组解包、扩展解包 |
| 变量交换 | 需要临时变量 | a, b = b, a |
| 常量 | final / val + 编译器强制 | 全大写约定(无强制) |
常见陷阱
a = b = []
a.append(1)
print(b)
a = []
b = []
original = [1, 2, 3]
copy = original
copy.append(4)
print(original)
copy = original.copy()
copy = original[:]
copy = list(original)
x, y, *rest = [1, 2, 3, 4, 5]
a = [1, 2, 3]
b = a
a += [4]
print(b)
a = 10
b = a
a += 1
print(b)
何时使用
- 解包赋值: 函数返回多个值、遍历键值对、交换变量
- 扩展解包
*: 只关心首尾元素、跳过中间元素
- 链式赋值: 仅用于不可变对象(如
a = b = c = 0)
- 全大写常量: 模块级别的配置值、魔法数字
2.3 基本数据类型
Java/Kotlin 对比
int x = 42;
Integer boxed = 42;
double pi = 3.14;
boolean flag = true;
String name = "Alice";
String nullStr = null;
if (x instanceof Integer) { }
if (str instanceof String) { }
int y = (int) 3.14;
String s = String.valueOf(42);
val x: Int = 42
val pi: Double = 3.14
val flag: Boolean = true
val name: String = "Alice"
val nullStr: String? = null
if (x is Int) { }
if (x is Number) { }
val y: Int = 3.14.toInt()
val s: String = 42.toString()
Python 实现
name = None
print(name)
print(type(None))
x = None
print(x is None)
print(x == None)
def no_return():
pass
result = no_return()
print(result)
big = 2 ** 100
print(big)
print(type(big))
print(big.bit_length())
binary = 0b1010
octal = 0o755
hex_num = 0xFF
million = 1_000_000
print(million)
pi = 3.14159
print(type(pi))
print(0.1 + 0.2)
print(0.1 + 0.2 == 0.3)
import math
print(math.isclose(0.1 + 0.2, 0.3))
print(float('inf'))
print(float('-inf'))
print(float('nan'))
print(float('nan') == float('nan'))
print(math.isnan(float('nan')))
print(type(True))
print(isinstance(True, int))
print(True + 1)
print(False + 1)
print(sum([True, False, True]))
name = "Alice"
print(type(name))
data = b"hello"
print(type(data))
print(data[0])
mutable = bytearray(b"hello")
mutable[0] = 72
print(mutable)
print(type(42))
print(type(True))
print(isinstance(42, int))
print(isinstance(True, int))
print(isinstance(True, bool))
def process(value):
if isinstance(value, (int, float)):
print(f"数值: {value}")
elif isinstance(value, str):
print(f"字符串: {value}")
else:
print(f"其他类型: {type(value)}")
process(42)
process(3.14)
process("hello")
process([1, 2])
核心差异
| 维度 | Java/Kotlin | Python |
|---|
| 整数范围 | int 32位, long 64位 | 无上限 |
| 整数溢出 | 溢出(环绕) | 不会溢出 |
| null | null | None(单例) |
| 布尔类型 | 独立类型 | int 的子类 |
| 浮点精度 | 同 IEEE 754 | 同 IEEE 754 |
| 类型检查 | instanceof / is | isinstance()(推荐) |
| 字节类型 | byte[] | bytes(不可变)、bytearray(可变) |
常见陷阱
print(True == 1)
print(False == 0)
print([True, False] == [1, 0])
d = {}
d[True] = "yes"
d[1] = "one"
print(d)
print(len(d))
x = None
print(x is None)
print(x == None)
print(type(True) == int)
print(isinstance(True, int))
print(0.1 + 0.2 == 0.3)
何时使用
isinstance(): 运行时类型检查(替代 Java 的 instanceof)
type(): 调试、日志输出(不要用于类型判断)
None: 函数默认返回值、可选参数的默认值
bytes: 网络传输、文件读写(二进制模式)
math.isclose(): 比较浮点数
2.4 字符串
Java/Kotlin 对比
String name = "Alice";
char ch = 'A';
String greeting = "Hello, " + name + "!";
String msg = STR."Hello, \{name}!";
name.length();
name.toUpperCase();
name.substring(0, 3);
name.split(",");
String.join("-", parts);
String text = """
Hello
World
""";
val name = "Alice"
val ch = 'A'
val greeting = "Hello, $name!"
val info = "Age: ${person.age}"
val text = """
Hello
World
""".trimIndent()
val regex = Regex("\\d+")
val raw = """\d+"""
Python 实现
s1 = 'hello'
s2 = "hello"
print(s1 == s2)
quote = 'He said "hello"'
quote2 = "He said 'hello'"
poem = """
Roses are red,
Violets are blue,
Python is awesome,
And so are you.
"""
print(poem)
import textwrap
poem = textwrap.dedent("""\
Roses are red,
Violets are blue,
Python is awesome.
""")
name = "Alice"
age = 30
print(f"Hello, {name}!")
print(f"Age: {age}")
print(f"Next year: {age + 1}")
print(f"Name upper: {name.upper()}")
pi = 3.14159
print(f"Pi: {pi:.2f}")
print(f"Pi: {pi:.4f}")
print(f"{'hello':>20}")
print(f"{'hello':<20}")
print(f"{'hello':^20}")
print(f"{1000000:,}")
print(f"{255:#x}")
print(f"{255:#b}")
x = 42
y = 3.14
print(f"{x = }")
print(f"{y = :.2f}")
print(f"{x * 2 = }")
newline = '\n'
print(f"{'hello' + newline + 'world'}")
s = " Hello, World! "
print(s.strip())
print(s.lstrip())
print(s.rstrip())
print("hello".upper())
print("HELLO".lower())
print("hello world".title())
print("hello world".capitalize())
print("hello".find("ll"))
print("hello".index("ll"))
print("hello".startswith("he"))
print("hello".endswith("lo"))
print("hello".count("l"))
print("hello world".replace("world", "Python"))
print("aaa".replace("a", "b", 2))
print("a,b,c".split(","))
print("a b c".split())
print("a\nb\nc".splitlines())
words = ["Hello", "World"]
print(" ".join(words))
print("-".join(words))
print("".join(words))
print("123".isdigit())
print("abc".isalpha())
print("abc123".isalnum())
print(" ".isspace())
print("Hello".isupper())
print("HELLO".isupper())
print("hello".center(20, "="))
print("hello".ljust(20, "-"))
print("hello".rjust(20, "-"))
import re
pattern = r"\d+"
print(re.findall(pattern, "abc123def456"))
path = r"C:\Users\name\file.txt"
print(path)
text = "hello"
encoded = text.encode("utf-8")
print(encoded)
print(type(encoded))
decoded = encoded.decode("utf-8")
print(decoded)
b_data = "你好".encode("utf-8")
old_style = "Hello, {}!".format("Alice")
print(old_style)
very_old = "Hello, %s! Age: %d" % ("Alice", 30)
print(very_old)
核心差异
| 维度 | Java | Kotlin | Python |
|---|
| 字符串引号 | 仅双引号 | 仅双引号 | 单/双/三引号均可 |
| 字符类型 | char(单引号) | Char(单引号) | 无字符类型,长度为1的字符串 |
| 字符串插值 | STR."..." (15+) | "...$var..." | f"...{expr}" |
| 多行字符串 | """...""" (15+) | """...""" | """...""" |
| 原始字符串 | 无 | 无 | r"..." |
| null 字符串 | null | String? | None(不是字符串) |
| 字符串拼接 | +(编译器优化) | +(StringBuilder) | + 或 f"" 或 join |
| 字符串不可变 | 是 | 是 | 是 |
常见陷阱
parts = []
for i in range(1000):
parts.append(str(i))
result = "".join(parts)
name = "Alice"
greeting = f"Hello, {name}"
name = "Bob"
print(greeting)
text = "hello" + b"world".decode()
data = b"hello" + "world".encode()
print("ell" in "hello")
何时使用
- f-string: 所有字符串插值场景(Python 3.6+,推荐)
- 三引号: 多行文本、SQL 查询、正则表达式
- r 前缀: 正则表达式、Windows 路径
join(): 拼接多个字符串(性能最优)
encode()/decode(): 网络传输、文件 I/O(二进制模式)
2.5 运算符
Java/Kotlin 对比
int a = 7 / 2;
double b = 7.0 / 2;
int c = 7 % 2;
int d = (int) Math.pow(2, 10);
String s1 = new String("hello");
String s2 = new String("hello");
s1 == s2;
s1.equals(s2);
boolean x = true && false;
boolean y = true || false;
boolean z = !true;
int bits = 0b1010 & 0b1100;
val a = 7 / 2
val b = 7.0 / 2
val c = 7 % 2
val d = 2.0.pow(10)
val s1 = "hello"
val s2 = "hello"
s1 == s2
s1 === s2
val range = 1..10
1 in range
Python 实现
print(7 / 2)
print(7.0 / 2)
print(7 // 2)
print(-7 // 2)
print(7 % 2)
print(-7 % 2)
print(2 ** 10)
print(2 ** 0.5)
print(2 ** 100)
print(1 == 1)
print("hello" == "hello")
print([1, 2] == [1, 2])
print([1, 2] == [1, 3])
a = [1, 2]
b = [1, 2]
print(a == b)
print(a is b)
c = a
print(a is c)
x = 256
y = 256
print(x is y)
x = 257
y = 257
print(x is y)
print(None is None)
x = 5
print(1 < x < 10)
print(1 < x > 3)
print(0 < x != 5)
print(True and False)
print(True or False)
print(not True)
print(1 and 2)
print(0 and 2)
print(1 or 2)
print(0 or 2)
print("" or "default")
print(None or "fallback")
name = None
display_name = name or "Anonymous"
print(3 in [1, 2, 3])
print(4 not in [1, 2, 3])
print("key" in {"key": "val"})
print("hello" in "hello world")
a = [1, 2]
b = [1, 2]
print(a is not b)
import re
text = "abc123def456"
pattern = re.compile(r"\d+")
match = pattern.search(text)
while match:
print(match.group())
match = pattern.search(text, match.end())
text = "abc123def456"
pos = 0
while (match := pattern.search(text, pos)):
print(match.group())
pos = match.end()
data = [1, 2, 3, 4, 5, 6]
results = [y for x in data if (y := x ** 2) > 10]
print(results)
if (n := len(data)) > 5:
print(f"Too many items: {n}")
print(0b1010 & 0b1100)
print(0b1010 | 0b1100)
print(0b1010 ^ 0b1100)
print(~0b1010)
print(0b1010 << 2)
print(0b1010 >> 2)
核心差异
| 运算符 | Java/Kotlin | Python | 差异 |
|---|
/ | 整数除法(截断) | 浮点除法 | 7/2 → Java: 3, Python: 3.5 |
// | 不存在 | 整除(向下取整) | -7//2 → Java: -3, Python: -4 |
% | 向零取模 | 向下取模 | -7%2 → Java: -1, Python: 1 |
** | Math.pow() | 内置幂运算 | Python 更直观 |
== | 引用/值取决于类型 | 始终值比较 | Python 的 == 像 Kotlin 的 == |
is | 不存在 | 身份比较 | Python 的 is 像 Kotlin 的 === |
&& / ` | | /!` | 逻辑运算 | and / or / not | Python 返回操作数值,不是布尔值 |
:= | 不存在 | 海象运算符 | Python 3.8+ 独有 |
| 链式比较 | 不支持 | 1 < x < 10 | Python 独有 |
常见陷阱
print(7 / 2)
print(7 // 2)
print(-7 // 2)
print(-7 % 2)
print(0 or "hello")
print(1 and 0)
x = 257
y = 257
print(x == y)
print(x is y)
何时使用
//: 需要整数结果时(分页、索引计算)
**: 幂运算(比 pow() 更直观)
is: 仅用于 None、True、False 的比较
==: 所有值比较
and/or: 逻辑运算 + 短路默认值
:=: 在表达式内需要赋值时(while 循环、推导式)
in: 成员检查(列表、字典键、子串)
2.6 控制流
Java/Kotlin 对比
if (score >= 90) {
grade = "A";
} else if (score >= 80) {
grade = "B";
} else {
grade = "C";
}
switch (obj) {
case Integer i -> System.out.println("Integer: " + i);
case String s -> System.out.println("String: " + s);
case null -> System.out.println("null");
default -> System.out.println("Other");
}
for (int i = 0; i < 10; i++) { }
for (String item : list) { }
while (condition) { }
do { } while (condition);
val grade = if (score >= 90) "A" else if (score >= 80) "B" else "C"
when (obj) {
is Int -> println("Integer: $obj")
is String -> println("String: $obj")
in 1..10 -> println("In range")
else -> println("Other")
}
for (i in 0 until 10) { }
for (item in list) { }
while (condition) { }
do { } while (condition)
Python 实现
score = 85
if score >= 90:
grade = "A"
elif score >= 80:
grade = "B"
elif score >= 70:
grade = "C"
else:
grade = "F"
print(f"Grade: {grade}")
grade = "A" if score >= 90 else "B" if score >= 80 else "C"
fruits = ["apple", "banana", "cherry"]
for fruit in fruits:
print(fruit)
for i, fruit in enumerate(fruits):
print(f"{i}: {fruit}")
for i in range(10):
print(i, end=" ")
for i in range(2, 10, 3):
print(i, end=" ")
user = {"name": "Alice", "age": 30}
for key in user:
print(key)
for key, value in user.items():
print(f"{key}: {value}")
names = ["Alice", "Bob", "Charlie"]
scores = [95, 87, 92]
for name, score in zip(names, scores):
print(f"{name}: {score}")
for i in reversed(range(5)):
print(i, end=" ")
for fruit in sorted(fruits, key=len):
print(fruit)
count = 0
while count < 5:
print(count)
count += 1
while True:
user_input = input("Enter 'quit' to exit: ")
if user_input == "quit":
break
print(f"You entered: {user_input}")
for i in range(10):
if i == 3:
continue
if i == 7:
break
print(i, end=" ")
for i in range(5):
pass
for n in range(2, 10):
for x in range(2, n):
if n % x == 0:
print(f"{n} = {x} * {n // x}")
break
else:
print(f"{n} is prime")
def http_status(code):
match code:
case 200:
return "OK"
case 404:
return "Not Found"
case 500:
return "Internal Server Error"
case _:
return "Unknown"
print(http_status(200))
print(http_status(404))
def describe(value):
match value:
case 0:
return "zero"
case 1 | 2 | 3:
return "small"
case _:
return "other"
def process_point(point):
match point:
case (0, 0):
return "origin"
case (x, 0):
return f"on x-axis at {x}"
case (0, y):
return f"on y-axis at {y}"
case (x, y):
return f"at ({x}, {y})"
print(process_point((3, 0)))
print(process_point((1, 2)))
def process_sequence(seq):
match seq:
case []:
return "empty"
case [first]:
return f"single: {first}"
case [first, second]:
return f"pair: {first}, {second}"
case [first, *rest]:
return f"first: {first}, rest: {rest}"
print(process_sequence([1, 2, 3, 4]))
def process_config(config):
match config:
case {"role": "admin", **rest}:
return f"Admin with extra: {rest}"
case {"role": role, "name": name}:
return f"{role}: {name}"
case {}:
return "empty config"
print(process_config({"role": "admin", "name": "Alice", "level": 5}))
def classify(number):
match number:
case n if n < 0:
return "negative"
case 0:
return "zero"
case n if n % 2 == 0:
return "even positive"
case _:
return "odd positive"
print(classify(-5))
print(classify(4))
print(classify(7))
def process_data(data):
match data:
case {"status": "ok", "data": [first, *rest]}:
return f"OK, first item: {first}, total: {1 + len(rest)}"
case {"status": "error", "message": msg}:
return f"Error: {msg}"
case _:
return "Unknown format"
print(process_data({"status": "ok", "data": [1, 2, 3]}))
核心差异
| 维度 | Java/Kotlin | Python |
|---|
| 条件分支 | if/else if/else | if/elif/else |
| 三元表达式 | cond ? a : b | a if cond else b |
| switch/when | switch/when | match/case (3.10+) |
| for 循环 | C 风格 + for-each | 仅 for-each(基于迭代器) |
| 循环变量 | 仅在循环内可见 | 循环后仍可见(泄漏!) |
| 循环 else | 不存在 | for...else / while...else |
| do-while | 有 | 没有(用 while True + break) |
| 模式匹配 | Java 17+ / Kotlin when | Python 3.10+ match/case |
常见陷阱
for i in range(5):
pass
print(i)
items = [1, 2, 3, 4, 5]
for item in items:
if item == 3:
items.remove(item)
print(items)
items = [1, 2, 3, 4, 5]
items = [item for item in items if item != 3]
items = [1, 2, 3, 4, 5]
for item in items[:]:
if item == 3:
items.remove(item)
def find_item(items, target):
for item in items:
if item == target:
print(f"Found: {item}")
break
else:
print("Not found")
find_item([1, 2, 3], 2)
find_item([1, 2, 3], 5)
何时使用
if/elif/else: 条件分支(简单逻辑)
- 三元表达式: 简单的二选一赋值
match/case: 复杂的多分支匹配(3.10+),尤其是结构化数据
for: 遍历集合、range()、enumerate()、zip()
while: 循环次数不确定时
for...else: 查找是否找到(替代"找到标志"变量)
break: 提前退出循环
continue: 跳过当前迭代
2.7 推导式
Java/Kotlin 对比
List<Integer> nums = List.of(1, 2, 3, 4, 5);
List<Integer> evens = nums.stream()
.filter(n -> n % 2 == 0)
.map(n -> n * n)
.collect(Collectors.toList());
val nums = listOf(1, 2, 3, 4, 5)
val evens = nums
.filter { it % 2 == 0 }
.map { it * it }
Python 实现
squares = [x ** 2 for x in range(10)]
print(squares)
evens = [x for x in range(20) if x % 2 == 0]
print(evens)
labels = [f"item_{i}" for i in range(5)]
print(labels)
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flat = [x for row in matrix for x in row]
print(flat)
pairs = [(x, y) for x in range(3) for y in range(3) if x != y]
print(pairs)
squares_dict = {x: x ** 2 for x in range(6)}
print(squares_dict)
original = {"a": 1, "b": 2, "c": 3}
swapped = {v: k for k, v in original.items()}
print(swapped)
scores = {"Alice": 95, "Bob": 72, "Charlie": 88, "Diana": 60}
passed = {name: score for name, score in scores.items() if score >= 70}
print(passed)
words = ["hello", "world", "hello", "python", "world"]
unique_lengths = {len(word) for word in words}
print(unique_lengths)
nums = [1, 2, 3, 4, 5, 5, 4, 3]
unique_squares = {x ** 2 for x in nums}
print(unique_squares)
squares_list = [x ** 2 for x in range(1_000_000)]
squares_gen = (x ** 2 for x in range(1_000_000))
gen = (x ** 2 for x in range(5))
print(list(gen))
print(list(gen))
total = sum(x ** 2 for x in range(100))
print(total)
max_val = max(len(word) for word in words)
print(max_val)
result = ",".join(str(x) for x in range(10))
print(result)
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
]
transposed = [[row[i] for row in matrix] for i in range(3)]
print(transposed)
names_by_length = {}
for name in ["Alice", "Bob", "Charlie", "Diana", "Eve"]:
names_by_length.setdefault(len(name), []).append(name)
from collections import defaultdict
names_by_length = defaultdict(list)
for name in ["Alice", "Bob", "Charlie", "Diana", "Eve"]:
names_by_length[len(name)].append(name)
print(dict(names_by_length))
核心差异
| 维度 | Java Stream | Kotlin 链式调用 | Python 推导式 |
|---|
| 语法 | stream().filter().map().collect() | .filter{}.map{} | [expr for x in iter if cond] |
| 惰性求值 | 是(Stream) | 否(List) | 列表推导式否,生成器表达式是 |
| 可读性 | 嵌套时差 | 中等 | 嵌套时差 |
| 性能 | 有开销(Stream 管道) | 较好 | 通常比 for 循环快 |
| 嵌套循环 | flatMap | flatMap | 直接写多个 for |
常见陷阱
result = [x for x in range(5)]
for x in range(5):
print(x)
gen = (x for x in range(3))
print(list(gen))
print(list(gen))
evens = [x for x in range(10) if x % 2 == 0]
labels = ["even" if x % 2 == 0 else "odd" for x in range(5)]
print(labels)
何时使用
- 列表推导式: 需要立即使用结果列表时
- 字典推导式: 从一个集合构建映射时
- 集合推导式: 需要去重时
- 生成器表达式: 数据量大、只需遍历一次时(传给
sum()、max()、any() 等函数)
- 普通 for 循环: 逻辑复杂、有副作用、超过2层嵌套时
2.8 函数定义
Java/Kotlin 对比
public class Calculator {
public int add(int a, int b) {
return a + b;
}
public double add(double a, double b) {
return a + b;
}
public int sum(int... nums) {
int total = 0;
for (int n : nums) total += n;
return total;
}
Runnable r = () -> System.out.println("hello");
Function<Integer, Integer> doubleIt = x -> x * 2;
}
fun add(a: Int, b: Int): Int = a + b
fun greet(name: String = "World"): String = "Hello, $name"
greet(name = "Alice")
fun sum(vararg nums: Int): Int = nums.sum()
val doubleIt: (Int) -> Int = { x -> x * 2 }
val square: (Int) -> Int = { it * it }
Python 实现
def add(a, b):
"""两数相加(docstring)"""
return a + b
result = add(3, 5)
my_add = add
print(my_add(3, 5))
def greet(name, greeting="Hello"):
return f"{greeting}, {name}!"
print(greet("Alice"))
print(greet("Alice", "Hi"))
print(greet(name="Bob", greeting="Hey"))
print(greet(greeting="Hey", name="Bob"))
def bad_append(item, target=[]):
"""每次调用共享同一个 list!"""
target.append(item)
return target
print(bad_append(1))
print(bad_append(2))
print(bad_append(3))
def good_append(item, target=None):
if target is None:
target = []
target.append(item)
return target
print(good_append(1))
print(good_append(2))
print(good_append(3))
def bad_config(options={}):
options.setdefault("debug", False)
return options
def good_config(options=None):
if options is None:
options = {}
options.setdefault("debug", False)
return options
def variadic(*args, **kwargs):
print(f"args: {args}")
print(f"kwargs: {kwargs}")
variadic(1, 2, 3, name="Alice", age=30)
def log(level, message, **extra):
print(f"[{level}] {message}")
for key, value in extra.items():
print(f" {key}: {value}")
log("INFO", "User logged in", user_id=42, ip="192.168.1.1")
def my_sum(*numbers):
total = 0
for n in numbers:
total += n
return total
print(my_sum(1, 2, 3, 4, 5))
def add(a, b, c):
return a + b + c
args = (1, 2, 3)
print(add(*args))
kwargs = {"a": 1, "b": 2, "c": 3}
print(add(**kwargs))
def safe_divide(numerator, denominator, *, round_to=2):
"""denominator 和 round_to 必须用关键字传递"""
result = numerator / denominator
return round(result, round_to)
print(safe_divide(10, 3, round_to=4))
square = lambda x: x ** 2
print(square(5))
add = lambda a, b: a + b
print(add(3, 4))
pairs = [(1, "banana"), (3, "apple"), (2, "cherry")]
pairs.sort(key=lambda x: x[1])
print(pairs)
numbers = [1, 2, 3, 4, 5]
doubled = list(map(lambda x: x * 2, numbers))
print(doubled)
evens = list(filter(lambda x: x % 2 == 0, numbers))
print(evens)
doubled = [x * 2 for x in numbers]
evens = [x for x in numbers if x % 2 == 0]
def greet(name: str) -> str:
return f"Hello, {name}"
def add(a: int, b: int) -> int:
return a + b
add("hello", "world")
from typing import Optional
def find_user(user_id: int) -> Optional[str]:
if user_id == 1:
return "Alice"
return None
def process(value: int | str) -> str:
return str(value)
say_hello = greet
operations = [lambda x: x + 1, lambda x: x * 2, lambda x: x ** 2]
for op in operations:
print(op(5))
def apply(func, value):
return func(value)
print(apply(lambda x: x ** 2, 5))
def make_multiplier(factor):
def multiplier(x):
return x * factor
return multiplier
double = make_multiplier(2)
triple = make_multiplier(3)
print(double(5))
print(triple(5))
def timer(func):
import time
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
elapsed = time.time() - start
print(f"{func.__name__} took {elapsed:.4f}s")
return result
return wrapper
@timer
def slow_function():
import time
time.sleep(0.1)
return "done"
print(slow_function())
核心差异
| 维度 | Java | Kotlin | Python |
|---|
| 函数位置 | 必须在类中 | 可以在类外(顶层函数) | 可以在模块顶层 |
| 参数类型 | 必须声明 | 可推断 | 可选(类型注解) |
| 返回类型 | 必须声明 | 可推断 | 可选 |
| 默认参数 | 不支持(需重载) | 支持 | 支持 |
| 可变参数 | Type... args | vararg args | *args, **kwargs |
| 命名参数 | 不支持 | 支持 | 支持(关键字参数) |
| 函数重载 | 支持 | 支持 | 不支持(用默认参数或 *args) |
| Lambda | (x) -> expr | { x -> expr } | lambda x: expr |
| 类型注解 | 编译时强制 | 编译时强制 | 运行时忽略(工具检查) |
常见陷阱
funcs = [lambda: i for i in range(5)]
print([f() for f in funcs])
funcs = [lambda i=i: i for i in range(5)]
print([f() for f in funcs])
import time
def report(timestamp=time.time()):
print(f"Generated at: {timestamp}")
report()
time.sleep(1)
report()
何时使用
def: 所有需要多行逻辑的函数
- 默认参数: 减少函数重载,提供便捷调用
*args: 函数需要接受任意数量的位置参数
**kwargs: 函数需要接受任意数量的关键字参数(配置选项、扩展参数)
- 仅关键字参数
*: 防止位置参数误传,提高可读性
lambda: 简短的一次性函数(排序 key、map/filter 参数)
- 类型注解: 团队项目、库开发、IDE 提示
2.9 作用域: LEGB 规则
Java/Kotlin 对比
public class ScopeDemo {
private static int global = 10;
public void method() {
int local = 20;
if (true) {
int blockScoped = 30;
System.out.println(local);
System.out.println(blockScoped);
}
}
public void anotherMethod() {
System.out.println(global);
}
}
fun method() {
val outer = 1
if (true) {
val inner = 2
println(outer)
}
}
fun makeCounter(): () -> Int {
var count = 0
return { count++ }
}
Python 实现
x = "global"
def outer():
print(f"outer: {x}")
def inner():
print(f"inner: {x}")
inner()
outer()
x = "global"
def func():
x = "local"
print(f"func: {x}")
func()
print(f"global: {x}")
def outer():
x = "enclosing"
def inner():
print(f"inner: {x}")
inner()
outer()
counter = 0
def increment():
global counter
counter += 1
increment()
increment()
increment()
print(counter)
counter = 0
def broken_increment():
pass
def make_counter():
count = 0
def increment():
nonlocal count
count += 1
return count
return increment
counter = make_counter()
print(counter())
print(counter())
print(counter())
def broken_counter():
count = 0
def increment():
pass
return increment
for i in range(5):
x = i * 2
print(i)
print(x)
result = [i for i in range(5)]
def make_multiplier(factor):
"""返回一个乘法函数,捕获 factor"""
def multiplier(x):
return x * factor
return multiplier
double = make_multiplier(2)
triple = make_multiplier(3)
print(double(5))
print(triple(5))
def make_funcs():
funcs = []
for i in range(3):
def func():
return i
funcs.append(func)
return funcs
f0, f1, f2 = make_funcs()
print(f0())
print(f1())
print(f2())
def make_funcs_fixed():
funcs = []
for i in range(3):
def func(i=i):
return i
funcs.append(func)
return funcs
f0, f1, f2 = make_funcs_fixed()
print(f0())
print(f1())
print(f2())
x = "global"
def outer():
x = "enclosing"
def middle():
x = "middle"
def inner():
x = "local"
print(f"inner: {x}")
inner()
print(f"middle: {x}")
middle()
print(f"outer: {x}")
outer()
print(f"module: {x}")
import builtins
print(dir(builtins)[:10])
核心差异
| 维度 | Java/Kotlin | Python |
|---|
| 作用域类型 | 块级作用域 | 函数级作用域(LEGB) |
| for 循环变量 | 循环结束后不可见 | 循环结束后仍可见(泄漏) |
| if 块变量 | 块结束后不可见 | 块结束后仍可见 |
| 修改外层变量 | 直接修改(如果是 final 则不能) | 需要 global 或 nonlocal 声明 |
| 闭包变量绑定 | 值捕获 | 延迟绑定(变量引用) |
| 内置函数覆盖 | 不可能(关键字/内置名受保护) | 可以覆盖(但不要这么做) |
常见陷阱
count = 0
def increment():
global count
count += 1
funcs = []
for i in range(3):
funcs.append(lambda: i)
print([f() for f in funcs])
total = 0
for x in range(5):
total += x
print(total)
x = "global"
class MyClass:
x = "class"
def method(self):
print(MyClass.x)
何时使用
global: 非常少用。大多数情况应该用函数参数和返回值传递数据
nonlocal: 闭包中需要修改外层函数的变量(如计数器、状态机)
- 理解 LEGB: 调试
UnboundLocalError 时,先检查是否需要 global/nonlocal
- 避免 for 循环变量泄漏: 循环结束后不需要用到循环变量时不用管;需要用到时显式赋值
本章总结: 语法速查表
| 知识点 | Java/Kotlin | Python | 最容易犯的错 |
|---|
| 代码块 | {} | 缩进 | 混用 Tab 和空格 |
| 变量赋值 | 类型声明 | 名字绑定 | 链式赋值共享可变对象 |
| null | null | None | 用 == 而非 is 比较 None |
| 整数 | 有范围 | 无上限 | 以为会溢出(不会) |
| 字符串 | 仅双引号 | 单/双/三引号 | bytes 和 str 混用 |
| 除法 | / 整除 | / 浮点, // 整除 | 7/2 以为是 3 |
| 逻辑运算 | &&, ||, ! | and, or, not | and/or 返回值不是布尔 |
| for 循环 | C 风格 + for-each | 仅迭代器 | 循环变量泄漏 |
| 推导式 | Stream API | [expr for x in iter] | 嵌套超过2层 |
| 默认参数 | 不支持/支持 | 支持 | 可变默认参数陷阱 |
| 作用域 | 块级 | 函数级 (LEGB) | 忘记 global/nonlocal |
核心认知: Python 的语法看似简单,但"看起来像"的东西往往"行为不同"。本章的每个陷阱都是从 Java/Kotlin 转过来的开发者踩过的坑。遇到 UnboundLocalError、IndentationError、TypeError 时,回来翻这一章。