Kotlin vs Python 知识点对照表

18 阅读23分钟

Kotlin vs Python 知识点对照表

面向精通Kotlin的开发者,快速掌握Python核心知识

目录

  1. 语法核心对照
    • 1.1 变量与类型声明
    • 1.2 函数定义
    • 1.3 类与对象
    • 1.4 泛型系统
    • 1.5 类型系统进阶
    • 1.6 空安全处理
    • 1.7 集合操作
    • 1.8 扩展函数与运算符重载
  2. 并发模型对照
    • 2.1 协程 vs asyncio
    • 2.2 线程模型
    • 2.3 异常处理
  3. 标准库/生态对照
    • 3.1 包管理
    • 3.2 测试框架
    • 3.3 常用库对照
  4. 运行时特性对照
    • 4.1 编译 vs 解释
    • 4.2 内存模型
    • 4.3 垃圾回收
  5. Python 易错代码大全
    • 5.1 可变默认参数陷阱
    • 5.2 闭包变量绑定延迟
    • 5.3 or 运算符的假值陷阱
    • 5.4 == vs is 的身份 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 boolint 的子类
    • 5.17 None 的比较陷阱
    • 5.18 lambda 在循环中的闭包陷阱
    • 5.19 multiprocessing 的 lambda 序列化失败
    • 5.20 asyncio 中调用同步阻塞函数
  6. 快速参考表

1. 语法核心对照

1.1 变量与类型声明

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 没有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
核心差异
特性KotlinPython
不可变性val 编译时强制约定,无强制
类型注解必须或推断完全可选
类型检查编译时运行时
延迟初始化lateinit / by lazy@property__getattr__

1.2 函数定义

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
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]
核心差异
特性KotlinPython
单表达式函数fun f() = exprlambda(受限)
默认参数支持支持
命名参数支持支持
可变参数vararg*args, **kwargs
扩展函数原生支持无(用独立函数)
Lambda多行支持仅单表达式

1.3 类与对象

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
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
核心差异
特性KotlinPython
构造函数主构造函数 + init__init__
数据类data class@dataclass
密封类sealed classUnion + 模式匹配
单例object模块级变量或 __new__
静态成员companion object@staticmethod / @classmethod
接口interfaceProtocolABC
访问控制public/private/protected约定 _ / __

1.4 泛型系统

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
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
核心差异
特性KotlinPython
泛型声明<T>TypeVar('T')T = TypeVar('T')
类型约束<T : UpperBound>bound=...
协变out Tcovariant=True
逆变in Tcontravariant=True
星投影*Any
具体化reified运行时天然支持
类型擦除JVM擦除运行时保留

1.5 类型系统进阶

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
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"]
核心差异
特性KotlinPython
类型别名typealiasTypeAliastype
值类型value classNewType(弱)
可空类型T?Optional[T]T | None
智能转换自动isinstance
联合类型密封类Union / Literal
类型检查编译时运行时 + mypy

1.6 空安全处理

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
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, "不能为空")
核心差异
特性KotlinPython说明
可空声明T?Optional[T]Kotlin 编译时强制
安全调用?.无语法糖Python 需显式检查
默认值?:or / if elsePython or 有陷阱
非空断言!!Python 直接抛异常
安全转换as?try/exceptPython 需异常处理

1.7 集合操作

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
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
核心差异
特性KotlinPython
不可变集合List / Settuple / frozenset
惰性求值Sequence生成器 / itertools
链式调用流畅 API需嵌套或中间变量
推导式[] / {} 推导式
集合运算方法名运算符 `& -`

