Skip to content
📖 Auto 版 Think Python本书目录

Python 附加特性 ​

前面的章节介绍了 Python 的核心特性(以 Auto 语言表达)。但 Python 还有很多有用且值得了解的附加特性。本章介绍其中的一部分。

集合 ​

集合(set)是一个无序且不包含重复元素的集合。Auto 通过标准库提供 HashSet。

创建和使用 HashSet

工作原理

在 Auto 中,HashSet 从 std::collections 导入。你可以从列表字面量创建 HashSet —— 重复值会自动被去除。add 和 remove 方法原地修改集合。集合运算如并集(|)、交集(&)、差集(-)和对称差集(^)在 Auto 和 Python 中的使用方式完全相同。

Python 程序员注意:

Auto 使用带显式类型参数的 HashSet<str>,而 Python 使用内置的 set 类型。Auto 的 HashSet 需要从 std::collections 导入,但操作方式完全相同。

集合对于去除集合中的重复元素和高效检查成员关系非常有用。集合的 in 操作符通常比列表更快,因为集合内部使用哈希表实现。

计数器和 defaultdict ​

Python 的 collections 模块提供了 Counter 和 defaultdict,它们是字典的便捷封装。在 Auto 中,你可以使用普通字典和辅助函数达到相同的效果。

列表推导和计数模式

工作原理

Auto 没有列表推导式。取而代之的是使用显式的 for 循环配合 append。a2p 转译器生成的 Python 代码也使用 for 循环而非推导式,有些人可能觉得这样更易读。

对于计数,Auto 使用 HashMap.get(key, default) 模式,而非 Python 的 Counter。对于分组(defaultdict 模式),你需要先检查键是否存在,如果不存在则初始化。

Python 程序员注意:

Auto 显式使用 HashMap 而非 Python 的 dict。a2p 转译器将 Auto 的 HashMap<K, V> 转换为 Python 的 dict。虽然 Python 有 Counter 和 defaultdict 作为便捷工具,但 Auto 只需要多写几行显式代码就能达到相同效果。

条件表达式 ​

Python 有条件表达式(也称为"三元运算符"),允许你在单个表达式中编写 if/else。Auto 支持相同的模式。

auto
let x = 5
let label = if x < 10 { "low" } else { "high" }
print(label)  // low

Python 中的等价写法:

python
x = 5
label = "low" if x < 10 else "high"
print(label)  # low

条件表达式通常比 if 语句更短,但不一定更容易阅读。当逻辑简单且表达式较短时,使用条件表达式比较合适。

命名元组 ​

命名元组(named tuple)是一种每个元素都有名称的元组。当你想要一个带有命名属性的简单对象,但不需要类的完整功能时,命名元组非常有用。

在 Auto 中,你可以通过 type 定义来达到相同的效果,这更加明确并提供了相同的好处。

使用 Auto type 定义实现命名元组

工作原理

在 Auto 中,type 定义起到与 Python 的 namedtuple 相同的作用。两者都提供带有命名属性的对象。Auto 的 type 更加灵活 —— 你可以添加方法、使用默认值,以及定义自定义行为。

a2p 转译器将 Auto 的 type 定义转换为 Python 类,并根据需要生成 __init__、__eq__ 和比较方法。

Python 程序员注意:

Python 的 namedtuple 是轻量级且不可变的。Auto 的 type 也是轻量级的,但默认是可变的。如果你想要不可变性,请对字段使用 let。a2p 转译器生成的是 Python 类而非 namedtuple 实例,这让你对行为有更多控制。

any 和 all ​

Python 提供了内置函数 any 和 all,它们接受一个可迭代的布尔值序列并返回单个布尔结果。

  • any 如果至少有一个元素为真,则返回 true。
  • all 如果所有元素都为真,则返回 true。

在 Auto 中,你可以从标准库使用这些函数,或者用循环自行实现逻辑。

条件表达式、any 和 all

工作原理

