括号是一个运算符,叫做函数调用运算符。它的作用是对括号前面的表达式计算出的结果进行一次调用。
例如 df.unique 这个表达式,运算出来是一个函数。你到后面加一个括号,那就是把这个函数调用了。调用函数的结果是函数的返回值。
可调用的不仅仅是函数,在 python 中,所有实现了 __call__ 方法的对象都可以调用,当然函数也是一个对象,它本身也有 __call__ 方法。例如:print(3) 和 print.__call__(3) 都是一样的。
其实 print.__call__.__call__.__call__.__call__.__call__(3)也是一样的……
你可以定义一个类,例如:
class Cup(object):
def __call__(self):
return 'cup'
Cup().__call__() # => 'cup'
Cup()() # => 'cup'
Cup() # => Cup Object
它就是一个普通的类,但是你给它加个 __call__方法,它一样能运行,而且其它功能一点不受影响。
是不是觉得 Cup 后面跟了 2 个括号,特奇怪?
class Cup(object):
def __init__(self):
self.count = 0
def __call__(self):
self.count += 1
return self
def __repr__(self):
return "We are%dcups." % self.count
Cup()()()()()()()()()()() # => We are 9 cups.
哈哈,是不是很有趣?其实只要按照运算符一个一个的看就可以了,不能想当然,要理解它是真么意义。
比如,上面的 Cup 是一个类,在类后面加一个括号,结果是该类的一个实例。
Cup():一个 Cup 实例
这个实例后面加一个括号,那就是调用这个实例了,我们说过这是函数调用运算符。我们已经知道,调用一个对象就是调用它的 __call__方法,于是 python 就会去 Cup 类里寻找 __call__ 方法。
Cup()()<=>Cup().__call__()
找到了!原来是返回 'cup',于是它就返回 'cup' 了。如果找不到 __call__ 方法,它会报错说这个对象是不能调用的。
所以关键是分解,一个一个运算符去看,每一次运算后是什么结果,然后再用这个结果进行下一次运算。前后要逻辑严格,不要想当然,要知其所以然。到最后就自然而然了。