pandas作者当年遇到了什么麻烦,才设计出如此糟糕的警告机制

我是数据外星人 2024-02-21 01:20:20
前言

pandas 中有一个让人捉摸不透的警告:

有人说,你用了"链式赋值操作",你应该:

事实上,这样子也会出来警告:

警告信息真的让人无语。有一些无脑的教程会说,你得用 copy:

无缘无故为啥要复制一整份数据。难道每次赋值都要 copy ?

我在 pandas 专栏中也详细讲解了其中的原理,主要是驳斥了网络上一些无脑说法。今天我们换一个角度,尝试成为 pandas 作者,看看当时作者到底遇到了什么样的难题,使得他做出这样子设计。

从零开始

假设我们是 pandas 的作者,现在要设计数据表(DataFrame)的定义:

名字叫 MyFrame初始化的时候需要传入字典数据

看看怎么使用

实例化的时候,传入字典

筛选是数据表常规操作,添加一个 where 的函数:

功能实现不是本文重点,这里借用 pandas 实现行15:重点是,我们要返回一个全新的 MyFrame 对象。 因为我们不希望后续操作会影响原来的数据

现在可以条件筛选:

现在的问题是,筛选总是用 where 显得太啰嗦。在 python 中对集合的物件取出元素,是有专门的语法 [...] 。

行2:语法 对象[切片范围]

这不也是一种数据筛选的方式吗?我们自定义的类也能有这样子的语法支持吗?

魔法方法

从对象的角度来说,它只不过是数据与函数的结合体。显然语法中的 [] 应该是一个函数。但 python 中是不可能如下定义函数名字的:

行17:这违反了 python 定义函数名字的规则

python 的作者就想,既然特殊符号不行,那就用比较不常用又合法的函数名字代替吧。所以,集合的物件取出元素的函数名字如下:

行18: __getitem__(self,...) ,就表示当使用 语法 对象[0:-2] 会调用的函数行25:可以看到,最终仍然是调用之前定义的 where 函数(没必要重新实现一次)。

现在我们的数据表可以这样子使用:

语义感满满。

同样的套路,我们可以实现赋值操作。首先实现一个 update 函数

行39:注意,更新操作不需要返回新的对象,而是修改对象中的 data

重点来了, 索引赋值操作 同样有魔法方法:

行41:魔法方法名字: __setitem__(self, keys, new_value)行50:直接调用 update 函数即可

看看使用方式就很容易理解这个魔法方法:

行6:使用 update行7:使用索引赋值

以下是魔法方法调用示意图:

可以想象,当年 pandas 作者做到这一步也是信心满满,这语义牛逼了!但不出意外的话,很快就会出意外!

陷阱

许多初学者以为,索引赋值操作会执行2个步骤( 错误理解 ):

执行等号左边的筛选操作。调用了魔法方法 __getitem__ ,得到了一个新的数据表执行赋值操作

现在我们自己实现了一遍就清楚知道,实际上代码只调用了 __setitem__ 函数, 没有调用 __getitem__ ,因此不会产生任何新的对象。

再看下面的代码:

行7:看起来也是更新操作。但结果根本没有被更新

这里就会执行2个步骤:

执行等号左边第一个 f1[cond] ,也就是执行了一次 __getitem__ ,返回了一个全新的对象全新的对象执行赋值操作 ,执行了一次 __setitem__ ,完成赋值操作。注意,这一步执行的操作,不是作用在 f1 对象上

如果代码换一种写法,就很容易理解:

行5:f2 就是之前说的"新对象"行7:更新的是 f2 ,f2 也确实被更新。但我们却期望 f1 被更新

此时,pandas 的作者有点绝望了。因为这是 python 的机制,他无法改变。唯一能做的,就是做一个警告,用于提醒用户。

此时他灵机一动,想到了一个简单可行的机制。

警告机制

问题核心就在于:

既然是 __getitem__ 的祸,那就从这里做手脚吧。

首先,在对象初始化的时候,给一个标志属性:

行11:标记一个对象是否为影子对象,就类似之前例子中的 f2

在 __getitem__ 中,返回全新对象之前,修改新对象的 _shadow 属性:

行36:打标记

接下来就很简单,在 __setitem__ 里面,按需出警告:

行65-66:判断,出警告

实际使用:

这种警告机制的问题在于,大部分情况下,我们会无意识产生 "影子对象" 。比如最常见的一种情况:

行7:做了一次筛选行10:调用函数注意结果,是正确的,但仍然出现警告。 这就是为什么在我的 pandas 专栏中明确告诉大家,只要你明确知道需要修改的数据表对象,那就可以不用管这警告

你觉得这种设计思路是不是挺巧妙,同时又让人有点无语?

不要忘记一键三连。你的点赞、收藏、关注,是我创作的动力。

转发、关注、评论,获得本期源码和数据。

0 阅读:0

我是数据外星人

简介:感谢大家的关注