Python 单元测试 unittest / pytest
整理一下 Python 单元测试的内容,包括: 内置的单元测试模块 unittest 第三方测试工具 pytest 除此之外,其实还有直接解析源码注释,获取测试用例的内置模块 doctest。 准备 为了便于描述,下面准备两个函数和一个类作为测试目标,构成 my_module.py my_module.py1234567891011121314151617181920def my_add(a, b): return a + bdef my_divide(a, b): return a / bclass MyDict(dict): def __init__(self, **kw): super().__init__(**kw) def __getattr__(self, key): try: return self[key] except KeyError: raise AttributeError(r"'MyDict' object ha...
DLL 注入攻击
概念介绍 DLL 注入攻击(DLL Injection)是一种将动态链接库(DLL)强制加载到目标进程中的技术,使得攻击者编写的代码能在目标进程的地址空间中运行。 在 Windows 中,DLL 注入是系统提供的合法功能,主要用于调试器和辅助工具,但也可以被用于攻击,不过这种攻击手段是非常明显且初等的,一般的防护软件都会阻止这种行为。 简易实现 可以使用最经典的 CreateRemoteThread + LoadLibraryA 方法实现 DLL 注入攻击,下面是主要的代码思路。 代码参考:idea4good/AbuCoding Loader 目标是让目标进程(这里以记事本Notepad.exe为例)加载提供的 DLL,实现步骤: 查找并获取目标进程句柄:使用 CreateToolhelp32Snapshot 遍历系统进程列表;调用 OpenProcess(PROCESS_ALL_ACCESS, ...) 在目标进程分配内存并写入 DLL 路径:VirtualAllocEx 为 DLL 路径字符串留空间;WriteProcessMemory 将 DLL 路径写到目标进程 获取 ...
Python 日志库 logging
Python 标准库中的 logging 模块提供了功能完备、可高度自定义的日志记录方案,适用于从简单脚本到复杂应用程序的各种场景。 许多 C/C++ 项目都依赖自行实现的简单日志库或成熟的第三方日志库(如 spdlog、log4cpp 等),与之不同的是,Python 内置的 logging 模块已经可以满足绝大多数开发需求,各种语言的日志库使用逻辑具有很多共性。 基本使用 先讨论在简单脚本文件中的日志使用,不涉及 logger 以及复杂的日志配置逻辑。 极简示例 导入日志库之后,无需任何配置就可以直接使用 1234567import logginglogging.debug("This is a debug message.")logging.info("This is an info message.")logging.warning("This is a warning message.")logging.error("This is an error message.")logging....
Vim 学习笔记
vim 被称为编辑器之神,学习难度很大,但是熟练掌握后可以更高效地敲代码,因此有必要学一下,但是没必要鼓捣各种插件。 主要参考:【Vim】可能是B站最系统的Vim教程 vim 介绍与版本 vim 是古董编辑器 vi 的升级版,在现代的 Linux 发行版中通常自带 vim,无需手动安装,虽然版本通常不是最新的,但是也足够使用。在很多发行版中都将 vi 命令链接到 vim 命令,因此 vi 命令和 vim 命令通常是等价的,都是在调用 vim 编辑器。 在 vim 中输入 :version 可以查看版本信息,例如 123VIM - Vi IMproved 8.2 (2019 Dec 12, compiled Nov 22 2021 19:31:05)Included patches: 1-3582Compiled by <https://www.msys2.org/> vim 的各种功能模块化,在编译安装时可以选择精简其中一部分功能,至少有几种安装模式:tiny, small, normal, big, huge,显然 huge 版本的功能最完整。 在 :version...
K-means 算法
K-means 算法是一种经典的无监督学习算法,用于将数据自动分为 \(k\) 个簇,这里的 \(k\) 需要提前给定。 K-means 算法假设簇是凸的、大小相近,此时处理效果最好,但是并不能处理复杂形状的簇(如半月形),对维度高的稀疏数据(如文本)不太适用。 算法步骤 设数据集为 \(X = \{x_1, x_2, \dots, x_n\}\),\(x_i \in \mathbb{R}^d\),希望聚为 \(k\) 类,算法流程如下: 初始化:随机选择 \(k\) 个数据点作为初始的簇中心。 分配:将每个数据点分配到最近的簇中心,以形成 \(k\) 个簇。设当前中心为 \(\mu_1, \dots, \mu_k\),对于样本 \(x_i\),所属的簇为 \[ x_i \in C_s \,\, \text{where} \,\, s = \arg\min_{j=1,\dots,k} \| x_i - \mu_j \|^2 \] 更新:重新计算每个簇的中心,记 \(C_s\) 是第 \(s\) 个簇内的数据点集合,那么中心 \(\mu_s\) 为 \[ \mu_s = \fra...
Numpy 学习笔记——3. 数组的线性代数运算
NumPy 提供了比较丰富的线性代数运算功能,主要集中在 numpy.linalg 模块中,下面罗列一些基础的操作,主要针对一维和二维数组,对于其它高维数组的语义可能不太符合直觉。 重要函数 点积 np.dot np.dot() 函数可以计算两个向量的点积,最基本的用法例如 1234a = np.array([1, 2, 3], dtype=np.float64)b = np.array([4, 5, 6], dtype=np.float64)np.dot(a, b) # np.float64(32.0)# 1*4 + 2*5 + 3*6 = 32 np.dot(a, b)的完整语义需要根据两个数组的维度来区分: 第一类情况: 如果其中一个是标量,那么就是进行(逐元素的)乘法,等效于 np.multiply(a, b) 或 a * b。 第二类情况: 如果 a 是 \(N\) 维数组,b 是一维数组,那么会沿着两者的最后一个轴求和,得到 \(N-1\) 维数组。 (特例,标准情况)如果两者都是尺寸为 (m,) 的一维数组,那么就是标准的向量内积,结果是一个标量。 (特例...
Numpy 学习笔记——2. 数组的变换和基本运算
数组的拷贝 Python 本身有深拷贝和浅拷贝等复杂的概念,对于多层列表等数据结构,对应的行为差异非常明显。 但是 Numpy 的 ndarray 数组无论形状如何,在内存中始终是连续存储的,高维数组并不是数组的数组, 因此并没有深拷贝和浅拷贝的明显差异。 和其它 Python 数据一样,在函数传参过程中对 ndarray 数组的传递并不会触发任何的拷贝行为。 为了获取一个 ndarray 数组的完整拷贝,可以使用 ndarray.copy() 方法,例如 12345a = np.array([1, 2, 3])b = a.copy()b[0] = 100a # array([1, 2, 3]) 上述测试代码表明,拷贝得到的是完全独立的数组,修改不会相互影响。 也可以使用numpy.copy()函数,例如 12a = np.array([1, 2, 3])b = np.copy(a) ndarray.copy() 方法和 numpy.copy() 函数的行为是基本一致的,都是获取原数组的拷贝,但是两者关于内存排布参数的默认值有细微差异,可以参考具体文档。 数组的视图 为了优化计...
Numpy 学习笔记——1. 数组的创建和索引
Numpy 是一个用于科学计算的 Python 扩展库,虽然不是 Python 标准库,但是已经是 Python 在科学计算、机器学习等领域毋庸置疑的基础库,很多主流的 Python 库都依赖 Numpy。 1import numpy as np 一个循序渐进的入门笔记的内容组织比较麻烦,我也并不打算这么做,这个笔记的内容会围绕一些关键点展开, 主要参考 Numpy 的官方资料。 ndarray 基本概念 np.ndarray (别名 np.array)是 Numpy 的核心数据类型,可以用于存储 n 维数组,并提供了大量相关操作方法。 它与 Python 的 list 类型类似,但是存在更多限制:只能存储同类型数据,并且尺寸是固定且规则的,即不允许各个元素长短不一的数组。 这些限制使得 ndarray 的运算非常高效(直接调用底层的 C/C++ 实现)。 但是有一点不足的是:Numpy 没有提供稀疏矩阵的数据结构,需要时可以使用其它包提供的稀疏矩阵。 我们主要关注一维数组和二维数组,例如 123array([1, 2, 3]) # shape=(3,)array([[1, ...
MATLAB 高性能编程笔记
记录一些常用的 MATLAB 编程技巧/规范,目标是写出高性能的 MATLAB 代码。主要参考官方文档中的提升性能的方法。 基础 关于代码结构 MATLAB 提供了很多方式来执行代码:命令行 vs 脚本 vs 函数,绝大多数代码在不同方式中执行都是等效的,但是考虑优化就不是一回事了,通常的运行效率关系为:命令行 < 脚本 < 函数,也就是说函数的执行速度通常是最快的。 基于模块化编程的思维,避免使用过大的单一文件,考虑将其中重复使用的功能拆分为简洁的函数文件,这种做法可以降低首次运行的成本。 优先使用局部函数而非嵌套函数,嵌套函数可以直接访问外层函数的变量(按照引用捕获),这会影响效率,更好的做法是将所有需要的变量以函数参数的形式显式传递。 交互式地在命令行中调用某些内置函数,相比于从脚本文件中调用,可能会有不一样的结果。 关于内置函数 避免重载内置函数,尤其不要对标准 MATLAB 数据类重载内置函数。 在可选的情况下,优先考虑使用 MATLAB 的内置函数来实现数组的常用运算,因为内置函数可能是直接使用底层语言实现的,至少也经过了大量的优化,比我们直接实现的效...
MATLAB 踩坑记录
记录一下 MATLAB 踩过的小坑,MATLAB的各种内置函数的用法实在是太奇怪了,一个小细节就可以搞出各种问题。 矩阵偏移 函数 circshift 可以用于向量或矩阵的循环偏移,不会修改原始数据。 向量偏移 123456A = [1, 2, 3, 4, 5];circshift(A, 1)% [5, 1, 2, 3, 4]circshift(A, -1)% [2, 3, 4, 5, 1] 矩阵的偏移就比较复杂了,按照前面的做法会以行为整体进行偏移!!! 1234567A = [1 2 3; 4 5 6; 7 8 9];circshift(A, 1);% 7 8 9% 1 2 3% 4 5 6 如果希望以列进行偏移,有两种方式,第一种方式是额外指定维数(传递两个标量) 1234567A = [1 2 3; 4 5 6; 7 8 9];circshift(A, 1, 2)% 3 1 2% 6 4 5% 9 7 8 ...
