質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.35%

  • Python

    9118questions

    Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

  • Python 3.x

    7324questions

    Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Pythonの関数とメソッドの違いについて

解決済

回答 5

投稿

  • 評価
  • クリップ 4
  • VIEW 2,789

MagMag

score 10

Pythonを勉強し始めたものですが、関数の括弧の中に変数を指定するものと、
"."を用いてメソッドとして指定するものの違いは何でしょうか?

例えば、以下のコードが該当します。
import numpy as np

x = np.array([1,2,3])
len(x) #3
x.mean() #2.0

x.len() #エラー
mean(x) #エラー

なぜ、len関数は括弧内に変数に入れて、meanは変数の後にメソッドで指定するのか、
その背後にある考え方について教えていただけないでしょうか?

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 5

+5

質問に直接答えますと:

メソッドはオブジェクトに付随する性質です。
オブジェクト指向で書かれているのであれば、実装はオブジェクト(クラス)でなされます。

それに対して関数はある機能を実現するために書かれることが多いです。
例えばnp.meanは平均値を計算します。

この時、np.mean(x)として、xがnp.arrayであれば、x.meanが実装されているので、それがそのまま呼び出されます。

xがリストだと、x.meanは定義されていないので、y = np.array(x)が実行されて、まずnp.arrayであるyが作られて、次にy.meanがコールされます。

lenの場合__len__が少し特殊なので難しいですが、試しに考えてみてください。
こちらの挙動がわかるようになれば初心者は脱出です。

そして、それぞれのオブジェクトにどのようなメソッドが実装されているのかを確認するには以下のやり方でできます。
メソッドだけでなく、変数なども含まれていることに注意する必要があるのはコメントにある通りです。


import numpy as np

a = np.arange(10)
print(dir(a))

使えるメソッドを確認できます。


さらに細かいことをいうと、lenはpythonの組み込み関数です。
https://docs.python.jp/3/library/functions.html#len
len(x)はxに__len__があればそれをコールする関数です。
なければエラーになります。intとか。

これに対してmeanはなくて、numpy.meanが定義されています。
その関係でxにx.meanが定義されていなければ、とりあえずnp.arrayにキャストすることを試みます。
なのでリストとかを入れても本当はmeanは定義されていなくてもnp.arrayにしてからmeanをコールするので、エラーにならないことがあります。
それでも文字列を入れたりすれば平均が取れないのでエラーになります。


かなり難しいことになってきますが、意識すべきことは、実装がどこにあるかを見極めることです。
その際にソースコードを読んだりすることや、vars/dirのようなメソッドを使いこなすことが役に立ちます。

今回の関連事項として、シンタックスシュガーをキーワードとして調べてみると理解を深められるかもしれません。
meanの場合は単なるシンタックスシュガーではありません。


最後に、
len(x) == x.__len__()です。
np.mean(x) == x.mean()はxがnp.arrayの時に限り必ず成り立ち、他の場合は実装次第です。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/04/29 14:09

    属性全部出るのでメソッドとは限らないのでは

    キャンセル

  • 2018/04/29 14:15

    おっしゃる通りです。
    メソッドは最低限全部出るのであのような書き方になりました。
    表示されたからといってメソッドとは限らないです。

    キャンセル

checkベストアンサー

+4

回答する範囲を見極めるのがちょっと難しい質問に見えました。

必ずしも他の方の回答と違うことを言っているわけではないですが・・・

関数とメソッドの違い

y_waiwaiさんがコメントしておられるように

  • 関数
    特定のクラスには縛られないもの。len()とかiter()とかnext()とか色々あります。その振る舞いを決めるのは引数だけです。

  • メソッド
    特定のクラス(またはそのクラスのインスタンス)専用のもの。その振る舞いを決めるのはやはり引数なのですが、インスタンスメソッドやクラスメソッドは暗黙的な第一引数にx.method(...)と書いたときのxが渡されるという機構によって「何に対して処理したいか」を「引数とは別の指定の仕方で明記することができる」文法が用意されています。質問者さんが

"."を用いてメソッドとして指定する

といっておられるタイプのものですね。

ただし"."がついていればメソッドというわけではない

これについて言及しておきたいと思いました。
x.foo()と書いたとき、xによってfooは関数の場合とメソッドの場合があります。xがクラスやクラスのインスタンスだった場合はメソッドです。しかしxがモジュールの場合はfooは関数です。

