Clojure

列表在Clojure中有特殊地位,因为代码本身就是由列表构成的:

;; 列表会被求值为函数调用
(+ 1 2) ; => 3 (列表被求值为函数调用)

;; 向量不会被求值为函数调用
[+ 1 2] ; => [#<core$_PLUS_ clojure.core$_PLUS_@...> 1 2]
  • 当需要表示代码或进行函数调用时,使用列表
  • 当需要存储数据或频繁按索引访问时,使用向量
  • 当需要频繁在头部添加元素时,使用列表
  • 当需要频繁在尾部添加元素时,使用向量

One common need is an anonymous function that takes an element and wraps it in a vector. You might try writing that as:

<em>;; DO NOT DO THIS</em>
#([%])

This anonymous function expands to the equivalent:

(fn [x] ([x]))

This form will wrap in a vector and try to invoke the vector with no arguments (the extra pair of parentheses). Instead:

<em>;; Instead do this:</em>
#(vector %)

<em>;; or this:</em>
(fn [x] [x])

<em>;; or most simply just the vector function itself:</em>
vector

Iterables vs. Iterators vs. Generators

容器 (Container)​

  • 定义​:存储元素并支持成员测试 (in / not in) 的数据结构,通常将所有元素保存在内存中。
  • 特点​:对象必须是实体化的数据结构。
  • 常见类型​:
# 列表 (List)
assert 1 in [1, 2, 3]

# 集合 (Set)
assert 1 in {1, 2, 3}

# 元组 (Tuple)
assert 1 in (1, 2, 3)

# 字典 (Dict) 测试键
d = {1: 'a', 2: 'b'}
assert 1 in d           # True
assert 'a' not in d     # True

# 字符串 (String) 测试子串
s = 'hello'
assert 'he' in s       # True
  • 关键点​:
    • 容器 ≠ 迭代能力(如 Bloom Filter 是容器但不可迭代)。
    • 成员测试针对数据结构特性(字典测键、字符串测子串)。

可迭代对象 (Iterable)​

  • 定义​:能返回迭代器的任意对象(不限于数据结构)。可通过 iter() 获取其迭代器。
  • 特点​:可表示有限或无限数据流(如文件、网络流)。
  • 示例​:
x = [1, 2, 3]      # 列表是可迭代对象
y = iter(x)         # 获取迭代器
print(next(y))      # 1 (迭代器保存状态)
  • 底层机制​:
# for 循环的等效操作
x = [1, 2, 3]
iterator = iter(x)  # 获取迭代器
while True:
    try:
        elem = next(iterator)  # 依次获取元素
    except StopIteration:
        break

迭代器 (Iterator)​

  • 定义​:带有状态的对象,通过 __next__() 方法逐个返回值。
  • 特点​:
    • 惰性求值:调用 next() 时才计算/返回数据。
    • 消耗性:遍历后不可重置(需重新创建迭代器)。
  • 示例​:
from itertools import count, cycle, islice

# 无限迭代器
counter = count(start=10)
print(next(counter))  # 10

# 有限迭代器从无限序列截取
colors = cycle(['red', 'blue'])
limited = islice(colors, 0, 3)  # ['red', 'blue', 'red']

生成器 (Generator)​

  • 定义​:通过 yield 创建的迭代器,无需手动实现 __next__()
  • 特点​:语法简洁,自动保存执行状态。
  • 生成器函数示例(斐波那契数列)​
def fib():
    prev, curr = 0, 1
    while True:
        yield curr
        prev, curr = curr, prev + curr

f = fib()
print(list(islice(f, 0, 5)))  # [1, 1, 2, 3, 5]

f = fib() 不执行代码,调用 next(f) 时运行到 yield 暂停。


生成器表达式 (Generator Expression)​

  • 定义​:类似列表推导的惰性版本,语法为 (expr for item in iterable)
  • 特点​:节省内存,一次产生一个值。
  • 示例​:
numbers = [1, 2, 3]
lazy_squares = (x*x for x in numbers)  # 生成器对象

print(next(lazy_squares))  # 1
print(list(lazy_squares))  # [4, 9](状态已推进

推导式 (Comprehension)​

  • 定义​:快速构建容器(列表/集合/字典)的语法。
  • 特点​:立即求值,直接生成内存数据结构。
  • 常见类型​:
# 列表推导式
[x*x for x in [1, 2, 3]]          # → [1, 4, 9]

# 集合推导式
{x*x for x in [1, 2, 3]}           # → {1, 4, 9}无序

# 字典推导式
{x: x*x for x in [1, 2, 3]}        # → {1:1, 2:4, 3:9}
  • 与生成器表达式对比​:​推导式​​生成器表达式​返回完整容器(如列表)返回惰性迭代器立即执行,占用内存惰性求值,节省内存

  • 核心区别​:
    • 容器​:存储元素,支持 in 测试。
    • 可迭代对象​:能返回迭代器(iter())。
    • 迭代器​:通过 __next__() 逐个返回值(带状态)。
    • 生成器​:用 yield 简化的迭代器。
    • 生成器表达式​:惰性推导式(返回迭代器)。
    • 推导式​:立即生成容器(列表/集/字典)。

实践建议​:将逐步构建列表的函数转为生成器,即:

def generate_data():    # 生成器节省内存
    for ... in ...:
        yield result

# 必要时再转换为列表
data = list(generate_data())

for 语句

for 语句用于对序列(例如字符串、元组或列表)或其他可迭代对象中的元素进行迭代:

for_stmt ::= "for" target_list "in" starred_list ":" suite
             ["else" ":" suite]

starred_list 表达式会被求值一次;它应当产生一个 iterable 对象。 将针对该可迭代对象创建一个 iterator。 随后该迭代器所提供的第一个条目将使用标准的赋值规则被赋值给目标列表 (参见 赋值语句),而代码块将被执行。 此过程将针对该迭代器所提供每个条目重复进行。 当迭代器被耗尽时,如果存在 else 子句中的代码块,则它将被执行,并终结循环。

第一个子句体中的 break 语句在执行时将终止循环且不执行 else 子句体。 第一个子句体中的 continue 语句在执行时将跳过子句体中的剩余部分并转往下一项继续执行,或者在没有下一项时转往 else 子句执行。

for 循环会对目标列表中的变量进行赋值。 这将覆盖之前对这些变量的所有赋值,包括在 for 循环体中的赋值:

for i in range(10):
    print(i)
    i = 5             # 这不会影响 for 循环
                      # 因为它将被 range 对象中的下一个索引
                      # 所覆盖

目标列表中的名称在循环结束时不会被删除,但是如果序列为空,则它们将根本不会被循环所赋值。 提示:内置类型 range() 代表由整数组成的不可变算数序列。 例如,迭代 range(3) 将依次产生 0, 1 和 2。

在 3.11 版本发生变更: 现在允许在表达式列表中使用带星号的元素。

Bash

在 Bash 中,快捷键可以显著提高命令行操作的效率。以下是一些常用的 Bash 快捷键:

光标移动

  • Ctrl + A: 移动到行首。
  • Ctrl + E: 移动到行尾。
  • Alt + B: 向后移动一个单词。
  • Alt + F: 向前移动一个单词。
  • Ctrl + B: 向后移动一个字符。
  • Ctrl + F: 向前移动一个字符。

编辑命令

  • Ctrl + W: 删除光标前的一个单词。
  • Alt + D: 删除光标后的一个单词。
  • Ctrl + U: 删除光标前的所有内容(从光标到行首)。
  • Ctrl + K: 删除光标后的所有内容(从光标到行尾)。
  • Ctrl + T: 交换光标前的两个字符。
  • Alt + T: 交换光标前的两个单词。
  • Ctrl + Y: 粘贴之前删除的内容。

历史命令

  • Ctrl + P: 上一条命令(等同于向上箭头)。
  • Ctrl + N: 下一条命令(等同于向下箭头)。
  • Ctrl + R: 反向搜索历史命令。
  • Ctrl + G: 退出历史搜索模式。

进程控制

  • Ctrl + C: 终止当前进程。
  • Ctrl + Z: 暂停当前进程(可以使用 fg 恢复)。
  • Ctrl + L: 清屏(等同于 clear 命令)。
  • Ctrl + D: 退出当前 Shell(等同于 exit 命令)。

其他

  • Ctrl + S: 暂停屏幕输出(可以使用 Ctrl + Q 恢复)。
  • Ctrl + Q: 恢复屏幕输出。
  • Ctrl + X + E: 使用默认编辑器编辑当前命令。

补全

  • Tab: 自动补全命令或文件名。
  • Alt + .: 插入上一个命令的最后一个参数。

这些快捷键可以帮助你更高效地使用 Bash,减少重复操作和提高工作效率。

Terminal

在终端中,如果你想清空已经输入但尚未执行的命令或内容,可以使用以下几种方法:


1. 使用 Ctrl + C

  • 按下 Ctrl + C 会中断当前输入的命令,并清空当前行。
  • 如果光标在命令行的任意位置,按下 Ctrl + C 会将整行内容清空,并返回到新的提示符。

2. 使用 Ctrl + U

  • 按下 Ctrl + U 会清空从光标位置到行首的内容。
  • 如果光标在行尾,则会清空整行。

3. 使用 Ctrl + W

  • 按下 Ctrl + W 会删除从光标位置到前一个空格或单词分隔符的内容。
  • 可以多次按 Ctrl + W 逐步删除前面的单词。

4. 使用 Esc + Backspace(或 Alt + Backspace

  • 按下 Esc 后按 Backspace(或直接按 Alt + Backspace)会删除光标前面的一个单词。

5. 使用 Ctrl + L

  • 按下 Ctrl + L 会清空整个终端屏幕,但不会删除已经输入的命令。
  • 如果你想清屏并保留当前输入的命令,可以使用这个方法。

6. 使用 Ctrl + ACtrl + K

  • 按下 Ctrl + A 将光标移动到行首。
  • 然后按下 Ctrl + K 删除从光标位置到行尾的内容。
  • 这样可以将整行内容清空。

7. 使用 reset 命令

  • 如果你已经执行了命令,但终端显示混乱,可以输入 reset 命令来重置终端状态。
  • 注意:reset 会清空整个终端屏幕和缓冲区。

总结

  • 清空当前行:Ctrl + UCtrl + C
  • 清空屏幕:Ctrl + L
  • 删除单词:Ctrl + WAlt + Backspace
  • 重置终端:reset

自动驾驶

自动驾驶的决策方面涉及多个关键领域和技术,以下是一些速成知识:

  1. 感知(Perception)
    • 自动驾驶汽车依靠传感器(如摄像头、雷达、激光雷达)收集环境信息。
    • 感知系统识别周围的物体(行人、车辆、交通标志等)和环境特征。
  2. 定位(Localization)
    • 通过GPS和高精度地图,车辆确定自身在环境中的位置。
    • 需要与感知数据结合,以提高精度。
  3. 预测(Prediction)
    • 预测其他道路使用者(如行人和车辆)的未来行为。
    • 使用机器学习模型分析历史数据和实时信息进行动态预测。
  4. 规划(Planning)
    • 生成安全的行驶路径,包括选择车道、转弯、避让障碍物等。
    • 规划过程通常分为全局规划(长远目标)和局部规划(短期决策)。
  5. 控制(Control)
    • 根据规划的路径,自动驾驶系统控制车辆的加速、刹车和转向。
    • 需要快速反应以适应实时变化的环境。
  6. 决策框架
    • 常用的决策模型包括基于规则的系统、马尔可夫决策过程(MDP)和强化学习。
    • 决策的复杂性体现在多目标优化和不确定性管理上。
  7. 安全与伦理
    • 自动驾驶必须考虑伦理决策,如在紧急情况下如何选择行动。
    • 安全性和可靠性是设计决策系统的重要因素。

这些要素共同构成了自动驾驶汽车的决策能力,确保它们在复杂环境中安全、有效地导航。

杂项

# 文件开头的 \ufeff 是字节顺序标记(BOM, Byte Order Mark),通常出现在 UTF-8 编码的文件中。BOM 是一个 Unicode 字符(U+FEFF),在某些文本编辑器或编码工具中会自动添加到文件的开头,以指示文件的编码类型。

C++

这里使用了std::prev函数,它返回给定迭代器的前一个迭代器,而不改变原始迭代器。这是C++11标准引入的方法,用于在不改变原始迭代器的情况下获取前一个迭代器。

在C++17中,条件初始化语句(”Conditionally-Scoped Init Statement”)是对if和switch语句的一种扩展,使它们可以在条件判断中包含初始化语句。这一特性增强了代码的可读性和简洁性,特别是在需要在条件判断中进行变量初始化的场景下。具体来说,这种语法允许你在if或switch语句中引入一个新的变量,该变量的作用域仅限于该语句块内。

#include <iostream>

int main() {
    if (int x = 42; x > 0) {
        std::cout << "x is positive and equals " << x << std::endl;
    } else {
        std::cout << "x is non-positive" << std::endl;
    }
    // x 的作用域在此结束
    return 0;
}
#include <iostream>

int main() {
    switch (int x = 42; x) {
        case 0:
            std::cout << "x is zero" << std::endl;
            break;
        case 42:
            std::cout << "x is 42" << std::endl;
            break;
        default:
            std::cout << "x is something else" << std::endl;
            break;
    }
    // x 的作用域在此结束
    return 0;
}

mAP50 和 mAP50-95


mAP50 和 mAP50-95 是用来评估目标检测模型(如图像中物体检测)性能的两种指标,常用在计算机视觉领域。这些指标主要用来衡量模型识别物体的准确性。下面是这两个指标的具体含义:

  1. mAP50 (mean Average Precision at 50% IOU)
    • 这是平均精确度均值(mean Average Precision,mAP)的一种形式,其中采用50%的交并比(Intersection over Union, IOU)作为阈值。
    • IOU是一个衡量预测框(模型对物体位置的预测)与真实框(物体实际位置)之间重叠程度的指标。
    • 当IOU至少为50%,即预测框和真实框至少有50%的重叠时,预测才被认为是正确的。
    • mAP50计算的是在此IOU阈值下,模型在所有类别和所有检测难度上的平均性能。
  2. mAP50-95
    • 这个指标是在多个不同的IOU阈值(通常是从50%到95%,间隔5%)下计算mAP,然后取这些mAP值的平均。
    • 它提供了一个更全面的评估,因为它不仅考虑到较容易的情况(例如50%的IOU),也考虑到更严格的情况(例如95%的IOU)。
    • 这种方法更加严格,能更好地衡量模型对物体位置精确预测的能力。

简而言之,mAP50 主要关注模型在较低准确度阈值下的表现,而 mAP50-95 则提供了一个在从较低到较高准确度阈值全范围内模型表现的综合评估。这使得mAP50-95成为一个更全面严格的性能评估指标。

Docker

docker exportdocker save这两个Docker命令都用于导出Docker容器和镜像,但它们的作用和使用场景有显著的区别。下面我将详细解释这两者之间的主要差异:

1. 导出的对象

  • docker export
  • 这个命令用于导出一个运行中的容器的文件系统。它创建一个包含容器中所有文件和文件夹的快照,但不包括容器运行时的元数据或历史。
  • 使用命令:docker export <container_id> > container.tar
  • docker save
  • 这个命令用于导出一个或多个Docker镜像,包括其所有的历史和元数据(如标签、层信息等)。
  • 使用命令:docker save -o image.tar image_name:tag

2. 输出内容

  • docker export
  • 输出是一个包含容器文件系统的tar文件。它不包括容器的元数据,如环境变量、命令历史或Dockerfile中定义的配置。
  • 结果是一个基本的文件系统快照,适用于需要文件级访问的场景。
  • docker save
  • 输出是一个tar文件,其中包含镜像的所有层、配置文件和元数据。这个文件可以用来重新创建镜像的完整记录,包括其历史和属性。
  • 这使得docker save成为在不同环境之间迁移镜像的理想选择,因为它保留了镜像构建的所有方面。

3. 使用场景

  • docker export
  • 如果你需要快速提取运行中的容器的文件系统状态,无论是为了调试还是为了快速迁移某些数据,docker export是一个很好的选择。
  • 注意,由于它不包含容器的元数据,你可能需要手动配置新容器的运行环境。
  • docker save
  • 当你需要完整地备份或迁移Docker镜像时,docker save是最合适的工具。它确保了镜像的所有层和配置都被保存下来,可以在任何安装了Docker的机器上重现。
  • 它是在团队或多环境部署中共享镜像的理想选择,因为它包含了创建镜像时所需的全部信息。

4. 还原方法

  • docker export 导出的容器可以通过docker import命令导入,但导入后只是一个镜像,不保留原容器的运行状态或配置。
  • docker save 导出的镜像可以通过docker load命令完全还原。

这些差异使得docker exportdocker save各自适用于不同的应用场景,根据需要备份的内容和目的选择使用哪一个命令。

PEP 3119 – Introducing Abstract Base Classes

PEP 3119, 标题为“引入抽象基类”,是Python增强提案的一部分,由Guido van Rossum, Talin, 和Phillip J. Eby于2007年提出。该PEP的目标是在Python中引入一种机制,允许创建抽象基类(ABCs)。这些类作为其他类的基类,定义了一组基本方法和属性,子类应当实现或继承这些方法和属性,从而遵循一个特定的接口或者继承某些实现。

主要内容和目标包括:

  • 抽象基类的引入:提供了一种标准方式来定义抽象基类。这些基类不能被实例化,只能被其他类继承。它们用来定义一个或多个抽象方法,即至少有一个方法是声明性的,而没有实现(使用@abstractmethod装饰器)。
  • 标准库的支持:PEP 3119还提议对Python标准库进行改进,以利用抽象基类。例如,通过创建诸如ContainerIterableSized等抽象基类,来为集合和其他容器提供一套统一的接口。
  • 类型检查:虽然Python是一种动态类型语言,PEP 3119通过抽象基类提供了一种机制,允许进行更严格的类型检查。这意味着开发者可以通过检查某个类是否为特定抽象基类的子类,来确认该类是否实现了必需的方法和属性。
  • 注册机制:PEP 3119引入了一种注册机制,允许将任意类标记为特定抽象基类的虚拟子类。这使得即使类没有从抽象基类继承,也可以被认为是满足接口要求的,只要它实现了必要的方法。

通过这些特性,PEP 3119旨在鼓励更加清晰和结构化的代码设计,促进接口和实现的明确分离,以及提高Python代码的可维护性和可重用性。