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...
基于 Markdown / Jupyter 生成幻灯片
Marp 简单介绍 Markdown → 幻灯片 可导出 PDF / HTML 适合讲义、科研展示、课程分享 使用方式 VS Code 安装 Marp 插件(推荐) npm 安装 Marp CLI 基本语法 基于现有的 Markdown 文件略微修改即可 使用 --- 分页,前后最好有单独空行 在头部添加元信息进行全局配置 1234567---marp: truetheme: gaiapaginate: true---... 配置 Marp 支持的配置包括全局配置和局部配置,前者出现在头部,后者出现在对应的分页。 在Markdown头部支持添加如下形式的元信息进行全局配置 12345---marp: truetheme: gaiapaginate: true--- 具体含义为: marp:true 开启 Marp 渲染(这是唯一的必选项) theme: default、gaia、uncover 几个内置主题 paginate:true、false 是否显示页码 在具体分页则可以使用html注释形式添加对应的局部配置,例如: 用大字体样式(通常用于封面) 1<...
Cpp 笔记汇总
Cpp 进阶笔记 Cpp 进阶笔记——1.右值引用 Cpp 进阶笔记——2.移动语义 Cpp 进阶笔记——3.引用折叠、万能引用和完美转发 Cpp 构建和编译笔记 Cpp 构建和编译笔记——1. 编译过程 Cpp 构建和编译笔记——2. 头文件和库 Cpp 构建和编译笔记——3. gcc 选项 Cpp 构建和编译笔记——4. make 与 Makefile Cpp 构建和编译笔记——5. CMake 与 CMakeLists Cpp 构建和编译笔记——6. CMake 基本语法 Cpp 构建和编译笔记——7. CMake 语法结构 Cpp 构建和编译笔记——8. CMake 依赖管理 Cpp 构建和编译笔记——9. CMake 库的开发 Cpp 配置笔记 GCC 源码编译安装(离线,普通用户) Cpp 编译环境笔记 Visual Studio 简单使用记录 VSCode Cpp 配置 Windows Cpp 编程中的几个问题 Cpp 函数 API 设计 Cpp 可调用对象笔记 Cpp const* 关键词 Cpp 奇异递归模板模式 CRTP Cpp 函数参数默认值 ...
Numpy 学习笔记之三
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 学习笔记之二
数组的拷贝 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 学习笔记之一
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, ...