Python的禅宗说,应该只有一种方法来做事情——但我经常遇到这样的问题:决定何时使用函数,何时使用方法。
让我们举一个简单的例子-棋盘对象。假设我们需要一些方法来获得董事会上所有合法的国王职位。我们是写棋盘,还是写棋盘?
下面是一些相关的问题:
我得到的答案基本上没有定论:Why does Python use methods for some functionality (e.g. list.index()) but functions for other (e.g. len(list))?
The major reason is history. Functions were used for those operations that were generic for a group of types and which were
intended to work even for objects that didn’t have methods at all
(e.g. tuples). It is also convenient to have a function that can
readily be applied to an amorphous collection of objects when you use
the functional features of Python (map(), apply() et al).
In fact, implementing len(), max(), min() as a built-in function is actually less code than implementing them as methods for each type.
One can quibble about individual cases but it’s a part of Python, and
it’s too late to make such fundamental changes now. The functions have
to remain to avoid massive code breakage.
虽然很有意思,但上面并没有说明该采取什么策略。This is one of the reasons - with custom methods, developers would be
free to choose a different method name, like getLength(), length(),
getlength() or whatsoever. Python enforces strict naming so that the
common function len() can be used.
稍微有趣一点。我认为函数在某种意义上是接口的Pythonic版本。Talking about the Abilities/Interfaces made me think about some of our
"rogue" special method names. In the Language Reference, it says, "A
class can implement certain operations that are invoked by special
syntax (such as arithmetic operations or subscripting and slicing) by
defining methods with special names." But there are all these methods
with special names like __len__ or __unicode__ which seem to be
provided for the benefit of built-in functions, rather than for
support of syntax. Presumably in an interface-based Python, these
methods would turn into regularly-named methods on an ABC, so that
__len__ would becomeclass container:
...
def len(self):
raise NotImplemented
Though, thinking about it some more, I don't see why all syntactic
operations wouldn't just invoke the appropriate normally-named method
on a specific ABC. "<", for instance, would presumably invoke
"object.lessthan" (or perhaps "comparable.lessthan"). So another
benefit would be the ability to wean Python away from this
mangled-name oddness, which seems to me an HCI improvement.
嗯。我不确定我是否同意。
我想解释两个“Python原理”
第一。
首先,我选择len(x)而不是x.len(),原因是HCI(def
__len__()来得晚了很多)。实际上,有两个相互交织的原因,两个HCI:
(a)对于某些操作,前缀表示法的读取效果比
后缀——前缀(和中缀!)手术有着悠久的传统
喜欢用符号表示的数学
数学家在思考一个问题。比较一下我们
将类似x*(a+b)的公式重写为x*a + x*b的笨拙
使用原始的OO符号做同样的事情。
(b)当我读到写着len(x)的代码时,我知道它要求的是
某物的长度。这告诉我两件事:结果是
整数,参数是某种容器。恰恰相反,
当我阅读x.len()时,我必须已经知道x是某种
实现接口或继承自
有一个标准的len()。见证我们偶尔的困惑
未实现映射的类具有get()或keys()
方法,或者不是文件的东西有一个write()方法。
用另一种方式说同样的话,我认为“len”是一个内置的
操作。我不想失去它。我不能肯定你是不是那个意思,但“def len(self):……”听起来确实像你
希望将其降级为普通方法。我强烈反对。
我承诺要解释的第二点Python原理是
为什么我选择特殊的方法来查看__special__,而不仅仅是
special。我预料到很多类可能需要的操作
要重写,有些标准(例如__add__或__getitem__),有些则不是
标准的(例如pickle的__reduce__很长一段时间在C中没有支持
完全是代码)。我不想这些特别行动用普通的
方法名,因为已存在的类,或由
对于所有的特殊方法,用户都没有百科全书式的内存,
可能会意外定义他们无意中定义的操作
实施,可能带来灾难性后果。伊万·克尔斯蒂奇
他在信中更简洁地解释了这一点
把这些都写出来了。
我对此的理解是,在某些情况下,前缀符号只是更有意义(即,从语言的角度来看,Duck.quack比quack(Duck)更有意义)并且,函数允许“接口”。
在这种情况下,我的猜测是仅仅基于Guido的第一点来实现get-king-u动作。但这仍然留下了很多问题,比如,用类似的push和pop方法实现堆栈和队列类——它们应该是函数还是方法?(在这里,我猜是函数,因为我真的想给push-pop接口发信号)
TLDR:有人能解释一下决定何时使用函数和方法的策略是什么吗?