Pythonを勉強し始めたものですが、関数の括弧の中に変数を指定するものと、
"."を用いてメソッドとして指定するものの違いは何でしょうか?
例えば、以下のコードが該当します。
import numpy as np
x = np.array([1,2,3])
len(x) #3
x.mean() #2.0
x.len() #エラー
mean(x) #エラー
なぜ、len関数は括弧内に変数に入れて、meanは変数の後にメソッドで指定するのか、
その背後にある考え方について教えていただけないでしょうか?
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答5件
0
質問に直接答えますと:
メソッドはオブジェクトに付随する性質です。
オブジェクト指向で書かれているのであれば、実装はオブジェクト(クラス)でなされます。
それに対して関数はある機能を実現するために書かれることが多いです。
例えば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総合スコア8562
0
ベストアンサー
回答する範囲を見極めるのがちょっと難しい質問に見えました。
必ずしも他の方の回答と違うことを言っているわけではないですが・・・
###関数とメソッドの違い
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
総合スコア18400
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
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総合スコア3601
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/04/29 05:29 編集
2018/04/29 05:54
2018/04/29 05:59
2018/04/29 06:24
2018/04/29 06:44
0
関数とメソッドというのは基本的に同じものです
なぜ、len関数は括弧内に変数に入れて、meanは変数の後にメソッドで指定するのか、
その背後にある考え方について教えていただけないでしょうか?
これはたんにlen関数は引数を一つ取る関数で、meanメソッドは引数無しで呼び出すメソッドだから、です。背後も考え方も関係ありません。
逆に、引数なしの関数もありますし、引数を持つメソッドもあります
で、メソッドというのは、クラス内で定義される関数です。
で、そのクラス内の関数は、当然ながらそのクラスの状態を取ってきたりクラスの状態をセットしたりする用途のものとなります
それに対し、独立した関数は、クラスに縛られない用途の関数となりますね
投稿2018/04/29 03:14
総合スコア88024
0
まず、言語仕様的にはとっちでも作れます。
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総合スコア30935
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/04/29 06:13
2018/04/29 06:21
2018/04/29 06:31
2018/05/01 00:25
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/04/29 05:09
2018/04/29 05:15