python的字典和集合的退化

python的字典和集合的退化

Python 的字典 dict 和集合 sethashable 作为 key,存储数据于其中,理想情况下,查询操作具有 $O(1)$ 的时间复杂度。但如果你想当然地认为,现实总是和理想差不太多,那么就可能会掉入一个陷阱之中。

操作 数组 (Array) 链表 (Linked List) 散列表 (Hash Table)
增(插入) $O(n)$ (中间) / $O(1)$ (末尾) $O(n)$ (需要遍历) 平均 $O(1)$
删(删除) $O(n)$ (中间) / $O(1)$ (末尾) $O(n)$ (需要遍历) 平均 $O(1)$
查(查找) $O(1)$ (按索引) / $O(n)$ (按值) $O(n)$ 平均 $O(1)$
改(修改) $O(1)$ (按索引) $O(n)$ 平均 $O(1)$

Python 实现字典和集合,利用了 hash 表。存储元素到 hash 表时,首先会用散列函数对元素计算 hash 值,然后相同 hash 值的元素,会存储在同一个链表之中。这个 hash 函数,就是元素的类上所定义的 __hash__ 特殊方法,会以元素进行计算然后得到一个整数值。Python 判断一个元素是否在字典和集合中(__contains__),还要判断元素是否相等 (__eq__,默认比较元素的内存地址,即 id)。首先是找到元素的 hash 值所在的链表,然后对链表元素进行逐个比对,仅当相等时才认为元素在其中,在链表中查找的时间复杂度是 $O(n)$。也就是说,字典和集合在最坏情况下,查询的时间复杂度就是 $O(1 * n)$,即 $O(n)$。

这种情况就是 hash 冲突,当严重的冲突发生时,hash 表就退化为链表了。

Separate Chaining technique to handle collisions

所以,如果一大堆元素有相同的 hash 值,则存储它们的字典或集合会发生退化。

阅读更多
Python模块-pandas.DataFrame转Excel格式的bytes数据

Python模块-pandas.DataFrame转Excel格式的bytes数据

背景

pandas is an open source, BSD-licensed library providing high-performance, easy-to-use data structures and data analysis tools for the Python programming language.

数据分析工具包 pandas,是利用 Python 进行数据分析时,一个难以割舍的选项。它的官方文档 pandas/docs 示例非常丰富,而且它的作者 Wes McKinney 另外还写了一本书 Python for Data Analysis,截至目前已经更新到第 3 版,👆点击下载
中国国内也有热心网友做了免费的翻译分享,这是第 2 版,简书-《Python数据分析》2nd
Python for Data Analysis, 3rd Edition

我曾经实现过一个单机部署的 ETL (extract, transform, load) 程序,三个步骤都基于 pandas 实现。不过这个程序最常用的功能,却仅仅是定时读取一批 SQL,然后写入 Excel,最后把这些 Excel 文件作为邮件附件进行发送,真是杀鸡用牛刀😂。

其实,我个人并不太喜欢使用 Excel 文件,先不论 Excel 那缓慢的打开速度,它的一个工作表最多也只能有 1048576(2^20) 行和 16384(2^14) 列,工作表名字最多 31 个字符。所以在我看来,CSV 才是更好的选项。

在那个 ETL 中,只允许从每个源读取一个 pandasDataFrame,但在输出时,可以把多个 DataFrame 输出到一个目标里面。对于一种这类情况,即把多个 DataFrame 输出到同一个 Excel 工作簿,如果这个目标之后再作为一个源时,就不好处理了。如果这是最终的输出,而不是管道的一个中间环节,却是可以接受的。

Excel 最大的问题是工作表的规模有限,如果你的表格的规格超出 1048576×16384,也就是这个矩形不能把你数据表格完全盖住,你就得对 DataFrame 进行拆分。一般来说,我个人是不推荐做拆分的。我的建议是,一个工作簿,只开一个工作表,如果一个工作表存储不下,那就用 CSV 或者 hdf5 格式。

阅读更多
Python模块-打包多个参数于一体

Python模块-打包多个参数于一体

背景

在调用 Python 函数 (See also realpython - Defining Your Own Python Function) 的时候,往往需要传入一些参数。函数所需的参数被称为形式参数 parameter,传入的参数被称为实际参数 argument (See also 5 Types of Arguments in Python Function Definitions))。

See also the FAQ question on the difference between arguments and parameters, the inspect.Parameter class, the Function definitions section, and PEP 362.

我常常需要把一些实际参数收集起来,可能后续还要进行一些更新,并在需要的时候反复使用。有一种办法是使用偏函数 functools.partial,但这需要绑定具体的函数。

1
2
3
4
5
6
7
8
9
>>> from functools import partial
>>> basetwo = partial(int, base=2)
>>> basetwo.__doc__ = 'Convert base 2 string to an int.'
>>> basetwo('10010')
18
>>> basethree = partial(basetwo, base=3)
>>> basethree.__doc__ = 'Convert base 3 string to an int.'
>>> basethree('10010')
84

于是我实现了一个类 Args,它可以一次性收集一些位置参数(positional argument,See also stackoverflow - Understanding positional arguments in Python)和关键字参数(keyword argument,See also realpython - Python args and kwargs: Demystified),并在以后需要时,反复直接使用。

1
2
3
4
5
6
7
>>> from args import UpdativeArgs
>>> args = UpdativeArgs('10010', base=2)
>>> args(int)
18
>>> args.update(base=3)
>>> args(int)
84
阅读更多
Python脚本设置pip索引源

Python脚本设置pip索引源

背景

