0%

【使用 Python 实现算法】目录


最近加入了公司同事组织的刷题群,会定期参加 LeetCode 等平台的算法比赛。

作为一个资深 Pythonist,我一向是使用 Python 来实现各种算法题目的。Python 本身也提供了一些不错的语言特性、内置函数和标准库来更高效简洁的编写各类算法的代码实现。

本系列博客是我根据个人使用 Python 工作和刷题的经验总结的一些使用 Python 实现各类算法的一些技巧。

作为系列博客的第一篇文章,本期的主题是 Python 的语言特性。

解构赋值

交换两个变量的值是一个很常见的场景,在 C 和 C++语言中,我们需要使用一个临时变量。代码会比较冗长,并且会有微小的性能开销。

1
2
3
int tmp = x;
int x = y;
int y = x;

利用 Python 的解构赋值特性,我们可以使用一个赋值语句交换两个变量的值。

1
x, y = y, x
Read more »

配置管理在现代应用开发和部署中至关重要,在十二要素应用(12 Factor App)中,配置管理也是第三个重要因素。

使用Pydantic库,我们可以方便灵活地在 Python 应用中管理配置。

使用 Pydantic

配置管理Pydantic官方文档中列出的一个重要应用领域。

如果你创建了一个继承自 BaseSettings 的模型,模型初始化器将试图通过从环境中读取来确定任何没有作为关键字参数传递的字段的值。(如果匹配的环境变量没有被设置,默认值仍将被使用)。

简化了一下操作:

  1. 创建一个明确定义的、有类型提示的应用程序配置类。
  2. 自动从环境变量中读取对配置的修改。
  3. 在需要时手动覆盖初始化器中的特定设置(例如在单元测试中)。
Read more »

C 和 C++中的函数重载

我们在学习 C 和 C++的时候,会接触到一个概念叫做函数重载。简单来说函数重载指的是多个函数具有相同的名称,但是参数不同(包括参数类型和参数数量)。编译器在遇到重载函数的调用时,会在同名函数的不同重载实现中选择参数匹配的哪一个来调用。

这里举一个简单的例子。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>

void desc(int n){
std::cout << n << " is an integer" << std::endl;
}

void desc(double x){
std::cout << x << " is a floating number" << std::endl;
}

int main(){
desc(1);
desc(2.0);
return 0;
}

C++ Function Overloading

Read more »

之前刷 LeetCode 题目的时候,偶尔会需要反转二维列表,这里总结了几种 Python 实现。

循环

简单的二维循环,将原始二维列表的每一行的第 N 个元素,放到新的二维列表的第 N 行中。

1
2
3
4
5
6
7
8
def invert_matrix(matrix: list[list[int]]) -> list[list[int]]:
new_matrix = []
for i in range(len(matrix[0])):
new_row = []
for row in matrix:
new_row.append(row[i])
new_matrix.append(new_row)
return new_matrix

列表推导式

本质上和循环算法是相同的,使用列表推导式语法来实现。

1
2
def invert_matrix(matrix: list[list[int]]) -> list[list[int]]:
return [[row[i] for row in matrix] for i in range(len(matrix[0]))]
Read more »

最近在深入学习 Rust 语言,本着学以致用的原则,使用 Rust 编写了一个生成二维码的 Web 服务

使用的库

  • axum,一个基于 tokio 的 web 框架
  • qrcode, 用于生成二维码

核心逻辑

生成二维码

直接调用qrcode库相关接口,返回生成的 PNG 文件的二进制内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
fn gen_qr_code(content: &str) -> Vec<u8> {
tracing::info!("Generating QR code for {}", content);

let image = QrCode::new(content)
.unwrap()
.render::<Luma<u8>>()
.min_dimensions(512, 512)
.build();

let mut buffer = Vec::new();
PngEncoder::new(buffer.by_ref())
.encode(&image, image.width(), image.height(), image::ColorType::L8)
.unwrap();

buffer
}
Read more »

最近接到了一个新的需求。需求本身是一个简单的运营活动,不过这个运营活动并不是长期存在的,需要通过后台设置生效时间。

抽象一下的话就是需要通过开关来控制一个功能是否生效,也就是特性开关(Feature Flags)模式。

Martin Fowler 先生写过一篇特性开关模式的文章,感兴趣的读者可以深入阅读。

Read more »

RAII 概念与在 Python 中的应用

RAII(Resource Acquisition Is Initialization),即资源获取即初始化,是一种设计模式,用于解决资源的获取与初始化的问题,最早在 C++中提出与推广。
在这篇文章我来简单地介绍一下 RAII 的概念,以及在 Python 中的应用。

RAII 的概念

在计算机与程序的世界中,有一些资源,比如文件、网络连接、数据库连接、线程、进程等,这些资源在使用的时候需要获取,在使用完成后需要释放。如果不及时释放,会导致资源泄露,造成资源的浪费,程序出错甚至系统崩溃。

一个简单的示例就是文件的读写。

1
2
3
4
f = open('test.json', 'r')
raw = f.read()
data = json.loads(raw)
f.close()

这段代码看起来没有什么问题,但是当test.json文件的内容不是合法的 JSON 格式时,第四行代码反序列化数据就会抛出异常,导致第五行代码无法执行,文件没有被关闭。

这个例子告诉我们在处理一些资源时,需要注意在操作过程中是否会发生一些意外情况,例如抛出异常,并且在意外情况发生后,也需要关闭资源。

在 Python2.5 之前的版本中,我们用try-finally来保证程序最终会关闭资源。

1
2
3
4
5
6
7
8
try:
f = open('test.json', 'r')
raw = f.read()
data = json.loads(raw)
except JSONDecodeError:
...
finally:
f.close()

在简单的文件读取操作中,使用try语句多少有点大材小用。为了更好地处理类似的资源管理问题,Python2.5 引入了with语句,做到无论语句块中的代码执行是否抛出异常,都可以在退出with语句块时执行清零代码。

事实上在 Python 中进行文件读写的标准方式就是使用with open语句。

1
2
3
with open('test.json', 'r') as f:
raw = f.read()
data = json.loads(raw)
Read more »

临近 618 年中大促,各大云服务商也会提供一些优惠。正好我三年前在腾讯云上买的一台 2 核 4G 的虚拟机到期了,看了一下腾讯云的优惠活动,下单了一台 2 核 4G 的的轻量应用服务器(一年期,288 元)。

轻量应用服务器一般都会提供一些常见的镜像(WordpressLAMP 等),我的目的不是建站,所以还是选了朴素的 Ubuntu18.04 的基础镜像。

下面大致介绍一下我配置服务器的过程(安装及配置方法基本来源于对应工具官网)。

配置密钥登录

轻量应用服务器默认是从腾讯云控制台直接登录到终端,可以将自己的公钥加到 ssh 配置里。

1
2
# Remote
cat PUBLIC_KEY >> ~/.ssh/authorized_keys

为了方便登录,可以配置自己主机的ssh config 文件,随后就可以通过ssh light命令登录到服务器。

1
2
3
4
5
6
# ~/.ssh/config

Host light
HostName 1.2.3.5
Port 22
User lighthouse
Read more »

最近公司越来越多的项目开始推动单元测试,而我在公司里很早就在进行单元测试实践。就用这篇文章作为一次内部技术分享的主题,同时也代表我自己对单元测试的认识和实践。

单元测试的概念

单元测试是软件测试的一种类型,测试对象是最基础的代码单元(函数、类、模块),属于白盒测试。在经典的测试金字塔中,单元测试处于最底层。

testPyramid

最简单的单元测试:

basic.png

Read more »