Pythonでは、メソッドの代わりに関数を使うべきですか?

Zen of
Pythonでは、1つの方法しかないはずですが、しばしば、関数をいつ使うべきか、いつメソッドを使うべきかを決める問題にぶつかります。

簡単な例、ChessBoardオブジェクトを考えてみましょう。ボード上で利用可能なすべての合法的な王の動きを得るための何らかの方法が必要だとしましょう。私たちはChessBoard.get_king_moves()やget_king_moves(chess_board)を書いていますか?

私が見たいくつかの関連する質問があります:

私が得た答えは大したものではありませんでした。

Pythonはいくつかの機能(list.index()など)ではなく、他の機能(len(list)など)のためにメソッドを使用するのはなぜですか?

     

主な理由は歴史です。関数は、あるタイプのグループに対して一般的であったものと、
  メソッドをまったく持たないオブジェクトであっても動作することを意図していました
  (例えばタプル)。それが可能な機能を持つことも便利です
  あなたが使用するときにオブジェクトのアモルファスコレクションに簡単に適用することができます
  Pythonの機能的な機能(map()、apply()など)。

     

実際には、組み込み関数としてlen()、max()、min()を実装する方が、実際には各型のメソッドとして実装するよりコードが少なくなります。
  個々のケースについては気にすることができますが、それはPythonの一部です
  このような根本的な変更を行うのは時期尚早です。関数には
  膨大なコードの破損を避けるために残しておいてください。

興味深いものの、上記のことは実際に採用する戦略についてはあまり言いません。

これが理由の1つです。カスタムメソッドでは、開発者は
  getLength()、length()などの別のメソッド名を自由に選択できます。
  getlength()または何でも。 Pythonは厳密な命名規則を適用して、
  共通の関数len()を使うことができます。

やや面白い。私の考えでは、機能はある意味でPythonバージョンのインタフェースです。

最後に、
rel=”nofollow noreferrer”> Guidoから

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 become

class 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
.

Hm. I’m not sure I agree (figure that :-).

There are two bits of “Python rationale” that I’d like to
explain first.

First of all, I chose len(x) over x.len() for HCI reasons
(def __len__() came much later). There are two
intertwined reasons actually, both HCI:

(a) For some operations, prefix notation just reads better than
postfix — prefix (and infix!) operations have a long tradition in
mathematics which likes notations where the visuals help the
mathematician thinking about a problem. Compare the easy with which
we rewrite a formula like x*(a+b) into x*a +
x*b
to the clumsiness of doing the same thing using a raw OO
notation.

(b) When I read code that says len(x) I
know that it is asking for the length of something. This
tells me two things: the result is an integer, and the argument is
some kind of container. To the contrary, when I read
x.len(), I have to already know that x is
some kind of container implementing an interface or inheriting from
a class that has a standard len(). Witness the
confusion we occasionally have when a class that is not
implementing a mapping has a get() or
keys() method, or something that isn’t a file has a
write() method.

Saying the same thing in another way, I see ‘len’ as a built-in
operation. I’d hate to lose that. I can’t say for sure
whether you meant that or not, but ‘def len(self): …’ certainly
sounds like you want to demote it to an ordinary method. I’m
strongly -1 on that.

The second bit of Python rationale I promised to explain is the
reason why I chose special methods to look __special__
and not merely special. I was anticipating lots of
operations that classes might want to override, some standard (e.g.
__add__ or __getitem__), some not so
standard (e.g. pickle’s __reduce__ for a long time had
no support in C code at all). I didn’t want these special
operations to use ordinary method names, because then pre-existing
classes, or classes written by users without an encyclopedic memory
for all the special methods, would be liable to accidentally define
operations they didn’t mean to implement, with possibly disastrous
consequences. Ivan Krstić explained this more concise in his
message, which arrived after I’d written all this up.

— –Guido van Rossum (home page: http://www.python.org/~guido/)

これについての私の理解は、ある場合には接頭辞表記がちょうど理にかなっているということです(つまり、Duck.quackは言語的観点からquack(Duck)よりも理にかなっています)。

そのような場合、私の推測は、Guidoの最初の点にのみ基づいてget_king_movesを実装することです。しかし、これは、スタックやキュークラスを同様のプッシュ/ポップメソッドで実装することは、関数やメソッドでなければいけないということに関して、未だに多くの未解決の問題を残しています。
(私は本当にプッシュポップインターフェースを知らせたいので、ここでは関数を推測します)

TLDR:誰かが、どのような方法で関数を使うべきかを決める戦略を説明することはできますか?

ベストアンサー

私の一般的なルールは次のとおりです。オブジェクトまたはオブジェクトで実行される操作ですか?

オブジェクトによって行われた場合は、メンバ操作でなければなりません。それが他のものにも当てはまるか、あるいはオブジェクトに何か他のものによって行われた場合、それは関数(または、おそらく他のもののメンバー)でなければなりません。

プログラミングを導入するとき、車のような実世界のオブジェクトに関してオブジェクトを記述するのは伝統的です(実装は間違っていますが)。あなたはアヒルに言及していますので、それを行こう。

class duck: 
    def __init__(self):pass
    def eat(self, o): pass 
    def crap(self) : pass
    def die(self)
    ....

「オブジェクトは本当のものです」という文脈では、オブジェクトが行うことのできるもののクラスメソッドを追加するのは「正しい」です。だから私はアヒルを殺したいと言っています。
。アヒルに殺す()?いいえ…私が知っている限り、動物は自殺しません。だから私がアヒルを殺したいなら、私はこれをするべきです:

def kill(o):
    if isinstance(o, duck):
        o.die()
    elif isinstance(o, dog):
        print "WHY????"
        o.die()
    elif isinstance(o, nyancat):
        raise Exception("NYAN "*9001)
    else:
       print "can't kill it."

この類推から離れて、なぜメソッドとクラスを使うのでしょうか?データを格納し、将来的に再利用可能で拡張可能なようにコードを構築したいと思っているからです。これは、オブジェクト指向設計にとても愛されているカプセル化の概念に私たちをもたらします。

カプセル化プリンシパルは、実際には次のようになります。設計者は、実装やクラス内部に関するすべてを隠すべきです。ユーザーや他の開発者が必ずしもアクセスする必要はありません。クラスのインスタンスを処理するため、これは「このインスタンスでどのような操作が重要か」になります。操作がインスタンス固有でない場合は、メンバー関数であってはなりません。

: what @Bryan said. If it operates on an
instance and needs to access data which is internal to the class
instance, it should be a member function.

コメントする

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です