例1:メソッド

xにnumpy.ndarrayのインスタンスが入っている場合、x.reshape(...)のように書けますが、このreshapeはメソッドです。numpy.ndarrayのインスタンスに対する特別な機能を持つものです。xにintのインスタンス(例えば1とか)が入っている場合、x.reshape(...)と書いても'int' object has not attribute 'reshape'と怒られますね。intにはreshapeという名前の属性(メソッドも属性の一つです)はないというわけです。

例2: 関数

>>> import numpy as np
>>> np.reshape([1, 2], (2, 1))
array([[1],
       [2]])


上の例ではreshapeの左側にあるnpはモジュール(numpyモジュール)です。この場合のreshapeはメソッドではありません。numpyモジュールに定義されている関数です。その振る舞いは何か特定のクラスに対するものではありませんので、np.reshape(...)と書けばとりあえず関数は起動できます。もちろん関数の引数として受け入れられるものと受け入れられないものは関数ごとに決まってますのでその振る舞いは引数によって決まりますが。

背後にある考え方

関数は「引数だけで振る舞いが決まる」ものです。基本的にこれだけを使ってもプログラミングはできるのですが・・・メソッドを用いるともっと柔軟なことができます。特定のインスタンスに対してメソッドを起動するということの意味は「そのメソッドが起動された対象のインスタンスにある(メソッド呼び出しする側が一々引数に指定していない)属性の状態によって様々な柔軟な振る舞いができる)という点がポイントです。numpy.ndarrayについていえば、「要素のデータ型がなにか」「配列の形がどうなってるか」等々の様々な情報がインスタンスにおしこめられてますね。一度

a = np.array([[1, 2], [3, 4]], dtype=np.uint8)
なんてふうにインスタンスを生成しておけば
b = a.reshape((1, 4))
などとしたとき、データ型がuint8であるといったことは自動的にreshapeに認識されるわけです。起動対象のインスタンスの中にdtypeの属性が含まれていますので。

つたない日本語で頑張って説明を試みたのですが・・・伝わるかなぁ・・・

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/05/01 09:52

    関数はより広いクラスに対して適用し、メソッドは特定のクラスに対して活用することで、使い勝手や柔軟性を向上させるという考えですね。ありがとうございました。

    キャンセル

+3

関数とメソッドというのは基本的に同じものです

なぜ、len関数は括弧内に変数に入れて、meanは変数の後にメソッドで指定するのか、
その背後にある考え方について教えていただけないでしょうか? 

これはたんにlen関数は引数を一つ取る関数で、meanメソッドは引数無しで呼び出すメソッドだから、です。背後も考え方も関係ありません。
逆に、引数なしの関数もありますし、引数を持つメソッドもあります

で、メソッドというのは、クラス内で定義される関数です。
で、そのクラス内の関数は、当然ながらそのクラスの状態を取ってきたりクラスの状態をセットしたりする用途のものとなります
それに対し、独立した関数は、クラスに縛られない用途の関数となりますね

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/05/01 09:17

    ありがとうございました!

    キャンセル

+2

lenはobjectのlenにdelegateされてるはずですよ。試しにx.__len__()を呼び出してみて下さい。

mean(x)は単にmeanがスコープ内で定義されてないだけですね。np.mean(x)がそれですね。np.mean(x)とx.mean()はこの場合一致しますが、np.resizeは挙動が異なります。オブジェクト指向でも手続き型でもどっちでも対応出来るように用意されてるのだと思いますが、違いが気になるようでしたら都度確認しておくと安全かもしれませんね。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/04/29 14:12 編集

    x._len_()ですね(_は半角アンダースコア2つ)。markdown扱いされるせいで悲惨なことに・・・

    キャンセル

  • 2018/04/29 14:54

    回答本文ではバッククォートで囲み`x.__len__()`と書きなおしておくとよいと思います。ご存知かと思いますが。これpythonの話題では結構見落としがちですよね。自分もやってるかも知れません・・・

    キャンセル

  • 2018/04/29 14:59

    あら

    キャンセル

  • 2018/04/29 15:24

    一度にコメントできなくてすみません。`object.__len__`は未定義のようですね。`__len__`はsequenceのようなコンテナ的なものにのみ定義されているものということかと思います。

    キャンセル

  • 2018/04/29 15:44

    そうですね。lenは少し特殊で、あえてメソッドにしなかった経緯があったかと思います。ただそのソースを見つけられずにいますので、またちゃんと調べたら追記します。

    キャンセル