1.8 扩展函数与运算符重载

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
# 扩展函数(无原生支持,用独立函数)
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__
"""
核心差异
特性KotlinPython
扩展函数原生支持无(用独立函数)
扩展属性支持
运算符数量有限集合更丰富
解构声明operator fun componentN()__iter____getitem__
调用运算符operator fun invoke()__call__

2. 并发模型对照

2.1 协程 vs asyncio

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
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()
核心差异
特性KotlinPython
协程启动launch / asynccreate_task / gather
挂起函数suspendasync def
挂起点delay()await asyncio.sleep()
作用域CoroutineScopeTaskGroup (3.11+)
FlowAsyncGenerator
调度器Dispatchers无内置(用 run_in_executor
取消job.cancel()task.cancel()
结构化并发原生支持3.11+ 支持

2.2 线程模型

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
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
核心差异
特性KotlinPython
线程模型真正多线程GIL 限制(CPU密集需多进程)
线程池Dispatchers.IOThreadPoolExecutor
进程池无内置ProcessPoolExecutor
阻塞转非阻塞withContextrun_in_executor
并发限制Semaphoreasyncio.Semaphore

2.3 并发异常处理

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
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)
核心差异
特性KotlinPython
异常隔离SupervisorJobreturn_exceptions=True
异常组ExceptionGroup (3.11+)
全局处理CoroutineExceptionHandler
取消传播自动需显式检查

3. 标准库/生态对照

3.1 包管理

Kotlin (Gradle)
// 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
# 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"
# 包管理命令对照
# 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/GradlePython
构建工具Gradle无(pip 只安装)
依赖声明build.gradle.ktspyproject.toml
锁文件gradle.lockfilerequirements.txt / uv.lock
多平台原生支持需条件依赖
发布Maven CentralPyPI

3.2 测试框架

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
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/JUnitPython/pytest
断言shouldBe / assertEqualsassert
参数化@ParameterizedTest@pytest.mark.parametrize
MockMockKunittest.mock / pytest-mock
异步测试runTest@pytest.mark.asyncio
嵌套测试@Nested嵌套类
Fixture@BeforeEach@pytest.fixture

3.3 常用库对照

领域KotlinPython
HTTP 客户端Ktor, OkHttp, Retrofithttpx, requests, aiohttp
JSON 序列化kotlinx.serialization, Gsonorjson, pydantic, msgspec
数据库Exposed, Ktorm, RoomSQLAlchemy, Tortoise ORM, DuckDB
依赖注入Koin, Dagger, Hiltdependency-injector, python-inject
配置管理hoplite, konfpydantic-settings, dynaconf
日志kotlin-logging, Logbackstructlog, loguru
日期时间kotlinx-datetimedatetime, pendulum, arrow
函数式Arrow Ktreturns, toolz
CLIclikt, kotlinx-cliclick, typer, rich
异步kotlinx-coroutinesasyncio, anyio
测试JUnit5, Kotest, MockKpytest, hypothesis, pytest-mock
类型检查编译器mypy, pyright

4. 运行时特性对照

4.1 编译 vs 解释

Kotlin
源代码 (.kt)
    ↓ kotlinc
字节码 (.class)
    ↓ JVM
机器码 (JIT编译)
  • 编译时检查:类型错误在编译时发现
  • JIT 优化:HotSpot JIT 运行时优化
  • 启动时间:较慢(JVM 预热)
  • 运行速度:快(JIT 优化后接近原生)
Python
源代码 (.py)
    ↓ CPython 编译器
字节码 (.pyc)
    ↓ CPython 虚拟机
机器码 (解释执行)
  • 运行时检查:类型错误在运行时发现
  • 无 JIT:3.13 实验性 JIT(PEP 744)
  • 启动时间:快
  • 运行速度:慢(纯解释)
性能对比示例
# Python - 简单循环
def sum_loop(n):
    total = 0
    for i in range(n):
        total += i
    return total

# 耗时约 0.1s (n=10_000_000)
// 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 - int 对象
import sys
sys.getsizeof(42)  # 28 bytes (64-bit)
sys.getsizeof([1, 2, 3])  # 80 bytes + 元素
// 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()
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 不是。

# ❌ 错误:所有调用共享同一个列表
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]  ← 越来越多
# ✅ 正确:每次调用创建新列表
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 没有这个问题:默认参数每次都是新实例
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 闭包绑定的是变量名而非值。

# ❌ 错误:所有闭包共享同一个变量 i
funcs = []
for i in range(3):
    funcs.append(lambda: i)

print([f() for f in funcs])  # [2, 2, 2]  ← 全是 2!
# ✅ 正确:用默认参数立即绑定当前值
funcs = []
for i in range(3):
    funcs.append(lambda i=i: i)  # i=i 在定义时求值

print([f() for f in funcs])  # [0, 1, 2]
// 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 对所有假值生效。

# ❌ 错误: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]  ← 空列表被当成假值!
# ✅ 正确:只在 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 的 ?: 只对 null 生效
val count = 0
val result = count ?: 42  // 0,不是 42

根因:Python 的 or 返回第一个"真值",而 0, "", [], {}, False 都是假值。


5.4 == vs is 的身份 vs 相等

Kotlin 的 == 调用 equals()=== 才比较引用。Python 的 == 调用 __eq__is 比较身份。

# ❌ 错误:用 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)
# ✅ 正确:None 比较用 is
x = None
print(x is None)  # True(Pythonic 写法)

# ✅ 正确:值比较用 ==
print(a == b)  # True

# ✅ 正确:需要身份比较时用 is
c = a
print(a is c)  # True
// 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 比较在小整数上"碰巧"成立。

# ❌ 令人困惑的行为
a = 256
b = 256
print(a is b)  # True  ← 缓存命中

a = 257
b = 257
print(a is b)  # False ← 超出缓存范围!
# ✅ 正确:永远用 == 比较整数
a = 257
b = 257
print(a == b)  # True  ← 值比较,永远正确
// Kotlin 没有这个问题:== 始终比较值
val a = 257
val b = 257
a == b  // true
a === b // false(但没人用 === 比较基本类型)

根因:CPython 实现细节,-5256 的整数对象被缓存复用。永远不要用 is 比较整数


5.6 列表推导式中的变量泄漏(Python 2 遗留)

Python 3 已修复此问题,但了解历史有助于理解 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 循环的变量泄漏到外部!
# ✅ 正确:for 循环后不需要用到循环变量
for x in range(5):
    process(x)
# x 在这里仍是 4,不要依赖它
// Kotlin 没有这个问题:for 循环变量不会泄漏
var x = "before"
for (i in 0 until 5) {
    // i 只在循环内可见
}
println(x)  // "before"

根因:Python 的 for 循环没有独立作用域,循环变量在循环后仍存在。


5.7 self 忘记写

Kotlin 的 this 是隐式的,Python 的 self 必须显式声明。

# ❌ 错误:忘记写 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'
# ✅ 正确:所有实例属性必须加 self
class User:
    def __init__(self, name, age):
        self.name = name  # 实例属性
        self.age = age    # 实例属性
// Kotlin 的 this 是隐式的,不会犯这种错
class User(val name: String, val age: Int)

根因:Python 的方法就是普通函数,第一个参数 self 是调用时自动传入的实例。不加 self. 就是创建局部变量。


5.8 __init__ 返回值陷阱

Kotlin 的构造函数不能有返回值,Python 的 __init__ 也不能,但 Python 不会在定义时报错。

# ❌ 错误:__init__ 返回值会被忽略
class Config:
    def __init__(self, path):
        self.path = path
        return self.load(path)  # 返回值被静默忽略!

config = Config("config.json")
print(config)  # <Config object>,不是 load() 的返回值
# ✅ 正确方案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 的 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 的 + 拼接在循环中性能极差。

# ❌ 错误:循环中用 + 拼接字符串(O(n²))
parts = ["hello", "world", "python", "kotlin"]
result = ""
for part in parts:
    result = result + ", " + part  # 每次创建新字符串!
# ✅ 正确方案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 的字符串模板天然高效(编译器用 StringBuilder)
val parts = listOf("hello", "world")
val result = parts.joinToString(", ")  // 高效

根因:Python 字符串是不可变的,+ 每次创建新对象并复制。join() 预计算总长度,一次分配。


5.10 try/except 吞掉 KeyboardInterrupt

Kotlin 的异常层次清晰,Python 的 except Exception 会吞掉 KeyboardInterrupt 以外的所有异常——包括 SystemExit

# ❌ 错误:裸 except 吞掉所有异常,包括 Ctrl+C
try:
    while True:
        process()
except:  # 捕获一切!包括 KeyboardInterrupt, SystemExit
    pass   # Ctrl+C 无法退出程序!
# ✅ 正确:只捕获预期的异常
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 的异常层次:只有非致命异常需要捕获
try {
    riskyOperation()
} catch (e: NumberFormatException) {
    println("解析失败: ${e.message}")
}

根因:Python 的 except:(无参数)捕获所有异常包括 SystemExitKeyboardInterrupt。永远用 except Exception: 或更具体的异常类型。


5.11 *args 捕获生成器耗尽

Kotlin 的 vararg 传入数组不会改变原数组,Python 的 *args 会消耗生成器。

# ❌ 错误:生成器被消耗后无法再次使用
def consume(*args):
    print(sum(args))

gen = (x for x in range(5))
consume(*gen)  # 10
consume(*gen)  # 0 ← 生成器已耗尽!
# ✅ 正确:传入列表而非生成器
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 的 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

# ❌ 错误:默认 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"}  # 同样报错!
# ✅ 正确方案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 的 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 检查继承链。

# ❌ 可能不符合预期的行为
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 处理
# ✅ 正确:需要区分 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 中 Boolean 和 Int 没有继承关系
val b: Boolean = true
b is Int  // 编译错误!类型不兼容

根因:Python 中 boolint 的子类(True == 1, False == 0)。这是历史设计决策。


5.14 dict 修改时遍历崩溃

Kotlin 的 MutableMap 遍历时修改会抛 ConcurrentModificationException,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!
# ✅ 正确方案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 同样不允许
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 classcopy() 是浅拷贝,Python 的 copy() 也是。但 Kotlin 开发者可能期望"拷贝"是深拷贝。

# ❌ 错误:浅拷贝导致嵌套对象共享
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 也被改了!
# ✅ 正确:需要深拷贝时用 copy.deepcopy
import copy

original = Person("Alice", Address("Beijing"))
copied = copy.deepcopy(original)

copied.address.city = "Shanghai"
print(original.address.city)  # "Beijing" ← 不受影响
// 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 boolint 的子类

# ❌ 令人困惑的算术行为
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,不会报类型错误!
# ✅ 正确:需要区分时显式检查
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 中 Boolean 和 Int 完全独立
true + true  // 编译错误
listOf(true, false).sum()  // 编译错误

根因:Python 历史原因,bool 继承自 intTrue 的值就是 1False 就是 0


5.17 None 的比较陷阱

# ❌ 错误:用 == 比较可能有歧义
class Tricky:
    def __eq__(self, other):
        return True  # 一切都相等!

t = Tricky()
print(t == None)  # True ← 不应该!
print(t == 42)    # True
print(t == "hi")  # True
# ✅ 正确:None 检查永远用 is
print(t is None)  # False ← 正确

# ✅ 正确:通用空值检查
def is_empty(value) -> bool:
    return value is None
// Kotlin 的 == 对 null 是安全的
val t: Any? = Tricky()
t == null  // false(不会调用 Tricky 的 equals)
t === null // false

根因== 调用 __eq__,可以被重载。is 比较身份,无法被重载。None 是单例,is None 永远可靠。


5.18 lambda 在循环中的闭包陷阱

与 5.2 类似,但更常见于回调场景。

# ❌ 错误:按钮点击都执行最后一个值
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!
# ✅ 正确:默认参数捕获当前值
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 捕获的是值(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 不支持。

# ❌ 错误: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()
# ✅ 正确:使用顶层函数
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 线程直接支持 lambda
Thread { task(1000) }.start()  // 完全没问题

根因multiprocessing 通过 pickle 序列化对象跨进程传递,pickle 只能序列化模块级函数,不能序列化 lambda 和嵌套函数。


5.20 asyncio 中调用同步阻塞函数

Kotlin 的 withContext 可以自动切换调度器,Python 的 asyncio 中直接调用阻塞函数会冻结事件循环。

# ❌ 错误:在协程中直接调用阻塞函数
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 秒!
# ✅ 正确:用 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 切换调度器很简单
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. 快速参考表

语法速查

概念KotlinPython
不可变变量val x = 1x = 1(约定)
可变变量var x = 1x = 1
空类型String?Optional[str]
安全调用obj?.method()obj.method() if obj else None
Elvisx ?: defaultx or default(注意 0/False)
字符串模板"$name ${expr}"f"{name} {expr}"
多行字符串"""...""""""..."""
原始字符串r"..."
范围1..10, 1 until 10range(1, 11), range(1, 10)
列表listOf(1, 2, 3)[1, 2, 3]
MapmapOf("a" to 1){"a": 1}
解构val (a, b) = paira, b = tuple
whenwhen (x) { ... }match x: (3.10+)
扩展函数fun String.f() = ...
运算符重载operator fun plus()__add__

并发速查

概念KotlinPython
挂起函数suspend funasync 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()

类型系统速查

概念KotlinPython
泛型class Box<T>class Box(Generic[T])
协变out TTypeVar(covariant=True)
逆变in TTypeVar(contravariant=True)
类型约束<T : Upper>bound=Upper
联合类型密封类Union[A, B] / A | B
交叉类型where T : A, T : BProtocol 组合
类型别名typealias Name = TypeName: TypeAlias = Type

总结

从 Kotlin 转向 Python,核心思维转变:

  1. 类型系统:编译时 → 运行时,显式 → 隐式
  2. 空安全:语言级 → 约定 + Optional
  3. 并发:协程原生支持 → asyncio 库
  4. 扩展:扩展函数 → 独立函数
  5. 性能:JVM JIT → 解释执行(无 JIT)
  6. 工具链:Gradle 全功能 → pip + pyproject.toml

Python 优势:简洁、快速原型、丰富生态(AI/ML/数据) Kotlin 优势:类型安全、性能、多平台、工具链成熟