Auto 的条件表达式语法是 if condition { value1 } else { value2 },类似于 Python 的 value1 if condition else value2,但条件放在前面(像 if 语句一样)。对于链式条件,Auto 自然地嵌套表达式。

any 和 all 函数在 Auto 和 Python 中的工作方式相同。它们接受一个可迭代对象并返回一个布尔值。在 Auto 中,当需要提前终止(如 break)时,你使用显式循环而非生成器表达式。

Python 程序员注意:

Python 的条件表达式将值放在前面:x if condition else y。Auto 将条件放在前面:if condition { x } else { y }。Python 的生成器表达式(如 any(x &gt; 0 for x in numbers))没有直接的 Auto 等价写法 —— 请使用显式循环。

调试 ​

当你使用集合、字典和其他集合类型时,有一些常见的错误来源:

可变默认参数: 在 Python 中,使用可变对象(如列表或字典)作为默认参数可能会导致意外行为,因为同一个对象在所有调用之间共享。在 Auto 中,默认值每次都会重新求值,因此这不是问题。

集合/字典键类型: 只有不可变类型才能用作字典的键或集合的元素。在 Python 中,这意味着字符串、数字和由不可变对象组成的元组。Auto 遵循相同的规则 —— 你不能将列表用作字典的键。

迭代时修改: 在迭代集合时修改它可能会导致错误或意外行为。如果你需要在迭代期间修改集合,请迭代一个副本。

auto
// 错误:在迭代时修改列表
let mut items = [1, 2, 3, 4, 5]
for item in items {
    if item == 3 {
        items.remove(item)  // 未定义行为!
    }
}

// 正确:收集要删除的元素,然后删除它们
let mut items = [1, 2, 3, 4, 5]
let mut to_remove: [int] = []
for item in items {
    if item == 3 {
        to_remove.append(item)
    }
}
for item in to_remove {
    items.remove(item)
}

术语表 ​

集合(set): 一个无序的唯一元素集合。在 Auto 中由 HashSet 表示。

HashSet: Auto 的集合类型,从 std::collections 导入。

集合运算: 如并集(|)、交集(&)、差集(-)和对称差集(^)等组合集合的运算。

计数器(Counter): 一个将元素映射到其出现次数的字典。在 Python 中由 collections.Counter 提供。在 Auto 中使用普通的 HashMap 实现。

defaultdict: 一个为缺失键提供默认值的字典。在 Python 中由 collections.defaultdict 提供。在 Auto 中通过显式键检查实现。

列表推导式(list comprehension): 一种 Python 表达式,通过对可迭代对象的每个元素应用表达式来创建列表,可选择按条件过滤。Auto 使用显式的 for 循环代替。

条件表达式(conditional expression): 根据布尔条件返回两个值之一表达式。也称为"三元运算符"。

命名元组(named tuple): 每个元素都有名称的元组。在 Auto 中通过 type 定义实现。

any: 如果可迭代对象中至少有一个元素为真则返回 true 的函数。

all: 如果可迭代对象中所有元素都为真则返回 true 的函数。

练习 ​

练习 1 ​

编写一个名为 has_duplicates 的函数,接受一个列表,如果任何元素出现超过一次则返回 true。它不应修改原始列表。

练习 2 ​

编写一个名为 word_frequency 的函数,接受一个字符串,返回一个将每个单词映射到其出现次数的字典。在计数前将字符串转换为小写并去除标点。

练习 3 ​

编写一个名为 unique_words 的函数,接受一个单词列表,返回按字母顺序排列的唯一单词列表,使用 HashSet。

练习 4 ​

Python 的 dict 有一个名为 setdefault 的方法,仅在键不存在时才设置字典中的值。在 Auto 中的等价写法是:

auto
let mut d: HashMap<str, [int]> = {}
// 代替 d.setdefault(key, []).append(value):
if key not in d {
    d[key] = []
}
d[key].append(value)

使用此模式编写一个名为 invert_dict 的函数,接受一个字典并返回一个键值互换的新字典。如果原始字典有重复的值,反转后的字典应将每个值映射到一个键的列表。

基于 MIT 许可发布。