为什么/如何Pandas使用方括号与.loc和.iloc一起?

26

所以,.loc和.iloc不是您通常使用的函数。 它们以某种方式使用 [ 和 ] 来包围参数,使其可与普通数组索引进行比较。 但是,我从未在其他库中看到过这种用法(我能想到的可能只有numpy类似的东西,我忘记了),而且我不知道它在Python代码中是如何工作/定义的。

在这种情况下,括号是否只是一种语法糖,用于调用函数?如果是这样,那么如何使任意函数使用方括号而不是圆括号?否则,Pandas中它们的使用/定义有什么特殊之处?


4
方括号语法是针对特殊方法__getitem__的一种语法糖。所有对象都可以在其类定义中实现此方法,然后随后使用方括号进行操作。 - Ted Petrou
1
请查看Pandas索引和选择文档 - Scott Boston
1
你可以在这里查看源代码(https://github.com/pandas-dev/pandas/blob/master/pandas/core/indexing.py),它全部用Python编写。`__getitem__`方法在`_LocationIndexer`中定义。 - roganjosh
12
那个链接的问题与被问到的问题完全不相同。我相信有一个好的答案,但那不是它。@coldspeed - Ted Petrou
1
为什么这个问题被标记为重复?Doomb af @rayreng - Poojan
类似于语法糖,但更进一步的思路可能是使其看起来像R,或者像R一样,使其看起来像许多其他语言中对数组和映射/哈希的访问。这确实给寻找所调用的内容以及它如何工作增加了一些曲折。 - Chris
2个回答

13
注意: 这个答案的第一部分是对我回答的另一个问题的直接改编,该问题在此问题重新开放之前已经被回答。我在第二部分中详细解释了“为什么”。

所以,.loc和.iloc不是你通常使用的函数

实际上,它们根本不是函数。我将用loc举例,iloc类似(它使用不同的内部类)。 检查loc实际上是什么的最简单方法是:

import pandas as pd
df = pd.DataFrame()
print(df.loc.__class__)

打印

<class 'pandas.core.indexing._LocIndexer'>

这告诉我们,df.loc_LocIndexer类的一个实例。语法loc[]源自于_LocIndexer定义了__getitem____setitem__*,这些方法是Python在使用方括号语法时调用的方法。
因此,是的,方括号在技术上是一种语法糖,代表了某些函数调用,但不是你认为的那个函数(当然,Python以这种方式设计的原因有很多,我不会详细介绍,因为1)我不够专业,无法提供全面答案,2)网络上有很多更好的资源可供参考)。 *技术上,它的基类_LocationIndexer定义了这些方法,我在这里稍微简化了一下

Pandas为什么在使用.loc和.iloc时要使用方括号?

我进入了推测领域,因为我找不到任何明确谈论Pandas设计选择的文档,但是:我至少看到了选择方括号的两个重要原因。
第一个,也是最重要的原因是:你不能通过函数调用来执行方括号符号所能做的一切操作,因为在Python中,将值赋给函数调用是语法错误。
# contrived example to show this can't work
a = []
def f():
  global a
  return a
f().append(1) # OK
f() = dict() # SyntaxError: cannot assign to function call

使用圆括号进行“函数”调用时,调用底层的__call__方法(请注意,定义了__call__的任何类都是可调用的,因此“函数”调用是一个不正确的术语,因为Python不关心某些东西是否是函数或者只是像函数一样的行为)。
相反地,使用方括号会根据调用发生的时间(如果在赋值运算符的左侧,则调用__setitem__,否则调用__getitem__)来替代调用__getitem____setitem__。没有办法通过函数调用来模仿这种行为,您需要使用setter方法来修改数据框中的数据,但仍然不允许在赋值操作中使用它:
# imaginary method-based alternative to the square bracket notation:
my_data = df.get_loc(my_index)
df.set_loc(my_index, my_data*2)

这个例子让我想到了第二个原因:一致性。你可以通过方括号访问DataFrame的元素:
something = df['a']
df['b'] = 2*something

使用loc时,您仍然尝试引用DataFrame中的某些项,因此最好使用相同的语法而不是要求用户使用一些getter和setter函数(我认为这也更符合Python风格,但这是一个模糊的概念,我宁愿避开它)。


1
关于“为什么”部分,使用:进行切片可能是另一个原因。 - user202729
好观点!理论上,您可以通过显式传递“slice()”实例在函数中获得相同的效果,但那太糟糕了。 - GPhilo

2
在底层实现上,两者都使用了__setitem____getitem__函数。

3
除了使用方括号外,通过调用 getitem 你还能做些什么事情,而直接不使用它则不能实现这些功能,这并没有回答问题。 - Chris

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接