Python 包索引(Python Package Index,PyPI)是由全球 Python 开发人员社区提供的大量开源 Python 包的存储库。官方索引在 https://pypi.org,网站本身由 Python 软件基金会(Python Software Foundation,PSF)维护。
你也可以在上面发布自己的项目,可参考 A Beginner’s Guide to Publishing Packages on the Python Package Index (PyPi)How to Publish an Open-Source Python Package to PyPI

Python 使用 pip 安装第三方包时,默认使用的官方索引源 pypi 的地址 https://pypi.python.org/pypi 在中国大陆因为墙的原因,下载缓慢。
ubuntuaptarchlinuxPacman 有各自国内镜像源一样,pip 也有国内索引源可用,下面罗列了一部分,进一步的,为了便于设置国内源,并受到 nodejsnrm 的启发,我编写了一个脚本

key index-url trusted-url 提供者
douban http://pypi.douban.com/simple/ pypi.douban.com 豆瓣
aliyun http://mirrors.aliyun.com/pypi/simple/ mirrors.aliyun.com 阿里云
tsinghua https://pypi.tuna.tsinghua.edu.cn/simple/ pypi.tuna.tsinghua.edu.cn 清华大学
ustc https://pypi.mirrors.ustc.edu.cn/simple/ pypi.mirrors.ustc.edu.cn 中国科学技术大学
hustunique http://pypi.hustunique.com/simple/ pypi.hustunique.com 华中理工大学
sdutlinux http://pypi.sdutlinux.org/simple/ pypi.sdutlinux.org 山东理工大学
tencent http://mirrors.cloud.tencent.com/pypi/simple/ mirrors.cloud.tencent.com 腾讯云
阅读更多
Python脚本作为配置文件加载

Python脚本作为配置文件加载

背景

在使用 Python 开发时,如果要把对象 obj 当作字典使用,可以直接操作 obj.__dict__(如果有的话),具体而言:

对象操作 字典操作
obj.foo obj.__dict__["foo"]
obj.foo = "bar" obj.__dict__["foo"] = "bar"
del obj.foo del obj.__dict__["foo"]

对象操作和字典(这里指的是对象的命名空间)操作并不等价,字典操作并不执行复杂的方法查找描述符,步骤更少,一般而言更快。

阅读更多
Python在命令行修改Properties配置文件

Python在命令行修改Properties配置文件

背景

我在平常的工作中,经常需要修改配置文件。配置文件的格式多种多样,有一种配置文件最为常见,就是每一行形如 name=value 格式,例如 Java Properties。在编写这个脚本以前,我常常用 sed 命令来做增删改查,不过我觉得这并不足够方便

于是我专门写了一个 Python 命令行工具,来批量增删改查上述格式的配置文件,使用时注意要给用户对被处理的配置文件授予必要权限,比如 rw

阅读更多
Python函数作为命令行使用

Python函数作为命令行使用

背景

我最近了解了一个快速构建命令行的工具 typer,受到了一些启发。
它可以把一组带有类型注解的 Python 函数,快速地转换成命令行工具。我尝试只用 Python 的内建包,不引入第三方依赖,也实现一个类似的命令行快速构建工具。代码会持续更新,之后会加入更强的功能。

阅读更多
Python把HTML中的img元素的src转换成datauri

Python把HTML中的img元素的src转换成datauri

背景

有时候,我们编写完 markdown 文档,为了便于分享阅读,会把它转换成 HTML 文档。但是,大多数的 markdownHTML 工具,只会保留外部资源链接,而不是把资源整合到 HTML 文档之中。如果是网络资源,只要联网就能下载,如果是本地资源,那么必须把对应文件也一起打包,分享给别人。

我个人觉得,分享一个单独的 HTML ,而不是一个 HTML 以及一堆文件的打包,可以更方便用户的阅读。这里,我分享一个 Python 脚本,可以把一个 HTML 文档中所有 <img> 元素中的 src 属性的值,转换成 datauri (更现代的称呼是 data URL,详阅:Data URLs | MDN

阅读更多
CPython中函数引用它自身

CPython中函数引用它自身

⚠️ 请确保CPython的版本不低于3.8,因语法涉及2个PEPPEP570PEP572

问题

启发自这篇问答:Is there a generic way for a function to reference itself?
曾有一个提议PEP 3130 – Access to Current Module/Class/Function,但是因为方案不完善而被拒绝了

就像__class__在函数体内指向于调用这个函数的类,是否有一个指针或者说魔法关键词,例如__func__,在函数体内使用时,能指向被调用的函数本身?因此,我可以写出像下面这样的代码:

1
2
3
4
5
def foo():
print(__func__.__name__)
print(__func__.__hash__)
print(__func__.__code__)
... # other simliars
阅读更多
掩码(Python实现)

掩码(Python实现)

关于掩码

什么是标志flag

在掩码的语境下,标志flag,是只有1位的掩码,取值范围$range(\mathrm{flag})$满足:
$$range(\mathrm{flag}) = {0, 1}$$

flag可以是一个单纯的取值范围为${0,1}$的二值的状态量,也可以是相对于另一个取值范围是${s_1, s_2}$的二值的状态量state,所建立一一映射
$$\mathrm{flag}: {s_1, s_2} \leftrightarrow {0,1}$$

Note 更一般而且常见的,标志flag是一个离散的状态量,取值范围是自然数集$\N$的子集。它可以是单纯的状态量,也可以是:设存在一个状态量state,它的取值范围$range(\mathrm{state})$是离散的,flag是$range(\mathrm{state})$到自然数集$\N$的映射
$$\mathrm{flag}: range(\mathrm{state}) \to \N$$
。也即,使用不同的自然数来分别枚举和指代状态量state的各个状态值。

阅读更多
Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×