在 Python 中,每个对象都有一个命名空间——对象的“属性”,可在该命名空间中访问,可以是方法、对其他对象的简单引用(可调用或不可调用),或者由描述符动态合成(普通属性可能存在于实例或类中,但描述符——包括作为综合方法的描述符的函数——仅在它们存在于类中时才使用,而不是在实例中;因此,特别是“特殊方法”只有在类中定义时才是特殊的,不是实例)。属性处理内置函数和特殊方法(getattr
, setattr
, __getattr__
, __setattr__
, ...)在对象的单个命名空间中以相同的方式工作,无论是否引用“普通属性”。
关键是对于任何 object a
,在 Python 中,a.b
可能是方法(或其他可调用)或不是:Python 编译器不知道(也不关心),您可以获取引用a.b
并(例如)将其作为参数传递,将其作为结果返回,将其附加到列表中,等等,这些操作都不意味着调用 a.b
. 如果并且当您想要(尝试和)调用a.b
时,您可以通过后缀括号显式地执行它:a.b()
如果您想在没有参数的情况下调用它。
在 Ruby 中,对象的方法和属性存在于不同的命名空间中(因此您可以拥有一个具有相同名称的方法和属性的对象,而在 Python 中则不能)并且隐式地“仅提及”无参数方法调用它(所以c=a.b
可能只是获取属性引用,或者它可能正在调用a.b()
;如果在b
中同时命名方法和属性a
,我不记得使用什么启发式规则来消除使用歧义)。因此,如果您只想获取方法引用(例如,存储在某个容器中或用作参数或返回值),然后执行调用,则使用不同的语法。
Smalltalk 也有单独的命名空间,比如 Ruby,但是你不能引用给定对象的“非方法”属性(每个对象只能“看到”它自己的属性),所以这种歧义不会出现(但你仍然有使用特定的消息来提取,然后调用“方法引用”)。