🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Python 3.x

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

Q&A

解決済

2回答

1178閲覧

Pythonでreturnの後に"関数名+()なし"を指定する効果について

arron

総合スコア34

Python 3.x

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

0グッド

0クリップ

投稿2021/02/11 01:37

前提・実現したいこと

デコレーターについて学習している中で、returnに関数名そのものを指定している例がありました。
添付コードのdeco関数最終行の"return wrapper"のところです。
returunの後には"関数名+()"かと思っていましたが、関数名+()で実行すると次のようなエラーが出ました。

returnの後に"関数名+()なし"を指定するのとどういう違いがあるのかよくわかりません。

とても基本的な質問だと思います。
すみません。宜しくお願い致します。

発生している問題・エラーメッセージ

Traceback (most recent call last): File "C:/Users/twig2/PycharmProjects/pythonProject/hello_world.py", line 216, in <module> test() TypeError: 'NoneType' object is not callable --start-- Hello Decorator --end-- Process finished with exit code 1

該当のソースコード

python

1def deco(func): 2 def wrapper(*args, **kwargs): 3 print('--start--') 4 func(*args, **kwargs) 5 print('--end--') 6 return wrapper 7 8@deco 9def test(): 10 print('Hello Decorator') 11 12test()

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

「関数そのもの」という考えかたは理解するのがちょっと難しいかもしれません。いろいろな例にあたって慣れるしかないと思います。

少しは理解の助けになればということで、ちょっと説明してみます。
まずは普通のデータについて。

python

1a = 'hello' 2A = a.upper()

aに文字列'hello'が入ると説明されますが、一歩踏みこむと、'hello'と記述すると文字列を表わすオブジェクトが作られて、= によって、 変数aに割り当てられれいる、ということになります。
aに入るのは、そのままの文字の並びではなく文字列型のオブジェクトで、いろいろな関数(メソッド)を持っています。 たとえば、その中のupperメソッドを使うと、AにHELLOという文字を表わる文字列オブジェクトガ入ります。

python

1d = {'身長':170, '体重':70} 2w = d.get('体重')

同様に、dに入るのは、身長と体重をキーに持つ辞書(dict)ですが、これも見たとおりではなく、辞書型を持つオブジェクトがdに入ります。 文字列のときと同様に、メソッドがあり、たとえば、valuesメソッドを呼ぶと、wには体重の値が入ります。
辞書型にはキーから値を取りだすための、特殊な構文があって、それは、[]を使うものです。

python

1w = d['体重']

とすることで、getメソッドどほぼ同じようなことができます。

このように、pythonで扱う各種データはオブジェクトであり、値やメソッドを持っています。そして、変数に代入したり、関数やメソッドの引数にしたり、返り値として返したりすることができます。

さて、関数についてはどうでしょうか。Cなどでは、関数は特別なもので変数に代入したり関数の引数にしたりなどはできません。
しかし、pythonなどの最近の言語(lispは昔からですが)では、関数そのものも関数オブジェクトとして定義されていて、他のオブジェクトと同様に変数に代入したり、引数にしたり、返したりすることができるようになっています。

python

1def x(): 2 print('this is x')

この構文は関数特有の構文ですが、やっていることは代入と同じで、定義の通りに作られた関数オブジェクトが作られて、変数xに代入されます。
オブジェクトのなで、あまり使われませんが、メソッドも持っています。

python

1def x(): 2 """ 3 関数xです。 4 """ 5 print('this is x') 6 7d = x.__doc__ 8print(d)

関数定義ときに説明文字列(docストリング)を付けておいて__doc__メソッドを呼ぶと、内容が取り出せます。

そして、その作った関数を関数として呼び出す方法が後ろに()をつけて中に引数を入れる構文です。

python

1x()

辞書のときにキーから値を取り出すときに[]を使ったのと同様です。

このように、pythonでは関数も、特殊な機能は持っていますが、他のオブジェクトと同様のオブジェクトであるということです。

どんな時に使うのかというのは、まあ、質問の元になっているデコレータなどは、この扱いでなければ実現できないものですが、簡単な例だとこんなものがあります。

python

1l = [1, -3, 2] 2 3print(sorted(l)) 4# [-3, 1, 2]

リストのソートです。何も指定しなければ小さい順に並べ変えてくれます。
このsorted関数に他の観点で並び変えたい場合、key引数というのがあって、これが「関数」を受け取ります。

python

1print(sorted(l, key=abs)) 2# [1, 2, -3]

ここでkeyに渡されているのがabs関数です。 これは引数の絶対値を返す関数で、結果として絶対値の小さい順に並べ変えられます。
ここで、関数を渡すことができなければ、sorted関数にその機能を盛り込むか、自分でそのような並べ替え関数を作らなければなりません。

こんな感じです。

投稿2021/02/11 06:52

TakaiY

総合スコア13756

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

arron

2021/02/11 08:27

とても丁寧に教えていただき大変助かりました。ありがとうございました。 関数をオブジェクトとして渡すということですね。 最後の例でabsが関数なのにうしろに()がついていないというのがとても分かりやすいと思いました。 おっしゃるようにもう少し例にあたって、慣れるしかなさそうです。 引き続きよろしくお願いいたします。
guest

0

returnの後に"関数名+()なし"を指定するのとどういう違いがあるのかよくわかりません。

return wrapperでは、関数そのものを返り値にします。return wrapper()では、関数の実行結果が返り値となります。

投稿2021/02/11 01:40

maisumakun

総合スコア145965

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

arron

2021/02/11 02:20

早速にありがとうございます。 「関数そのもの」を返り値にするというところがいまひとつわかりません。 deco関数の中で、wrapper関数を定義&実行する、ということなら6行目が次でもよさそうですが #6 wrapper() TypeError: 'NoneType' object is not callableが返ってきます。 基本がわかっていなくてすみません。
maisumakun

2021/02/11 02:33

> 「関数そのもの」を返り値にするというところがいまひとつわかりません。 Pythonでは、関数そのものも変数に入れて、引数にしたり返り値にしたりができるオブジェクトです。 「@deco(改行)def test()後略」と書くのは、「test = deco(defした関数)」と書くのと同じ意味になります。 なので、return wrapper()と書くと、testの値はwrapper()の返り値、つまりNoneになってしまいます。
maisumakun

2021/02/11 02:40 編集

> deco関数の中で、wrapper関数を定義&実行する decoの中で実行は「しません」。新しい関数を作って「関数を返す」ことがdecoの仕事です。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問