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ページの「注目」タブのフィードに表示されやすくなります。
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
下記のような質問は推奨されていません。
- 間違っている
- 質問になっていない投稿
- スパムや攻撃的な表現を用いた投稿
適切な質問に修正を依頼しましょう。
回答5件
6
質問に直接答えますと:
メソッドはオブジェクトに付随する性質です。
オブジェクト指向で書かれているのであれば、実装はオブジェクト(クラス)でなされます。
それに対して関数はある機能を実現するために書かれることが多いです。
例えばnp.meanは平均値を計算します。
この時、np.mean(x)として、xがnp.arrayであれば、x.meanが実装されているので、それがそのまま呼び出されます。
xがリストだと、x.meanは定義されていないので、y = np.array(x)が実行されて、まずnp.arrayであるyが作られて、次にy.meanがコールされます。
lenの場合__len__
が少し特殊なので難しいですが、試しに考えてみてください。
こちらの挙動がわかるようになれば初心者は脱出です。
そして、それぞれのオブジェクトにどのようなメソッドが実装されているのかを確認するには以下のやり方でできます。
メソッドだけでなく、変数なども含まれていることに注意する必要があるのはコメントにある通りです。
python
1import numpy as np 2 3a = np.arange(10) 4print(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 03:23
編集2018/04/29 05:45総合スコア8554
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/04/29 05:08
総合スコア18378
良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
このような回答には修正を依頼しましょう。
回答へのコメント
3
lenはobjectの__len__にdelegateされてるはずですよ。試しにx.__len__()
を呼び出してみて下さい。
mean(x)は単にmeanがスコープ内で定義されてないだけですね。np.mean(x)がそれですね。np.mean(x)とx.mean()はこの場合一致しますが、np.resizeは挙動が異なります。オブジェクト指向でも手続き型でもどっちでも対応出来るように用意されてるのだと思いますが、違いが気になるようでしたら都度確認しておくと安全かもしれませんね。
投稿2018/04/29 03:30
編集2018/04/29 06:00総合スコア3599
良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
このような回答には修正を依頼しましょう。
こちらの回答が他のユーザーから「過去の低評価」という指摘を受けました。
回答へのコメント
2018/04/29 05:29 編集
2018/04/29 05:54
2018/04/29 06:24
3
関数とメソッドというのは基本的に同じものです
なぜ、len関数は括弧内に変数に入れて、meanは変数の後にメソッドで指定するのか、
その背後にある考え方について教えていただけないでしょうか?
これはたんにlen関数は引数を一つ取る関数で、meanメソッドは引数無しで呼び出すメソッドだから、です。背後も考え方も関係ありません。
逆に、引数なしの関数もありますし、引数を持つメソッドもあります
で、メソッドというのは、クラス内で定義される関数です。
で、そのクラス内の関数は、当然ながらそのクラスの状態を取ってきたりクラスの状態をセットしたりする用途のものとなります
それに対し、独立した関数は、クラスに縛られない用途の関数となりますね
投稿2018/04/29 03:14
総合スコア86044
良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
このような回答には修正を依頼しましょう。
回答へのコメント
2
まず、言語仕様的にはとっちでも作れます。
python
1>>> class Myobj: 2... def __init__(self, objlen): 3... self.objlen = objlen 4... def __len__(self): 5... return self.objlen 6... def len(self): 7... return self.objlen 8... 9>>> m = Myobj(10) 10>>> len(m) 1110 12>>> m.len() 1310
中の仕組みは(クラス定義のレベルでは)こうなってる訳です。
それで、背後にある考え方ですが、numpyはこっちも使えますからね。
python
1>>> import numpy as np 2>>> a = np.array([1,2,3]) 3>>> np.mean(a) # これは関数 42.0
両者のmeanは厳密には異なるのですが、この場合振る舞いは同じようなものです。
あまり考え方の違いとか、考えるだけ無駄な気がします・・・。
余談
まあでも、だいたい次のような法則があり、組み込みや標準ライブラリの関数・オブジェクトは大半のものが従っています(すべてではないのが厄介なところ)。
0. 破壊的な操作をする系のものは概ねメソッドにし、返り値はNone(list.sort()、list.reverse()などメソッドを呼んだ相手の中身が変わるもの)
- 非破壊的な操作は関数で、結果を返り値として返す(len()のようにオリジナルの中身に影響を及ぼさないものや、sorted()やreversed()など、オリジナルを変えないで新しい結果を作るもの・・・って今確認したらreversedはクラスだったよ! なんてこった! そういうこともありますね)
- どっちもほしいときとか、どっちでも良いときは割と両方作ってあったりする(list.sort()とsorted()の違いを考えてみましょう)
- 破壊的な操作をして更に結果を返すという関数/メソッドはほとんど見かけたことがない。あると便利だけど、それ以上に事故の元になるという発想だと思います。
これはPEPなどで明文化されてるのだろうか・・・。
更に余談
なぜ、len関数は括弧内に変数に入れて、meanは変数の後にメソッドで指定するのか、
その背後にある考え方について教えていただけないでしょうか?
上の私の回答はこれへの直接の回答になってないかもなので、追記。
len()の方は古(いにしえ)からある関数であります。オブジェクト指向原理主義者の人には「なんでメソッドにしないのよ」とよく言われるのですが(でも最近は見かけない気がする。古い記事でそういうのはたくさんある)、こういう理由でメソッドになっていないらしいです。
len が py3k でも 関数のままである理由 - methaneのブログ
numpyのmeanメソッドは、numpy作った人たちの思想です、としか言いようがないです。
投稿2018/04/29 05:44
編集2018/04/29 06:10総合スコア30898
良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
このような回答には修正を依頼しましょう。
回答へのコメント
2018/04/29 06:13
2018/04/29 06:31
関連した質問
Q&A
解決済
最速で配列からデータを取り出し、正規表現で検索したい。
回答3
クリップ1
更新
2023/01/31
Q&A
解決済
住所を3つに区分し抽出した時のエラー対応
回答1
クリップ0
更新
2023/02/02
Q&A
解決済
classの中の、整数と文字を一緒にアウトプットするメソッドの記述について
回答3
クリップ0
更新
2023/01/29
Q&A
受付中
Google Colaboratoryを使った機械学習でイメージのサイズが合わない
回答1
クリップ0
更新
2023/02/01
Q&A
解決済
JDBCとJSPを用いた住所検索システムを作成したい
回答2
クリップ0
更新
2023/01/31
Q&A
解決済
グーグルコラボで今まで動いていたプログラムが、動かなくなりました
回答2
クリップ0
更新
2023/01/29
意見交換
受付中
Python:データフレームを列ごとにプロット
回答4
クリップ0
更新
2023/02/02
Q&A
受付中
JavaScriptでエラーをキャッチできる場合とできない場合の違い
回答4
クリップ3
更新
2023/01/31
同じタグがついた質問を見る
Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。
Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。
良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。
下記のような回答は推奨されていません。
このような回答には修正を依頼しましょう。
2018/04/29 05:09
2018/04/29 05:15