Python的Zen指出,只有一种方法可以做事情-但我经常遇到决定何时使用函数以及何时使用方法的问题。
让我们举一个简单的例子-ChessBoard对象。假设我们需要某种方式使董事会上所有合法的King举动均可用。我们是否编写ChessBoard.get_king_moves()或get_king_moves(chess_board)?
这是我看过的一些相关问题:
我得到的答案基本上没有定论:
为什么Python使用方法来实现某些功能(例如list.index()),却使用其他方法(例如len(list))呢?
主要原因是历史。函数用于那些对一组类型通用的操作,即使对于根本没有方法的对象(例如元组),这些操作也可以使用。使用Python的功能特性(map(),apply()等)时,具有可以轻松应用于对象的不定形集合的函数也很方便。
实际上,将len(),max(),min()实现为内置函数实际上比将它们实现为每种类型的方法要少。人们可能会质疑个别情况,但这是Python的一部分,现在进行这样的基本更改为时已晚。必须保留功能以避免大量代码损坏。
尽管很有趣,但是上面并没有真正说明采用哪种策略。
这是原因之一-使用自定义方法,开发人员可以自由选择其他方法名称,例如getLength(),length(),getlength()或其他名称。Python强制执行严格的命名,以便可以使用通用函数len()。
稍微有趣一点。我认为函数在某种意义上是接口的Pythonic版本。
最后,来自Guido本人:
谈论能力/接口使我想到了一些“流氓”特殊方法名称。在《语言参考》中,它说:“类可以通过定义具有特殊名称的方法来实现某些由特殊语法调用的操作(例如算术运算或下标和切片)。” 但是,所有这些带有特殊名称的方法(例如
__len__
或)__unicode__
似乎都是为内置函数的利益提供的,而不是为了支持语法。大概在基于接口的Python中,这些方法将在ABC上变成常规命名的方法,因此__len__
将成为class container: ... def len(self): raise NotImplemented
虽然,再想一想,我不明白为什么所有的句法运算都不会仅仅在特定的ABC上调用适当的通常命名的方法。“
<
”举例来说,大概会调用“object.lessthan
”(或者是“comparable.lessthan
“)。因此,另一个好处是能够使Python摆脱这种乱七八糟的名字,对我而言这似乎是HCI的改进。嗯 我不确定我是否同意(图:-)。
我首先要解释“ Python基本原理”的两个方面。
首先,出于HCI的原因,我选择了len(x)而不是x.len()(
def __len__()
后来出现了)。实际上,两个HCI相互交织在一起:(a)对于某些运算,前缀表示法比后缀读得更好-前缀(和infix!)操作在数学中具有悠久的传统,喜欢在视觉上帮助数学家思考问题的表示法。比较与我们改写像公式简单
x*(a+b)
到x*a + x*b
使用原始OO符号做同样的事情的笨拙。(b)当我读到说的代码时,
len(x)
我知道那是在问某物的长度。这告诉我两件事:结果是整数,参数是某种容器。相反,当我阅读本文时x.len()
,我必须已经知道这x
是一种实现接口或从具有standard的类继承的容器len()
。当未实现映射的类具有get()
或keys()
方法,或者不是文件的某些具有方法时,我们有时会感到困惑write()
。用另一种方式说同样的事情,我将'len'视为内置 操作。我不想失去那个。我不能肯定地说出您是否是那样的意思,但是“ def len(self):...”当然听起来像您想将其降级为普通方法。我对此坚决为-1。
我答应解释的Python基本原理的第二点是为什么我选择了特殊的外观
__special__
而不是仅仅 选择外观的原因special
。我期待类可能要覆盖的许多操作,一些标准(例如__add__
或__getitem__
),某些不是那么标准(例如,泡菜__reduce__
很长一段时间都不支持C代码)。我不希望这些特殊操作使用普通的方法名称,因为那样的话,预先存在的类或用户没有为所有特殊方法存储百科全书的用户编写的类可能会意外地定义它们并非要实现的操作,可能会造成灾难性的后果。伊万·科斯蒂奇(IvanKrstić)在他的信息中对此进行了更为简洁的解释,在我将所有这些内容写完之后,这些信息才得以体现。---Guido van Rossum(主页:http ://www.python.org/~guido/ )
我对此的理解是,在某些情况下,前缀表示法更有意义(即,从语言的角度来看,Duck.quack比quack(Duck)更有意义。)而且,该函数还允许使用“接口”。
在这种情况下,我的猜测是仅基于Guido的第一点实现get_king_moves。但这仍然存在很多悬而未决的问题,例如使用类似的push和pop方法实现堆栈和队列类-它们应该是函数还是方法?(在这里我会猜测功能,因为我真的很想发信号通知推送界面)
TLDR:有人可以解释决定何时使用函数还是方法的策略是什么?
X.frob
还是X.__frob__
独立的,都没有太大区别frob
。