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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Python 3.x

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

関数

関数(ファンクション・メソッド・サブルーチンとも呼ばれる)は、はプログラムのコードの一部であり、ある特定のタスクを処理するように設計されたものです。

関数型プログラミング

関数型プログラミングとは、関数を用いて演算子を構築し、算出し、コンピュータプログラムを構成する枠組みです。

Q&A

解決済

2回答

599閲覧

高階関数の動作について

chem_search

総合スコア30

Python 3.x

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

関数

関数(ファンクション・メソッド・サブルーチンとも呼ばれる)は、はプログラムのコードの一部であり、ある特定のタスクを処理するように設計されたものです。

関数型プログラミング

関数型プログラミングとは、関数を用いて演算子を構築し、算出し、コンピュータプログラムを構成する枠組みです。

0グッド

2クリップ

投稿2021/10/30 11:34

前提・実現したいこと

みんなのPython(4th)の中動作ついて分からないことがありましたので、
教えて頂きたいです。

該当のソースコード

Python

1def logger(func): 2 def inner(*args): 3 print("引数:", args) 4 return func(*args) 5 return inner 6 7def accumulate(a, b): 8 return a + b 9 10newfunc = logger(accumulate) 11print(newfunc(1,2)) 12 13#出力 14#引数: (1, 2) 15#3 16

知りたいこと

最後の、print(newfunc(1,2))と言う部分なのですが、このnewfunc関数の引数1,2は
最初に定義したlogger関数の*argsに渡されているかと思います。
この動作がいまいち理解できません。

logger関数の内部でinner関数を定義して、そのinner関数の引数が*argsとなっているのに、
なぜnewfunc関数の引数が勝手にそこに渡されるのでしょうか。
logger関数はfuncという引数しか定義されていないのに、自動的にその内部に定義した関数に
引数が渡されるというのは、何か特別な仕組みがあるのでしょうか。

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

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

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

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

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

guest

回答2

0

既に解決積みですが、重要な点なので和つぃなりの回答を載せておきます。

こういう質問をされる方は、関数オブジェクトと、関数オブジェクトがバインドされている変数の関係が良くわかっていないか、あるいは関数の定義と関数の実行の関係が良くわかっていない場合が多いです。

最初に 公式ドキュメント 4.2. 名前づけと束縛 (naming and binding)を読んで束縛(バインド)を理解してください。

  • 関数オブジェクトと、関数オブジェクトがバインドされている変数の関係とは

maxという関数がありますが、これはmaxという名前が最大値を求める組込み関数に束縛されているということです。

例えば以下のコード実行で何が起きているかを理解してください。

python

1>>> maximum = max 2>>> print(maximum([1,2,3,0])) 33 4>>> print(maximum.__name__) 5max

maxmumもmaxもmaxという名前を持つ関数オブジェクトに束縛されている名前なのでどちらを使っても同じです。

次のコードはmaxとminの束縛を入れ替えるものです。

python

1>>> max, min = min, max 2>>> print(max([1,2,3,0])) 30 4>>> print(min([1,2,3,0])) 53 6>>> max, min = min, max 7>>> print(max([1,2,3,0])) 83
  • 関数の定義と関数の実行の関係とは

python

1def accumulate(a, b): 2 return a + b

このように関数を定義しても、足し算が実行されるわけではありません。
実行されたのは関数定義です。つまり足し算を行う関数オブジェクトが作られ、accumulateという名前がその関数オブジェクトに束縛されたのです。

この関数を実行してはじめて足し算が実行されます。

python

1>>> def accumulate(a, b): 2... return a + b 3... 4>>> print(accumulate(40, 2)) 542 6>>> print(accumulate('Hello, ', 'Python')) 7Hello, Python

ご質問に戻ると、

python

1def logger(func): 2 def inner(*args): 3 print("引数:", args) 4 return func(*args) 5 return inner

によって、innerという関数定義を行って、できた関数を返すようなloggerという関数が定義されます。
loggerという関数は定義されましたが、まだloggerは実行されていないので、innerという関数は定義されていません。

python

1newfunc = logger(accumulate)

を実行したときにその右辺であるlogger(accumulate)が実行され、このときinnerという関数オブジェクトが生成されて、loggerのローカル変数であるinnerがその関数オブジェクトに束縛されます。このときのinnerの関数定義では、引数funcが束縛されているのはaccumulateという関数オブジェクトです。
loggerはinnerをreturnするので、logger(accumulate)はinnerが束縛されているinnerという関数オブジェクトを返します。
代入文ですので、newfuncという名前が生成されたinnerという関数オブジェクトに束縛されます。

python

1print(newfunc(1,2))

を実行すると、newfuncという名前が束縛されている関数オブジェクトが(1, 2)を引数として呼び出されます。この関数呼び出し、つまり関数の実行の中で、func(*args)が呼び出されますが、このローカル変数funcの中身は関数オブジェクトinnerが定義されたときのfuncですので、そのときfuncという名前に束縛されていたaccumulateという名前の関数オブジェクトです。従って、func(*args)は(1, 2)を引数としてaccumulateという名前の関数オブジェクトを呼び出すことになります。

投稿2021/10/30 12:54

ppaul

総合スコア24666

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

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

chem_search

2021/10/31 13:02

とても丁寧に解説して頂きありがとうございます! まだ完璧とは言えませんが、理解が深まりました。 自分で色々なパターンを試してみて、動作に対する理解を深めてみます!
guest

0

ベストアンサー

最後の、print(newfunc(1,2))と言う部分なのですが、このnewfunc関数の引数1,2は

最初に定義したlogger関数の*argsに渡されているかと思います。
この動作がいまいち理解できません。

引数1,2が何に渡されているか?という理解に誤解があるようです。
logger関数ではなくlogger関数が返した**inner関数に**渡されています。
提示コードを簡略化した以下だと理解しやすいかと思います。

Python

1def logger(): 2 def inner(*args): 3 print("引数:", args) 4 return inner 5 6inner_f = logger() # inner関数が返る 7inner_f(1,2) # たんにinner関数を呼び出しているのと同じ 8#引数: (1, 2)

投稿2021/10/30 12:24

can110

総合スコア38266

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

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

chem_search

2021/10/30 12:32

なるほど、newfuncにはinner関数が代入されて、 newfuncの引数をinner関数が受け取っていると理解すればよいのですね。 提示して頂いたコードですっきりしました! ありがとうございます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問