Kotlin vs Python 知识点对照表
面向精通Kotlin的开发者,快速掌握Python核心知识
目录
- 语法核心对照
- 1.1 变量与类型声明
- 1.2 函数定义
- 1.3 类与对象
- 1.4 泛型系统
- 1.5 类型系统进阶
- 1.6 空安全处理
- 1.7 集合操作
- 1.8 扩展函数与运算符重载
- 并发模型对照
- 2.1 协程 vs asyncio
- 2.2 线程模型
- 2.3 异常处理
- 标准库/生态对照
- 3.1 包管理
- 3.2 测试框架
- 3.3 常用库对照
- 运行时特性对照
- 4.1 编译 vs 解释
- 4.2 内存模型
- 4.3 垃圾回收
- [Python 易错代码大全](#Python 易错代码大全 "#5-python-%E6%98%93%E9%94%99%E4%BB%A3%E7%A0%81%E5%A4%A7%E5%85%A8")
- 5.1 可变默认参数陷阱
- 5.2 闭包变量绑定延迟
- 5.3
or运算符的假值陷阱 - 5.4
==vsis的身份 vs 相等 - 5.5 整数缓存与身份比较
- 5.6 列表推导式中的变量泄漏
- 5.7
self忘记写 - 5.8
__init__返回值陷阱 - 5.9 字符串拼接性能陷阱
- 5.10
try/except吞掉 KeyboardInterrupt - 5.11
*args捕获生成器耗尽 - 5.12
@dataclass的__hash__陷阱 - 5.13
isinstance与类型的微妙关系 - 5.14
dict修改时遍历崩溃 - 5.15 浅拷贝 vs 深拷贝
- 5.16
bool是int的子类 - 5.17
None的比较陷阱 - 5.18
lambda在循环中的闭包陷阱 - 5.19
multiprocessing的 lambda 序列化失败 - 5.20
asyncio中调用同步阻塞函数
- 快速参考表
1. 语法核心对照
1.1 变量与类型声明
Kotlin
kotlin
// 不可变变量 (val)
val name: String = "Kotlin"
val inferred = "类型推断" // String
// 可变变量 (var)
var count: Int = 0
count = 1 // OK
// 延迟初始化
lateinit var lateString: String
val lazyValue: String by lazy {
"延迟计算"
}
// 常量
const val MAX_SIZE = 100
Python
python
# Python 没有val/var区分,靠约定
# 不可变约定:全大写或文档说明
MAX_SIZE = 100 # 约定为常量
# 变量声明(无需类型注解)
name: str = "Python" # 类型注解可选
inferred = "类型推断" # 运行时确定类型
# 可变变量(默认都可变)
count: int = 0
count = 1 # OK
# 延迟初始化
class Example:
def __init__(self):
self._lazy_value = None
@property
def lazy_value(self):
if self._lazy_value is None:
self._lazy_value = "延迟计算"
return self._lazy_value
核心差异
| 特性 | Kotlin | Python |
|---|---|---|
| 不可变性 | val 编译时强制 |
约定,无强制 |
| 类型注解 | 必须或推断 | 完全可选 |
| 类型检查 | 编译时 | 运行时 |
| 延迟初始化 | lateinit / by lazy |
@property 或 __getattr__ |
1.2 函数定义
Kotlin
kotlin
// 普通函数
fun add(a: Int, b: Int): Int {
return a + b
}
// 单表达式函数
fun addSimple(a: Int, b: Int) = a + b
// 默认参数
fun greet(name: String, greeting: String = "Hello") =
"$greeting, $name!"
// 命名参数
greet(name = "World", greeting = "Hi")
// 可变参数
fun sum(vararg numbers: Int): Int =
numbers.sum()
// 扩展函数
fun String.shout() = this.uppercase() + "!"
"hello".shout() // "HELLO!"
// 高阶函数
fun operate(a: Int, b: Int, op: (Int, Int) -> Int): Int =
op(a, b)
operate(1, 2) { x, y -> x * y } // 2
// Lambda 表达式
val square: (Int) -> Int = { x -> x * x }
val square2 = { x: Int -> x * x }
// 函数类型别名
typealias IntOp = (Int, Int) -> Int
Python
python
from typing import Callable, TypeAlias
# 普通函数
def add(a: int, b: int) -> int:
return a + b
# 单表达式函数(lambda 有限制)
add_simple = lambda a, b: a + b # 不推荐复杂逻辑
# 默认参数
def greet(name: str, greeting: str = "Hello") -> str:
return f"{greeting}, {name}!"
# 命名参数
greet(name="World", greeting="Hi")
# 可变参数
def sum_numbers(*numbers: int) -> int:
return sum(numbers)
sum_numbers(1, 2, 3) # 6
# 扩展函数(Python 无原生支持,用猴子补丁或独立函数)
def shout(s: str) -> str:
return s.upper() + "!"
shout("hello") # "HELLO!"
# 高阶函数
from typing import Callable
def operate(a: int, b: int, op: Callable[[int, int], int]) -> int:
return op(a, b)
operate(1, 2, lambda x, y: x * y) # 2
# Lambda 表达式(只能是单表达式)
square: Callable[[int], int] = lambda x: x * x
# 函数类型别名
IntOp: TypeAlias = Callable[[int, int], int]
核心差异
| 特性 | Kotlin | Python |
|---|---|---|
| 单表达式函数 | fun f() = expr |
lambda(受限) |
| 默认参数 | 支持 | 支持 |
| 命名参数 | 支持 | 支持 |
| 可变参数 | vararg |
*args, **kwargs |
| 扩展函数 | 原生支持 | 无(用独立函数) |
| Lambda | 多行支持 | 仅单表达式 |
1.3 类与对象
Kotlin
kotlin
// 普通类
class Person(val name: String, var age: Int) {
fun greet() = "Hi, I'm $name"
}
// 数据类(自动生成 equals, hashCode, toString, copy)
data class User(val id: Int, val name: String)
// 密封类(受限继承)
sealed class Result {
data class Success(val data: String) : Result()
data class Error(val message: String) : Result()
}
// 枚举类
enum class Status {
ACTIVE, INACTIVE, PENDING
}
// 对象声明(单例)
object Database {
fun connect() = "Connected"
}
// 伴生对象(静态成员)
class Factory {
companion object {
fun create() = Factory()
}
}
// 匿名对象
val listener = object : ClickListener {
override fun onClick() = println("Clicked")
}
// 接口
interface Drawable {
fun draw()
fun description() = "Drawable" // 默认实现
}
Python
python
from dataclasses import dataclass
from enum import Enum, auto
from typing import Protocol, runtime_checkable
import abc
# 普通类
class Person:
def __init__(self, name: str, age: int):
self.name = name
self.age = age
def greet(self) -> str:
return f"Hi, I'm {self.name}"
# 数据类(Python 3.7+)
@dataclass
class User:
id: int
name: str
# 自动生成 __init__, __repr__, __eq__
# 密封类(无原生支持,用 Union 模拟)
from typing import Union
class Success:
def __init__(self, data: str):
self.data = data
class Error:
def __init__(self, message: str):
self.message = message
Result = Union[Success, Error]
# 枚举类
class Status(Enum):
ACTIVE = auto()
INACTIVE = auto()
PENDING = auto()
# 单例模式(模块级变量或 __new__)
class Database:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
def connect(self) -> str:
return "Connected"
# 静态方法/类方法
class Factory:
@staticmethod
def create() -> 'Factory':
return Factory()
@classmethod
def from_config(cls, config: dict) -> 'Factory':
return cls()
# 接口(Protocol 或 ABC)
@runtime_checkable
class Drawable(Protocol):
def draw(self) -> None: ...
# 或抽象基类
class DrawableABC(abc.ABC):
@abc.abstractmethod
def draw(self) -> None:
pass
核心差异
| 特性 | Kotlin | Python |
|---|---|---|
| 构造函数 | 主构造函数 + init | __init__ |
| 数据类 | data class |
@dataclass |
| 密封类 | sealed class |
Union + 模式匹配 |
| 单例 | object |
模块级变量或 __new__ |
| 静态成员 | companion object |
@staticmethod / @classmethod |
| 接口 | interface |
Protocol 或 ABC |
| 访问控制 | public/private/protected |
约定 _ / __ |
1.4 泛型系统
Kotlin
kotlin
// 泛型类
class Box<T>(val value: T)
// 泛型函数
fun <T> singletonList(item: T): List<T> = listOf(item)
// 类型约束
fun <T : Comparable<T>> max(a: T, b: T): T =
if (a > b) a else b
// 多重约束
fun <T> process(item: T) where T : CharSequence, T : Comparable<T> {
// ...
}
// 型变 - 协变 (out)
interface Producer<out T> {
fun produce(): T
}
// Producer<String> 是 Producer<Any> 的子类型
// 型变 - 逆变 (in)
interface Consumer<in T> {
fun consume(item: T)
}
// Consumer<Any> 是 Consumer<String> 的子类型
// 星投影
fun printList(list: List<*>) {
list.forEach { println(it) } // it 是 Any?
}
// 具体化泛型
inline fun <reified T> isType(value: Any): Boolean =
value is T
isType<String>("hello") // true
Python
python
from typing import TypeVar, Generic, List, Any, Callable
from typing import Protocol, runtime_checkable
# 泛型类
T = TypeVar('T')
class Box(Generic[T]):
def __init__(self, value: T):
self.value = value
# 泛型函数
def singleton_list(item: T) -> List[T]:
return [item]
# 类型约束 (bound)
TComparable = TypeVar('TComparable', bound='Comparable')
class Comparable(Protocol):
def __lt__(self, other: Any) -> bool: ...
def max_val(a: TComparable, b: TComparable) -> TComparable:
return a if a > b else b
# 多重约束(Python 3.12+ 或 Protocol 组合)
class CharSequenceComparable(Protocol):
def __len__(self) -> int: ...
def __lt__(self, other: Any) -> bool: ...
# 协变 (covariant)
T_co = TypeVar('T_co', covariant=True)
class Producer(Protocol[T_co]):
def produce(self) -> T_co: ...
# 逆变 (contravariant)
T_contra = TypeVar('T_contra', contravariant=True)
class Consumer(Protocol[T_contra]):
def consume(self, item: T_contra) -> None: ...
# Any 类似星投影
def print_list(lst: List[Any]) -> None:
for item in lst:
print(item)
# 具体化(Python 运行时可获取类型)
def is_type(value: Any, expected_type: type) -> bool:
return isinstance(value, expected_type)
is_type("hello", str) # True
核心差异
| 特性 | Kotlin | Python |
|---|---|---|
| 泛型声明 | <T> |
TypeVar('T') 或 T = TypeVar('T') |
| 类型约束 | <T : UpperBound> |
bound=... |
| 协变 | out T |
covariant=True |
| 逆变 | in T |
contravariant=True |
| 星投影 | * |
Any |
| 具体化 | reified |
运行时天然支持 |
| 类型擦除 | JVM擦除 | 运行时保留 |
1.5 类型系统进阶
Kotlin
kotlin
// 类型别名
typealias StringList = List<String>
typealias Predicate<T> = (T) -> Boolean
// 内联类 / 值类
@JvmInline
value class Password(val value: String)
// 交叉类型
fun <T> both(a: T) where T : CharSequence, T : Appendable
// 可空类型
val nullable: String? = null
val nonNull: String = "required"
// 智能类型转换
fun process(obj: Any) {
if (obj is String) {
println(obj.length) // 自动转换为 String
}
}
// 密封接口
sealed interface Node {
data class Leaf(val value: Int) : Node
data class Branch(val left: Node, val right: Node) : Node
}
Python
python
from typing import TypeAlias, Union, Optional, Any
from typing import Protocol, runtime_checkable
# 类型别名 (Python 3.12+)
type StringList = list[str]
type Predicate[T] = Callable[[T], bool]
# 或旧语法
StringList2: TypeAlias = list[str]
# NewType(类似值类)
from typing import NewType
Password = NewType('Password', str)
# 交叉类型(Protocol 组合)
class CharSequence(Protocol):
def __len__(self) -> int: ...
class Appendable(Protocol):
def append(self, s: str) -> None: ...
class Both(CharSequence, Appendable, Protocol):
pass
# 可空类型
nullable: Optional[str] = None # 等价于 str | None
non_null: str = "required"
# 类型检查(运行时)
def process(obj: Any) -> None:
if isinstance(obj, str):
print(len(obj)) # 类型已知
# Union 类型 (Python 3.10+)
from typing import Union
Result = Union[int, str] # 或 int | str
# 字面量类型
from typing import Literal
Status = Literal["active", "inactive"]
核心差异
| 特性 | Kotlin | Python |
|---|---|---|
| 类型别名 | typealias |
TypeAlias 或 type |
| 值类型 | value class |
NewType(弱) |
| 可空类型 | T? |
Optional[T] 或 `T |
| 智能转换 | 自动 | 需 isinstance |
| 联合类型 | 密封类 | Union / Literal |
| 类型检查 | 编译时 | 运行时 + mypy |
1.6 空安全处理
Kotlin
kotlin
val nullable: String? = null
// 安全调用
val length: Int? = nullable?.length
// Elvis 运算符
val length2: Int = nullable?.length ?: 0
// 非空断言(可能抛 NPE)
val length3: Int = nullable!!.length // 危险!
// 安全转换
val number: Int? = obj as? Int
// let 链式调用
nullable?.let {
println(it.length)
}
// takeIf / takeUnless
val result = nullable?.takeIf { it.isNotEmpty() }
// requireNotNull
val required: String = requireNotNull(nullable) { "不能为空" }
Python
python
from typing import Optional
nullable: Optional[str] = None
# 安全访问(无语法糖,需显式检查)
length: Optional[int] = nullable.length if nullable else None
# 默认值
length2: int = len(nullable) if nullable else 0
# 非空断言(无内置,自定义)
def require_non_null(value: Optional[T], msg: str = "不能为空") -> T:
if value is None:
raise ValueError(msg)
return value
# 安全转换
def safe_int(obj: Any) -> Optional[int]:
try:
return int(obj)
except (ValueError, TypeError):
return None
# 链式调用(无 let,用 if)
if nullable is not None:
print(len(nullable))
# 条件赋值
result = nullable if nullable and len(nullable) > 0 else None
# requireNotNull 等价
required: str = require_non_null(nullable, "不能为空")
核心差异
| 特性 | Kotlin | Python | 说明 |
|---|---|---|---|
| 可空声明 | T? |
Optional[T] |
Kotlin 编译时强制 |
| 安全调用 | ?. |
无语法糖 | Python 需显式检查 |
| 默认值 | ?: |
or / if else |
Python or 有陷阱 |
| 非空断言 | !! |
无 | Python 直接抛异常 |
| 安全转换 | as? |
try/except |
Python 需异常处理 |
1.7 集合操作
Kotlin
kotlin
val numbers = listOf(1, 2, 3, 4, 5)
// 不可变 vs 可变
val immutable: List<Int> = listOf(1, 2, 3)
val mutable: MutableList<Int> = mutableListOf(1, 2, 3)
// 序列(惰性求值)
val result = numbers
.asSequence()
.filter { it > 2 }
.map { it * 2 }
.take(2)
.toList() // [6, 8]
// 常用操作
numbers.filter { it % 2 == 0 } // [2, 4]
numbers.map { it * 2 } // [2, 4, 6, 8, 10]
numbers.flatMap { listOf(it, it) } // [1,1,2,2,3,3,4,4,5,5]
numbers.reduce { acc, n -> acc + n } // 15
numbers.fold(0) { acc, n -> acc + n } // 15
numbers.groupBy { it % 2 } // {1=[1,3,5], 0=[2,4]}
numbers.associateBy { "key$it" } // Map
numbers.partition { it > 2 } // ([3,4,5], [1,2])
numbers.chunked(2) // [[1,2], [3,4], [5]]
numbers.windowed(3) // [[1,2,3], [2,3,4], [3,4,5]]
// Set 操作
val set1 = setOf(1, 2, 3)
val set2 = setOf(2, 3, 4)
set1 union set2 // {1, 2, 3, 4}
set1 intersect set2 // {2, 3}
set1 subtract set2 // {1}
// Map 操作
val map = mapOf("a" to 1, "b" to 2)
map.mapKeys { it.key.uppercase() }
map.mapValues { it.value * 2 }
Python
python
from typing import List, Dict, Set, Optional
from itertools import islice, chain
numbers = [1, 2, 3, 4, 5]
# 不可变 vs 可变(Python 无编译时区分)
immutable: tuple[int, ...] = (1, 2, 3)
mutable: list[int] = [1, 2, 3]
# 生成器(惰性求值)
def process_sequence(nums):
for n in nums:
if n > 2:
yield n * 2
result = list(islice(process_sequence(numbers), 2)) # [6, 8]
# 或使用生成器表达式
result2 = list(islice((n * 2 for n in numbers if n > 2), 2))
# 常用操作
list(filter(lambda x: x % 2 == 0, numbers)) # [2, 4]
[x * 2 for x in numbers] # [2, 4, 6, 8, 10] - 列表推导式
[x for n in numbers for x in (n, n)] # flatMap 等价
# 或
list(chain.from_iterable([[n, n] for n in numbers]))
from functools import reduce
reduce(lambda acc, n: acc + n, numbers, 0) # 15
# groupBy
from itertools import groupby
from operator import itemgetter
sorted_nums = sorted(numbers, key=lambda x: x % 2)
grouped = {k: list(g) for k, g in groupby(sorted_nums, key=lambda x: x % 2)}
# partition
def partition(pred, iterable):
true, false = [], []
for x in iterable:
(true if pred(x) else false).append(x)
return true, false
greater, lesser = partition(lambda x: x > 2, numbers)
# chunked
def chunked(iterable, n):
return [iterable[i:i+n] for i in range(0, len(iterable), n)]
chunked(numbers, 2) # [[1,2], [3,4], [5]]
# windowed
def windowed(iterable, n):
return [iterable[i:i+n] for i in range(len(iterable) - n + 1)]
windowed(numbers, 3) # [[1,2,3], [2,3,4], [3,4,5]]
# Set 操作
set1 = {1, 2, 3}
set2 = {2, 3, 4}
set1 | set2 # union {1, 2, 3, 4}
set1 & set2 # intersect {2, 3}
set1 - set2 # difference {1}
# Map 操作
d = {"a": 1, "b": 2}
{k.upper(): v for k, v in d.items()} # mapKeys
{k: v * 2 for k, v in d.items()} # mapValues
核心差异
| 特性 | Kotlin | Python |
|-------|----------------|-----------------------|--------|
| 不可变集合 | List / Set | tuple / frozenset |
| 惰性求值 | Sequence | 生成器 / itertools |
| 链式调用 | 流畅 API | 需嵌套或中间变量 |
| 推导式 | 无 | [] / {} 推导式 |
| 集合运算 | 方法名 | 运算符 ` | & -` |
1.8 扩展函数与运算符重载
Kotlin
kotlin
// 扩展函数
fun String.addExclamation() = this + "!"
"hello".addExclamation() // "hello!"
// 扩展属性
val String.hasContent: Boolean
get() = this.isNotEmpty()
// 运算符重载
data class Point(val x: Int, val y: Int) {
operator fun plus(other: Point) =
Point(x + other.x, y + other.y)
operator fun times(scalar: Int) =
Point(x * scalar, y * scalar)
operator fun get(index: Int) =
when (index) {
0 -> x
1 -> y
else -> throw IndexOutOfBoundsException()
}
}
val p1 = Point(1, 2)
val p2 = Point(3, 4)
p1 + p2 // Point(4, 6)
p1 * 2 // Point(2, 4)
p1[0] // 1
// 解构声明
val (x, y) = p1
// in 运算符
operator fun Point.contains(point: Point) =
point.x in 0..x && point.y in 0..y
// 范围运算符
operator fun Point.rangeTo(other: Point) =
PointRange(this, other)
// 调用运算符
operator fun Point.invoke(action: (Int, Int) -> Unit) =
action(x, y)
Python
python
# 扩展函数(无原生支持,用独立函数)
def add_exclamation(s: str) -> str:
return s + "!"
add_exclamation("hello") # "hello!"
# 或猴子补丁(不推荐)
# str.add_exclamation = lambda self: self + "!"
# 运算符重载
from dataclasses import dataclass
@dataclass
class Point:
x: int
y: int
def __add__(self, other: 'Point') -> 'Point':
return Point(self.x + other.x, self.y + other.y)
def __mul__(self, scalar: int) -> 'Point':
return Point(self.x * scalar, self.y * scalar)
def __getitem__(self, index: int) -> int:
if index == 0:
return self.x
elif index == 1:
return self.y
raise IndexError("Point index out of range")
def __contains__(self, point: 'Point') -> bool:
return 0 <= point.x <= self.x and 0 <= point.y <= self.y
def __call__(self, action):
return action(self.x, self.y)
p1 = Point(1, 2)
p2 = Point(3, 4)
p1 + p2 # Point(x=4, y=6)
p1 * 2 # Point(x=2, y=4)
p1[0] # 1
# 解构(通过元组协议)
def __iter__(self):
yield self.x
yield self.y
x, y = p1 # 需要添加 __iter__ 方法
# 运算符对照表
"""
Kotlin operator Python method
+ (plus) __add__
- (minus) __sub__
* (times) __mul__
/ (div) __truediv__
% (mod) __mod__
** (无) __pow__
in (contains) __contains__
[] (get) __getitem__
[] = (set) __setitem__
() (invoke) __call__
< > <= >= __lt__, __gt__, __le__, __ge__
== (equals) __eq__
"""
核心差异
| 特性 | Kotlin | Python |
|---|---|---|
| 扩展函数 | 原生支持 | 无(用独立函数) |
| 扩展属性 | 支持 | 无 |
| 运算符数量 | 有限集合 | 更丰富 |
| 解构声明 | operator fun componentN() |
__iter__ 或 __getitem__ |
| 调用运算符 | operator fun invoke() |
__call__ |
2. 并发模型对照
2.1 协程 vs asyncio
Kotlin 协程
kotlin
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
// 启动协程
fun main() = runBlocking {
// launch: 不返回结果
launch {
delay(1000)
println("World!")
}
println("Hello")
// async: 返回结果
val deferred = async {
delay(500)
42
}
println(deferred.await()) // 42
}
// 协程作用域
class ViewModel {
private val scope = CoroutineScope(Dispatchers.Main + SupervisorJob())
fun fetchData() {
scope.launch {
try {
val data = withContext(Dispatchers.IO) {
apiCall()
}
updateUI(data)
} catch (e: Exception) {
handleError(e)
}
}
}
fun cleanup() {
scope.cancel()
}
}
// Flow(冷流)
fun numbers(): Flow<Int> = flow {
for (i in 1..10) {
delay(100)
emit(i)
}
}
// SharedFlow / StateFlow(热流)
val sharedFlow = MutableSharedFlow<Int>()
val stateFlow = MutableStateFlow(0)
// 结构化并发
suspend fun parallelTasks(): List<String> = coroutineScope {
val deferred1 = async { task1() }
val deferred2 = async { task2() }
listOf(deferred1.await(), deferred2.await())
}
Python asyncio
python
import asyncio
from typing import AsyncGenerator, List
from dataclasses import dataclass
# 启动协程
async def main():
# create_task: 不等待结果
task1 = asyncio.create_task(say_world())
print("Hello")
await task1
# gather: 并发执行多个协程
results = await asyncio.gather(
task1(),
task2(),
return_exceptions=True # 异常处理
)
# 返回结果
result = await compute_42()
print(result)
async def say_world():
await asyncio.sleep(1)
print("World!")
async def compute_42() -> int:
await asyncio.sleep(0.5)
return 42
# 运行
asyncio.run(main())
# 异步生成器(类似 Flow)
async def numbers() -> AsyncGenerator[int, None]:
for i in range(1, 11):
await asyncio.sleep(0.1)
yield i
# 消费异步生成器
async def consume():
async for num in numbers():
print(num)
# 或
async def consume_all():
result = [num async for num in numbers()]
# 结构化并发(Python 3.11+ TaskGroup)
async def parallel_tasks() -> List[str]:
async with asyncio.TaskGroup() as tg:
task1 = tg.create_task(do_task1())
task2 = tg.create_task(do_task2())
return [task1.result(), task2.result()]
# 超时控制
async def with_timeout():
try:
async with asyncio.timeout(5.0):
await long_operation()
except TimeoutError:
print("Timeout!")
# 同步原语
class AsyncQueue:
def __init__(self):
self.queue = asyncio.Queue()
async def producer(self):
for i in range(10):
await self.queue.put(i)
await asyncio.sleep(0.1)
async def consumer(self):
while True:
item = await self.queue.get()
print(f"Got: {item}")
self.queue.task_done()
核心差异
| 特性 | Kotlin | Python |
|---|---|---|
| 协程启动 | launch / async |
create_task / gather |
| 挂起函数 | suspend |
async def |
| 挂起点 | delay() |
await asyncio.sleep() |
| 作用域 | CoroutineScope |
TaskGroup (3.11+) |
| 流 | Flow |
AsyncGenerator |
| 调度器 | Dispatchers |
无内置(用 run_in_executor) |
| 取消 | job.cancel() |
task.cancel() |
| 结构化并发 | 原生支持 | 3.11+ 支持 |
2.2 线程模型
Kotlin
kotlin
import kotlinx.coroutines.*
import java.util.concurrent.Executors
// 线程池调度器
val ioDispatcher = Dispatchers.IO
val cpuDispatcher = Dispatchers.Default
val customDispatcher = Executors.newFixedThreadPool(4).asCoroutineDispatcher()
// 切换上下文
suspend fun fetchData(): Data = withContext(Dispatchers.IO) {
apiCall()
}
// 并行分解
suspend fun loadAll(): AllData = coroutineScope {
val user = async { loadUser() }
val posts = async { loadPosts() }
val friends = async { loadFriends() }
AllData(user.await(), posts.await(), friends.await())
}
// 限制并发
suspend fun limitedConcurrency() {
val semaphore = Semaphore(3)
List(10) { index ->
async {
semaphore.acquire()
try {
process(index)
} finally {
semaphore.release()
}
}
}.awaitAll()
}
// 阻塞操作
fun blockingOperation() = runBlocking {
// 阻塞当前线程
}
Python
python
import asyncio
import threading
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
from typing import List
import multiprocessing
# 线程池
def blocking_io():
import time
time.sleep(1)
return "done"
async def run_in_thread():
loop = asyncio.get_event_loop()
result = await loop.run_in_executor(None, blocking_io)
return result
# 自定义线程池
executor = ThreadPoolExecutor(max_workers=4)
async def with_custom_executor():
loop = asyncio.get_event_loop()
result = await loop.run_in_executor(executor, blocking_io)
# 进程池(CPU 密集型)
def cpu_intensive(n):
return sum(i * i for i in range(n))
async def run_cpu_task():
loop = asyncio.get_event_loop()
with ProcessPoolExecutor() as executor:
result = await loop.run_in_executor(
executor,
cpu_intensive,
10_000_000
)
return result
# 并发限制
import asyncio
async def limited_concurrency(tasks: List, limit: int):
semaphore = asyncio.Semaphore(limit)
async def limited_task(task):
async with semaphore:
return await task
return await asyncio.gather(*[limited_task(t) for t in tasks])
# 多线程(非协程)
def threading_example():
results = []
lock = threading.Lock()
def worker(n):
result = n * n
with lock:
results.append(result)
threads = [threading.Thread(target=worker, args=(i,)) for i in range(10)]
for t in threads:
t.start()
for t in threads:
t.join()
# 多进程(绕过 GIL)
def multiprocessing_example():
with multiprocessing.Pool(4) as pool:
results = pool.map(cpu_intensive, [10_000_000] * 4)
return results
核心差异
| 特性 | Kotlin | Python |
|---|---|---|
| 线程模型 | 真正多线程 | GIL 限制(CPU密集需多进程) |
| 线程池 | Dispatchers.IO |
ThreadPoolExecutor |
| 进程池 | 无内置 | ProcessPoolExecutor |
| 阻塞转非阻塞 | withContext |
run_in_executor |
| 并发限制 | Semaphore |
asyncio.Semaphore |
2.3 并发异常处理
Kotlin
kotlin
import kotlinx.coroutines.*
// SupervisorJob: 子协程失败不影响其他
val scope = CoroutineScope(SupervisorJob())
scope.launch {
// 一个失败不影响另一个
launch { mightFail() }
launch { otherTask() }
}
// async 异常处理
suspend fun handleErrors() = coroutineScope {
val deferred = async {
throw RuntimeException("Failed!")
}
try {
deferred.await()
} catch (e: Exception) {
println("Caught: ${e.message}")
}
}
// CoroutineExceptionHandler
val handler = CoroutineExceptionHandler { _, exception ->
println("Caught: $exception")
}
scope.launch(handler) {
throw RuntimeException("Error!")
}
// 结果包装
sealed class Result<out T> {
data class Success<T>(val value: T) : Result<T>()
data class Failure(val error: Throwable) : Result<Nothing>()
}
suspend fun <T> safeCall(block: suspend () -> T): Result<T> = try {
Result.Success(block())
} catch (e: Exception) {
Result.Failure(e)
}
Python
python
import asyncio
from typing import List, Union
from dataclasses import dataclass
# gather 异常处理
async def handle_errors():
try:
results = await asyncio.gather(
might_fail(),
other_task(),
return_exceptions=True # 异常作为结果返回
)
for r in results:
if isinstance(r, Exception):
print(f"Error: {r}")
else:
print(f"Success: {r}")
except Exception as e:
print(f"Outer error: {e}")
# TaskGroup 异常处理 (3.11+)
async def task_group_errors():
try:
async with asyncio.TaskGroup() as tg:
tg.create_task(might_fail())
tg.create_task(other_task())
except ExceptionGroup as eg:
for exc in eg.exceptions:
print(f"Caught: {exc}")
# 结果包装
@dataclass
class Result[T]:
value: T | None = None
error: Exception | None = None
@property
def is_success(self) -> bool:
return self.error is None
async def safe_call(coro) -> Result:
try:
return Result(value=await coro)
except Exception as e:
return Result(error=e)
# 超时 + 异常
async def with_timeout_and_retry(
coro,
timeout: float = 5.0,
retries: int = 3
):
for attempt in range(retries):
try:
async with asyncio.timeout(timeout):
return await coro
except TimeoutError:
if attempt == retries - 1:
raise
await asyncio.sleep(1)
核心差异
| 特性 | Kotlin | Python |
|---|---|---|
| 异常隔离 | SupervisorJob |
return_exceptions=True |
| 异常组 | 无 | ExceptionGroup (3.11+) |
| 全局处理 | CoroutineExceptionHandler |
无 |
| 取消传播 | 自动 | 需显式检查 |
3. 标准库/生态对照
3.1 包管理
Kotlin (Gradle)
kotlin
// build.gradle.kts
plugins {
kotlin("jvm") version "1.9.20"
kotlin("plugin.serialization") version "1.9.20"
}
group = "com.example"
version = "1.0.0"
repositories {
mavenCentral()
google()
}
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0")
testImplementation("org.junit.jupiter:junit-jupiter:5.10.0")
}
// 多平台
kotlin {
jvm()
js()
linuxX64()
}
Python
toml
# pyproject.toml (现代标准)
[project]
name = "my-project"
version = "1.0.0"
description = "A Python project"
requires-python = ">=3.10"
dependencies = [
"httpx>=0.25.0",
"pydantic>=2.0.0",
]
[project.optional-dependencies]
dev = [
"pytest>=7.0.0",
"mypy>=1.0.0",
"ruff>=0.1.0",
]
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
bash
# 包管理命令对照
# Kotlin (Gradle) Python (pip/uv)
./gradlew build pip install -e . / uv pip install -e .
./gradlew test pytest
./gradlew dependencies pip list / pip show <package>
./gradlew clean pip cache purge
uv pip compile pyproject.toml -o requirements.txt
核心差异
| 特性 | Kotlin/Gradle | Python |
|---|---|---|
| 构建工具 | Gradle | 无(pip 只安装) |
| 依赖声明 | build.gradle.kts |
pyproject.toml |
| 锁文件 | gradle.lockfile |
requirements.txt / uv.lock |
| 多平台 | 原生支持 | 需条件依赖 |
| 发布 | Maven Central | PyPI |
3.2 测试框架
Kotlin
kotlin
import org.junit.jupiter.api.*
import org.junit.jupiter.params.*
import org.junit.jupiter.params.provider.*
import io.mockk.*
import kotlinx.coroutines.test.*
import org.amshove.kluent.*
class CalculatorTest {
private lateinit var calc: Calculator
@BeforeEach
fun setup() {
calc = Calculator()
}
@Test
fun `add should return sum`() {
calc.add(1, 2) shouldBe 3
}
@Test
fun `divide by zero should throw`() {
assertThrows<IllegalArgumentException> {
calc.divide(1, 0)
}
}
@ParameterizedTest
@CsvSource("1, 2, 3", "2, 3, 5", "0, 0, 0")
fun `add parameterized`(a: Int, b: Int, expected: Int) {
calc.add(a, b) shouldBe expected
}
@Test
fun `mock example`() = runTest {
val mockApi = mockk<Api>()
every { mockApi.fetch() } returns "data"
val result = mockApi.fetch()
result shouldBe "data"
verify { mockApi.fetch() }
}
@Nested
inner class EdgeCases {
@Test
fun `negative numbers`() {
calc.add(-1, -2) shouldBe -3
}
}
}
Python
python
import pytest
from pytest_mock import MockerFixture
from unittest.mock import Mock, patch
import asyncio
class TestCalculator:
@pytest.fixture
def calc(self):
return Calculator()
def test_add(self, calc):
assert calc.add(1, 2) == 3
def test_divide_by_zero(self, calc):
with pytest.raises(ValueError):
calc.divide(1, 0)
@pytest.mark.parametrize("a,b,expected", [
(1, 2, 3),
(2, 3, 5),
(0, 0, 0),
])
def test_add_parameterized(self, calc, a, b, expected):
assert calc.add(a, b) == expected
def test_mock_example(self, mocker: MockerFixture):
mock_api = mocker.Mock()
mock_api.fetch.return_value = "data"
result = mock_api.fetch()
assert result == "data"
mock_api.fetch.assert_called_once()
class TestEdgeCases:
@pytest.fixture
def calc(self):
return Calculator()
def test_negative_numbers(self, calc):
assert calc.add(-1, -2) == -3
@pytest.mark.asyncio
async def test_async(self):
result = await async_function()
assert result == "expected"
# pytest.ini 配置
"""
[pytest]
asyncio_mode = auto
testpaths = tests
"""
核心差异
| 特性 | Kotlin/JUnit | Python/pytest |
|---|---|---|
| 断言 | shouldBe / assertEquals |
assert |
| 参数化 | @ParameterizedTest |
@pytest.mark.parametrize |
| Mock | MockK | unittest.mock / pytest-mock |
| 异步测试 | runTest |
@pytest.mark.asyncio |
| 嵌套测试 | @Nested |
嵌套类 |
| Fixture | @BeforeEach |
@pytest.fixture |
3.3 常用库对照
| 领域 | Kotlin | Python |
|---|---|---|
| HTTP 客户端 | Ktor, OkHttp, Retrofit | httpx, requests, aiohttp |
| JSON 序列化 | kotlinx.serialization, Gson | orjson, pydantic, msgspec |
| 数据库 | Exposed, Ktorm, Room | SQLAlchemy, Tortoise ORM, DuckDB |
| 依赖注入 | Koin, Dagger, Hilt | dependency-injector, python-inject |
| 配置管理 | hoplite, konf | pydantic-settings, dynaconf |
| 日志 | kotlin-logging, Logback | structlog, loguru |
| 日期时间 | kotlinx-datetime | datetime, pendulum, arrow |
| 函数式 | Arrow Kt | returns, toolz |
| CLI | clikt, kotlinx-cli | click, typer, rich |
| 异步 | kotlinx-coroutines | asyncio, anyio |
| 测试 | JUnit5, Kotest, MockK | pytest, hypothesis, pytest-mock |
| 类型检查 | 编译器 | mypy, pyright |
4. 运行时特性对照
4.1 编译 vs 解释
Kotlin
scss
源代码 (.kt)
↓ kotlinc
字节码 (.class)
↓ JVM
机器码 (JIT编译)
- 编译时检查:类型错误在编译时发现
- JIT 优化:HotSpot JIT 运行时优化
- 启动时间:较慢(JVM 预热)
- 运行速度:快(JIT 优化后接近原生)
Python
scss
源代码 (.py)
↓ CPython 编译器
字节码 (.pyc)
↓ CPython 虚拟机
机器码 (解释执行)
- 运行时检查:类型错误在运行时发现
- 无 JIT:3.13 实验性 JIT(PEP 744)
- 启动时间:快
- 运行速度:慢(纯解释)
性能对比示例
python
# Python - 简单循环
def sum_loop(n):
total = 0
for i in range(n):
total += i
return total
# 耗时约 0.1s (n=10_000_000)
kotlin
// Kotlin - 简单循环
fun sumLoop(n: Int): Long {
var total = 0L
for (i in 0 until n) {
total += i
}
return total
}
// 耗时约 0.01s (n=10_000_000) - 快 10 倍
4.2 内存模型
Kotlin/JVM
线程栈 堆
┌─────────┐ ┌──────────────────┐
│局部变量 │ │ 对象实例 │
│方法帧 │───→│ 数组 │
│操作数栈 │ │ 类元数据 │
└─────────┘ └──────────────────┘
- 对象分配:堆上分配(逃逸分析可栈上分配)
- 内存布局:对象头 + 实例数据 + 对齐填充
- 引用类型:强/软/弱/虚引用
Python
线程栈 堆
┌─────────┐ ┌──────────────────┐
│局部变量 │ │ PyObject │
│帧对象 │───→│ 引用计数 = 2 │
│ │ │ 类型指针 │
└─────────┘ └──────────────────┘
- 对象分配:所有对象堆上分配
- 内存布局:PyObject 头(引用计数 + 类型指针)+ 实例数据
- 引用类型:无分级,靠 GC 处理循环引用
内存占用对比
python
# Python - int 对象
import sys
sys.getsizeof(42) # 28 bytes (64-bit)
sys.getsizeof([1, 2, 3]) # 80 bytes + 元素
kotlin
// Kotlin/JVM - Integer 对象
// 约 16 bytes 对象头 + 4 bytes 数据 + 填充
// 但 JVM 有 Integer 缓存 (-128 to 127)
4.3 垃圾回收
Kotlin/JVM
- 算法:分代 GC(G1, ZGC, Shenandoah)
- 触发:堆满时自动触发
- 暂停:Stop-the-world(现代 GC 毫秒级)
- 调优 :
-Xmx,-XX:+UseG1GC, etc.
Python
- 算法:引用计数 + 循环检测器
- 触发:引用计数归零立即回收
- 暂停:循环检测时有短暂暂停
- 调优 :
gc.disable(),gc.collect()
python
import gc
# 手动控制
gc.disable() # 禁用循环检测
gc.collect() # 手动触发
gc.get_stats() # GC 统计
# 循环引用示例
class Node:
def __init__(self):
self.ref = None
a = Node()
b = Node()
a.ref = b
b.ref = a # 循环引用
del a, b # 引用计数不为 0,需 GC 检测
5. Python 易错代码大全
以下陷阱全部经过实际验证。每个陷阱从Kotlin视角解释"为什么会踩坑"。
5.1 可变默认参数陷阱
Kotlin 开发者最容易犯的错误。Kotlin 中默认参数每次调用都是新实例,Python 不是。
python
# ❌ 错误:所有调用共享同一个列表
def append_to(item, target=[]):
target.append(item)
return target
print(append_to(1)) # [1]
print(append_to(2)) # [1, 2] ← 不是 [2]!
print(append_to(3)) # [1, 2, 3] ← 越来越多
python
# ✅ 正确:每次调用创建新列表
def append_to(item, target=None):
if target is None:
target = []
target.append(item)
return target
print(append_to(1)) # [1]
print(append_to(2)) # [2]
kotlin
// Kotlin 没有这个问题:默认参数每次都是新实例
fun appendTo(item: Int, target: MutableList<Int> = mutableListOf()): MutableList<Int> {
target.add(item)
return target
}
appendTo(1) // [1]
appendTo(2) // [2] ← 每次都是新的
根因 :Python 的 def 是执行语句,默认值在函数定义时求值一次,不是每次调用时。
5.2 闭包变量绑定延迟
循环中创建闭包,Kotlin 会正确捕获每次迭代的值,Python 闭包绑定的是变量名而非值。
python
# ❌ 错误:所有闭包共享同一个变量 i
funcs = []
for i in range(3):
funcs.append(lambda: i)
print([f() for f in funcs]) # [2, 2, 2] ← 全是 2!
python
# ✅ 正确:用默认参数立即绑定当前值
funcs = []
for i in range(3):
funcs.append(lambda i=i: i) # i=i 在定义时求值
print([f() for f in funcs]) # [0, 1, 2]
kotlin
// Kotlin 没有这个问题:lambda 正确捕获每次迭代的值
val funcs = mutableListOf<() -> Int>()
for (i in 0 until 3) {
funcs.add { i }
}
println(funcs.map { it() }) // [0, 1, 2]
根因 :Python 闭包是晚绑定 (late binding),变量 i 在调用时查找,此时循环已结束。
5.3 or 运算符的假值陷阱
Kotlin 的 ?: 只对 null 生效,Python 的 or 对所有假值生效。
python
# ❌ 错误:0 和空字符串被当作"无值"
count = 0
result = count or 42
print(result) # 42 ← 0 被当成假值!
name = ""
display = name or "Anonymous"
print(display) # "Anonymous" ← 空字符串被当成假值!
items = []
total = items or [1, 2, 3]
print(total) # [1, 2, 3] ← 空列表被当成假值!
python
# ✅ 正确:只在 None 时提供默认值
count = 0
result = count if count is not None else 42
print(result) # 0 ← 保留了 0
# 或封装工具函数
from typing import Any
def elvis(value: Any, default: Any) -> Any:
"""模拟 Kotlin 的 ?: 运算符,只对 None 生效"""
return default if value is None else value
print(elvis(0, 42)) # 0
print(elvis("", "default")) # ""
print(elvis(None, 42)) # 42
kotlin
// Kotlin 的 ?: 只对 null 生效
val count = 0
val result = count ?: 42 // 0,不是 42
根因 :Python 的 or 返回第一个"真值",而 0, "", [], {}, False 都是假值。
5.4 == vs is 的身份 vs 相等
Kotlin 的 == 调用 equals(),=== 才比较引用。Python 的 == 调用 __eq__,is 比较身份。
python
# ❌ 错误:用 is 比较值
a = [1, 2, 3]
b = [1, 2, 3]
print(a == b) # True ← 值相等
print(a is b) # False ← 不是同一个对象
# ❌ 错误:用 == 比较 None(虽然能工作但不规范)
x = None
print(x == None) # True(能工作,但不 Pythonic)
python
# ✅ 正确:None 比较用 is
x = None
print(x is None) # True(Pythonic 写法)
# ✅ 正确:值比较用 ==
print(a == b) # True
# ✅ 正确:需要身份比较时用 is
c = a
print(a is c) # True
kotlin
// Kotlin 的区分
val a = listOf(1, 2, 3)
val b = listOf(1, 2, 3)
a == b // true (equals)
a === b // false (引用)
根因 :is 比较的是 id()(内存地址),== 比较的是值。只有 None, True, False 应该用 is。
5.5 整数缓存与身份比较
Python 缓存了小整数(-5 到 256),导致 is 比较在小整数上"碰巧"成立。
python
# ❌ 令人困惑的行为
a = 256
b = 256
print(a is b) # True ← 缓存命中
a = 257
b = 257
print(a is b) # False ← 超出缓存范围!
python
# ✅ 正确:永远用 == 比较整数
a = 257
b = 257
print(a == b) # True ← 值比较,永远正确
kotlin
// Kotlin 没有这个问题:== 始终比较值
val a = 257
val b = 257
a == b // true
a === b // false(但没人用 === 比较基本类型)
根因 :CPython 实现细节,-5 到 256 的整数对象被缓存复用。永远不要用 is 比较整数。
5.6 列表推导式中的变量泄漏(Python 2 遗留)
Python 3 已修复此问题,但了解历史有助于理解 Python 的作用域规则。
python
# Python 3 已修复:推导式有自己的作用域
x = "before"
squares = [x for x in range(5)]
print(x) # "before" ← Python 3 中 x 不被污染
# 但 for 循环仍会泄漏
x = "before"
for x in range(5):
pass
print(x) # 4 ← for 循环的变量泄漏到外部!
python
# ✅ 正确:for 循环后不需要用到循环变量
for x in range(5):
process(x)
# x 在这里仍是 4,不要依赖它
kotlin
// Kotlin 没有这个问题:for 循环变量不会泄漏
var x = "before"
for (i in 0 until 5) {
// i 只在循环内可见
}
println(x) // "before"
根因 :Python 的 for 循环没有独立作用域,循环变量在循环后仍存在。
5.7 self 忘记写
Kotlin 的 this 是隐式的,Python 的 self 必须显式声明。
python
# ❌ 错误:忘记写 self,变成局部变量
class User:
def __init__(self, name, age):
name = name # 局部变量赋值,不是实例属性!
age = age # 同上!
user = User("Alice", 30)
print(user.name) # AttributeError: 'User' object has no attribute 'name'
python
# ✅ 正确:所有实例属性必须加 self
class User:
def __init__(self, name, age):
self.name = name # 实例属性
self.age = age # 实例属性
kotlin
// Kotlin 的 this 是隐式的,不会犯这种错
class User(val name: String, val age: Int)
根因 :Python 的方法就是普通函数,第一个参数 self 是调用时自动传入的实例。不加 self. 就是创建局部变量。
5.8 __init__ 返回值陷阱
Kotlin 的构造函数不能有返回值,Python 的 __init__ 也不能,但 Python 不会在定义时报错。
python
# ❌ 错误:__init__ 返回值会被忽略
class Config:
def __init__(self, path):
self.path = path
return self.load(path) # 返回值被静默忽略!
config = Config("config.json")
print(config) # <Config object>,不是 load() 的返回值
python
# ✅ 正确方案1:用类方法替代构造函数
class Config:
def __init__(self, data: dict):
self.data = data
@classmethod
def from_file(cls, path: str) -> 'Config':
data = cls._load(path)
return cls(data)
@staticmethod
def _load(path: str) -> dict:
# 读取文件逻辑
return {"key": "value"}
config = Config.from_file("config.json")
kotlin
// Kotlin 的 companion object 工厂模式
class Config private constructor(val data: Map<String, Any>) {
companion object {
fun fromFile(path: String): Config {
val data = load(path)
return Config(data)
}
}
}
根因 :__init__ 是初始化方法,不是构造函数。真正的构造函数是 __new__,它负责创建实例。
5.9 字符串拼接性能陷阱
Kotlin 的 StringBuilder 和字符串模板很高效,Python 的 + 拼接在循环中性能极差。
python
# ❌ 错误:循环中用 + 拼接字符串(O(n²))
parts = ["hello", "world", "python", "kotlin"]
result = ""
for part in parts:
result = result + ", " + part # 每次创建新字符串!
python
# ✅ 正确方案1:join(推荐)
result = ", ".join(parts) # O(n),一次分配
# ✅ 正确方案2:f-string(少量拼接时)
name = "World"
greeting = f"Hello, {name}!"
# ✅ 正确方案3:io.StringIO(大量动态拼接)
import io
buffer = io.StringIO()
for part in parts:
buffer.write(part)
buffer.write(", ")
result = buffer.getvalue()
kotlin
// Kotlin 的字符串模板天然高效(编译器用 StringBuilder)
val parts = listOf("hello", "world")
val result = parts.joinToString(", ") // 高效
根因 :Python 字符串是不可变的,+ 每次创建新对象并复制。join() 预计算总长度,一次分配。
5.10 try/except 吞掉 KeyboardInterrupt
Kotlin 的异常层次清晰,Python 的 except Exception 会吞掉 KeyboardInterrupt 以外的所有异常------包括 SystemExit。
python
# ❌ 错误:裸 except 吞掉所有异常,包括 Ctrl+C
try:
while True:
process()
except: # 捕获一切!包括 KeyboardInterrupt, SystemExit
pass # Ctrl+C 无法退出程序!
python
# ✅ 正确:只捕获预期的异常
try:
result = int(user_input)
except ValueError as e:
print(f"无效输入: {e}")
# ✅ 正确:需要捕获多种异常时明确列出
try:
data = json.loads(text)
except (ValueError, KeyError) as e:
print(f"解析失败: {e}")
# ✅ 正确:需要记录未预期异常但不吞掉
try:
risky_operation()
except Exception as e:
logger.exception(f"未预期错误: {e}")
raise # 重新抛出!
kotlin
// Kotlin 的异常层次:只有非致命异常需要捕获
try {
riskyOperation()
} catch (e: NumberFormatException) {
println("解析失败: ${e.message}")
}
根因 :Python 的 except:(无参数)捕获所有异常包括 SystemExit 和 KeyboardInterrupt。永远用 except Exception: 或更具体的异常类型。
5.11 *args 捕获生成器耗尽
Kotlin 的 vararg 传入数组不会改变原数组,Python 的 *args 会消耗生成器。
python
# ❌ 错误:生成器被消耗后无法再次使用
def consume(*args):
print(sum(args))
gen = (x for x in range(5))
consume(*gen) # 10
consume(*gen) # 0 ← 生成器已耗尽!
python
# ✅ 正确:传入列表而非生成器
items = list(range(5)) # 先物化为列表
consume(*items) # 10
consume(*items) # 10 ← 列表可重复使用
# ✅ 正确:或使用 itertools.tee 复制生成器
import itertools
gen = (x for x in range(5))
gen1, gen2 = itertools.tee(gen)
consume(*gen1) # 10
consume(*gen2) # 10
kotlin
// Kotlin 的 vararg 接收数组,不影响原数据
fun consume(vararg args: Int) = args.sum()
val items = intArrayOf(0, 1, 2, 3, 4)
consume(*items) // 10
consume(*items) // 10 ← 数组不受影响
根因 :生成器是迭代器,只能遍历一次。*args 展开时会完全消耗生成器。
5.12 @dataclass 的 __hash__ 陷阱
Kotlin 的 data class 自动生成正确的 hashCode(),Python 的 @dataclass 默认设置 __hash__=None。
python
# ❌ 错误:默认 dataclass 不可哈希
from dataclasses import dataclass
@dataclass
class User:
name: str
age: int
u1 = User("Alice", 30)
u2 = User("Alice", 30)
user_set = {u1, u2} # TypeError: unhashable type: 'User'!
user_dict = {u1: "admin"} # 同样报错!
python
# ✅ 正确方案1:frozen=True(不可变,可哈希)
@dataclass(frozen=True)
class User:
name: str
age: int
u1 = User("Alice", 30)
user_set = {u1} # OK
# ✅ 正确方案2:unsafe_hash=True(可变但可哈希,需自行保证不变性)
@dataclass(unsafe_hash=True)
class User:
name: str
age: int
u1 = User("Alice", 30)
user_set = {u1} # OK,但如果修改 u1.age,set 会出问题
kotlin
// Kotlin 的 data class 自动生成 hashCode
data class User(val name: String, val age: Int)
val u1 = User("Alice", 30)
val set = setOf(u1) // OK
根因 :@dataclass 默认 eq=True,Python 规定 __eq__ 定义后 __hash__ 自动设为 None(防止可变对象放入 set 后被修改导致查找失败)。
5.13 isinstance 与类型的微妙关系
Kotlin 的 is 检查精确类型,Python 的 isinstance 检查继承链。
python
# ❌ 可能不符合预期的行为
print(isinstance(True, int)) # True ← bool 是 int 的子类!
print(isinstance(1, bool)) # False
print(isinstance(True, bool)) # True
# 这会导致类型检查出问题
def process(value: int):
if isinstance(value, bool): # 需要额外检查
print("bool, not int!")
return
print(f"int: {value}")
process(True) # 如果不检查 bool,会被当成 int 处理
python
# ✅ 正确:需要区分 bool 和 int 时
from typing import Union
def process(value: Union[int, bool]):
if isinstance(value, bool):
print(f"bool: {value}")
elif isinstance(value, int):
print(f"int: {value}")
# ✅ 正确:精确类型检查用 type()
print(type(True) is bool) # True
print(type(True) is int) # False
print(type(1) is int) # True
kotlin
// Kotlin 中 Boolean 和 Int 没有继承关系
val b: Boolean = true
b is Int // 编译错误!类型不兼容
根因 :Python 中 bool 是 int 的子类(True == 1, False == 0)。这是历史设计决策。
5.14 dict 修改时遍历崩溃
Kotlin 的 MutableMap 遍历时修改会抛 ConcurrentModificationException,Python 也是但错误信息不够直观。
python
# ❌ 错误:遍历时修改字典
scores = {"Alice": 90, "Bob": 85, "Charlie": 95}
for name in scores:
if scores[name] < 90:
del scores[name] # RuntimeError: dictionary changed size during iteration!
python
# ✅ 正确方案1:遍历副本的键
for name in list(scores.keys()): # list() 创建副本
if scores[name] < 90:
del scores[name]
# ✅ 正确方案2:构建新字典
scores = {name: score for name, score in scores.items() if score >= 90}
# ✅ 正确方案3:先收集要删除的键
to_remove = [name for name, score in scores.items() if score < 90]
for name in to_remove:
del scores[name]
kotlin
// Kotlin 同样不允许
val scores = mutableMapOf("Alice" to 90, "Bob" to 85)
for ((name, _) in scores) {
if (scores[name]!! < 90) {
scores.remove(name) // ConcurrentModificationException
}
}
// 正确:用 scores.toList() 或 filter
val filtered = scores.filter { it.value >= 90 }
5.15 浅拷贝 vs 深拷贝
Kotlin 的 data class 的 copy() 是浅拷贝,Python 的 copy() 也是。但 Kotlin 开发者可能期望"拷贝"是深拷贝。
python
# ❌ 错误:浅拷贝导致嵌套对象共享
from dataclasses import dataclass, replace
@dataclass
class Address:
city: str
@dataclass
class Person:
name: str
address: Address
original = Person("Alice", Address("Beijing"))
copied = replace(original, name="Bob") # 浅拷贝
copied.address.city = "Shanghai"
print(original.address.city) # "Shanghai" ← original 也被改了!
python
# ✅ 正确:需要深拷贝时用 copy.deepcopy
import copy
original = Person("Alice", Address("Beijing"))
copied = copy.deepcopy(original)
copied.address.city = "Shanghai"
print(original.address.city) # "Beijing" ← 不受影响
kotlin
// Kotlin 的 copy() 也是浅拷贝
data class Address(var city: String)
data class Person(val name: String, val address: Address)
val original = Person("Alice", Address("Beijing"))
val copied = original.copy(name = "Bob")
copied.address.city = "Shanghai"
println(original.address.city) // "Shanghai" ← 同样的问题
根因 :copy() / replace() 只复制顶层字段,嵌套对象仍然是同一个引用。Kotlin 和 Python 行为一致,但都容易忘记。
5.16 bool 是 int 的子类
python
# ❌ 令人困惑的算术行为
print(True + True) # 2
print(True * 10) # 10
print(sum([True, False, True])) # 2
print(False == 0) # True
print(True == 1) # True
# ❌ 类型标注无法阻止
from typing import List
def count_items(items: List[int]) -> int:
return sum(items)
count_items([True, False, True]) # 2,不会报类型错误!
python
# ✅ 正确:需要区分时显式检查
def count_items(items: List[int]) -> int:
# 排除 bool
return sum(item for item in items if not isinstance(item, bool))
# ✅ 正确:严格类型检查
def count_items_strict(items: List[int]) -> int:
for item in items:
if isinstance(item, bool):
raise TypeError(f"Expected int, got bool: {item}")
return sum(items)
kotlin
// Kotlin 中 Boolean 和 Int 完全独立
true + true // 编译错误
listOf(true, false).sum() // 编译错误
根因 :Python 历史原因,bool 继承自 int。True 的值就是 1,False 就是 0。
5.17 None 的比较陷阱
python
# ❌ 错误:用 == 比较可能有歧义
class Tricky:
def __eq__(self, other):
return True # 一切都相等!
t = Tricky()
print(t == None) # True ← 不应该!
print(t == 42) # True
print(t == "hi") # True
python
# ✅ 正确:None 检查永远用 is
print(t is None) # False ← 正确
# ✅ 正确:通用空值检查
def is_empty(value) -> bool:
return value is None
kotlin
// Kotlin 的 == 对 null 是安全的
val t: Any? = Tricky()
t == null // false(不会调用 Tricky 的 equals)
t === null // false
根因 :== 调用 __eq__,可以被重载。is 比较身份,无法被重载。None 是单例,is None 永远可靠。
5.18 lambda 在循环中的闭包陷阱
与 5.2 类似,但更常见于回调场景。
python
# ❌ 错误:按钮点击都执行最后一个值
buttons = []
for i in range(3):
button = {"label": f"Button {i}", "action": lambda: print(i)}
buttons.append(button)
for btn in buttons:
btn["action"]()
# 输出:
# 2
# 2
# 2 ← 全是 2!
python
# ✅ 正确:默认参数捕获当前值
for i in range(3):
button = {"label": f"Button {i}", "action": lambda i=i: print(i)}
buttons.append(button)
for btn in buttons:
btn["action"]()
# 输出:
# 0
# 1
# 2
# ✅ 正确:使用 functools.partial
from functools import partial
def print_value(v):
print(v)
for i in range(3):
button = {"label": f"Button {i}", "action": partial(print_value, i)}
buttons.append(button)
kotlin
// Kotlin 捕获的是值(val 是不可变的)
val buttons = mutableListOf<Map<String, Any>>()
for (i in 0 until 3) {
buttons.add(mapOf("label" to "Button $i", "action" to { println(i) }))
}
buttons.forEach { it["action"]() } // 0, 1, 2
5.19 multiprocessing 的 lambda 序列化失败
Kotlin 的线程可以直接传 lambda,Python 的 multiprocessing 需要序列化,lambda 不支持。
python
# ❌ 错误:lambda 无法被 pickle 序列化
from multiprocessing import Process
def task(n):
return sum(i * i for i in range(n))
p = Process(target=lambda: task(1000)) # AttributeError: Can't pickle lambda!
p.start()
python
# ✅ 正确:使用顶层函数
from multiprocessing import Process
def run_task():
result = task(1000)
print(result)
p = Process(target=run_task)
p.start()
p.join()
# ✅ 正确:使用 functools.partial 传参数
from multiprocessing import Process
from functools import partial
p = Process(target=task, args=(1000,))
p.start()
p.join()
kotlin
// Kotlin 线程直接支持 lambda
Thread { task(1000) }.start() // 完全没问题
根因 :multiprocessing 通过 pickle 序列化对象跨进程传递,pickle 只能序列化模块级函数,不能序列化 lambda 和嵌套函数。
5.20 asyncio 中调用同步阻塞函数
Kotlin 的 withContext 可以自动切换调度器,Python 的 asyncio 中直接调用阻塞函数会冻结事件循环。
python
# ❌ 错误:在协程中直接调用阻塞函数
import asyncio
import time
async def fetch_data():
time.sleep(2) # ← 阻塞整个事件循环!所有协程都卡住
return "data"
async def main():
# 3 个任务"并行",但实际串行,每个 2 秒,总共 6 秒
results = await asyncio.gather(
fetch_data(),
fetch_data(),
fetch_data()
)
return results
asyncio.run(main()) # 耗时 6 秒,不是 2 秒!
python
# ✅ 正确:用 run_in_executor 在线程池中运行阻塞函数
import asyncio
import time
from concurrent.futures import ThreadPoolExecutor
executor = ThreadPoolExecutor(max_workers=4)
async def fetch_data():
loop = asyncio.get_event_loop()
result = await loop.run_in_executor(executor, time.sleep, 2)
return "data"
async def main():
# 真正并行,总共约 2 秒
results = await asyncio.gather(
fetch_data(),
fetch_data(),
fetch_data()
)
return results
asyncio.run(main()) # 耗时约 2 秒
kotlin
// Kotlin 切换调度器很简单
suspend fun fetchData(): String = withContext(Dispatchers.IO) {
Thread.sleep(2000) // 不阻塞主线程
"data"
}
// 并行执行
suspend fun main() {
val results = listOf(
async { fetchData() },
async { fetchData() },
async { fetchData() }
).awaitAll() // 约 2 秒
}
根因 :asyncio 是单线程事件循环,阻塞调用会冻结整个循环。必须用 run_in_executor 把阻塞操作放到线程池。
6. 快速参考表
语法速查
| 概念 | Kotlin | Python |
|---|---|---|
| 不可变变量 | val x = 1 |
x = 1(约定) |
| 可变变量 | var x = 1 |
x = 1 |
| 空类型 | String? |
Optional[str] |
| 安全调用 | obj?.method() |
obj.method() if obj else None |
| Elvis | x ?: default |
x or default(注意 0/False) |
| 字符串模板 | "$name ${expr}" |
f"{name} {expr}" |
| 多行字符串 | """...""" |
"""...""" |
| 原始字符串 | 无 | r"..." |
| 范围 | 1..10, 1 until 10 |
range(1, 11), range(1, 10) |
| 列表 | listOf(1, 2, 3) |
[1, 2, 3] |
| Map | mapOf("a" to 1) |
{"a": 1} |
| 解构 | val (a, b) = pair |
a, b = tuple |
| when | when (x) { ... } |
match x: (3.10+) |
| 扩展函数 | fun String.f() = ... |
无 |
| 运算符重载 | operator fun plus() |
__add__ |
并发速查
| 概念 | Kotlin | Python |
|---|---|---|
| 挂起函数 | suspend fun |
async def |
| 启动协程 | launch { } |
asyncio.create_task() |
| 异步结果 | async { }.await() |
await coro |
| 延迟 | delay(ms) |
await asyncio.sleep(s) |
| 并发执行 | async { } + awaitAll() |
asyncio.gather() |
| 切换线程 | withContext(Dispatchers.IO) |
run_in_executor() |
| 流 | Flow<T> |
AsyncGenerator[T] |
| 取消 | job.cancel() |
task.cancel() |
类型系统速查
| 概念 | Kotlin | Python |
|---|---|---|
| 泛型 | class Box<T> |
class Box(Generic[T]) |
| 协变 | out T |
TypeVar(covariant=True) |
| 逆变 | in T |
TypeVar(contravariant=True) |
| 类型约束 | <T : Upper> |
bound=Upper |
| 联合类型 | 密封类 | Union[A, B] / `A |
| 交叉类型 | where T : A, T : B |
Protocol 组合 |
| 类型别名 | typealias Name = Type |
Name: TypeAlias = Type |
总结
从 Kotlin 转向 Python,核心思维转变:
- 类型系统:编译时 → 运行时,显式 → 隐式
- 空安全:语言级 → 约定 + Optional
- 并发:协程原生支持 → asyncio 库
- 扩展:扩展函数 → 独立函数
- 性能:JVM JIT → 解释执行(无 JIT)
- 工具链:Gradle 全功能 → pip + pyproject.toml
Python 优势 :简洁、快速原型、丰富生态(AI/ML/数据) Kotlin 优势:类型安全、性能、多平台、工具链成熟