+2

まず、言語仕様的にはとっちでも作れます。

>>> class Myobj:
...     def __init__(self, objlen):
...         self.objlen = objlen
...     def __len__(self):
...         return self.objlen
...     def len(self):
...         return self.objlen
... 
>>> m = Myobj(10)
>>> len(m)
10
>>> m.len()
10


中の仕組みは(クラス定義のレベルでは)こうなってる訳です。

それで、背後にある考え方ですが、numpyはこっちも使えますからね。

>>> import numpy as np
>>> a = np.array([1,2,3])
>>> np.mean(a) # これは関数
2.0

両者のmeanは厳密には異なるのですが、この場合振る舞いは同じようなものです。

あまり考え方の違いとか、考えるだけ無駄な気がします・・・。

 余談

まあでも、だいたい次のような法則があり、組み込みや標準ライブラリの関数・オブジェクトは大半のものが従っています(すべてではないのが厄介なところ)。

  1. 破壊的な操作をする系のものは概ねメソッドにし、返り値はNone(list.sort()、list.reverse()などメソッドを呼んだ相手の中身が変わるもの)
  2. 非破壊的な操作は関数で、結果を返り値として返す(len()のようにオリジナルの中身に影響を及ぼさないものや、sorted()やreversed()など、オリジナルを変えないで新しい結果を作るもの・・・って今確認したらreversedはクラスだったよ! なんてこった! そういうこともありますね)
  3. どっちもほしいときとか、どっちでも良いときは割と両方作ってあったりする(list.sort()とsorted()の違いを考えてみましょう)
  4. 破壊的な操作をして更に結果を返すという関数/メソッドはほとんど見かけたことがない。あると便利だけど、それ以上に事故の元になるという発想だと思います。

これはPEPなどで明文化されてるのだろうか・・・。

 更に余談

なぜ、len関数は括弧内に変数に入れて、meanは変数の後にメソッドで指定するのか、
その背後にある考え方について教えていただけないでしょうか?

上の私の回答はこれへの直接の回答になってないかもなので、追記。
len()の方は古(いにしえ)からある関数であります。オブジェクト指向原理主義者の人には「なんでメソッドにしないのよ」とよく言われるのですが(でも最近は見かけない気がする。古い記事でそういうのはたくさんある)、こういう理由でメソッドになっていないらしいです。

len が py3k でも 関数のままである理由 - methaneのブログ

numpyのmeanメソッドは、numpy作った人たちの思想です、としか言いようがないです。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/04/29 15:13

    4.にlist.__iadd__が該当すると思います。
    自分はhayataka2049さんのご意見(事故の元)に賛成です。
    list.__iadd__は「a+=[2]」が「a=a+[2]」と同じ意味であるような定義でよかったのではと感じてしまいます。このあたり設計者の感覚的なものなのでしょうがその感覚がよくわかりませんでした。

    キャンセル

  • 2018/04/29 15:21

    INPLACE_ADDはin-placeで処理したいという根強い需要に応えるために用意されたものと認識しています。listだとご利益はなさそうですが(appendで済む)、データ型によっては便利な訳で。
    これはバイトコードからして違いますから、区別のためにメソッドも分けるのは当然と思います。
    実際問題としてプログラマが直接list__iadd__を直接呼び出すことはまずなく(闇pythonで遊ぶなら別だけど)、常に累算代入「文」で内部的に呼ばれる訳ですから、個人的にはgoodな仕様だと思っています。

    キャンセル

  • 2018/04/29 15:31

    なるほど・・・a+=bがa=a+bだという捉え方は違ってて「inplace」がポイントなのですね。そう伺うと何を根拠にそういう仕様にしたのかが腑に落ちる気がしました。コメントいただき恐縮です。

    キャンセル

  • 2018/05/01 09:25

    余談の部分がお聞きしたかったところです。慣習も含めてそういった考えで実装されているのですね。
    ありがとうございました。

    キャンセル

同じタグがついた質問を見る

  • Python

    9118questions

    Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

  • Python 3.x

    7324questions

    Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。