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

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

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

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

Q&A

解決済

3回答

610閲覧

高階関数の構造が理解できません。

a_441

総合スコア14

Python

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

1グッド

3クリップ

投稿2018/02/14 09:27

Python初心者です。書籍を購入して勉強していますが、内容を読んでも意味が分からない箇所があったので質問します。

書籍:Pythonプログラミング パーフェクトマスター (秀和システム)
バージョン:Python 3.7 64bit

P162 高階関数


コード)

①def attack_sound(a,s):
print(a,"-->",s)

......

②def run_something(func,arg1,arg2):
func(arg1,arg2)

......

③run_something(attack_sound,"ドロップショット","ポワーン")

実行結果: ドロップショット-->ポワーン


attack_sound()関数にはパラメーターが2つありますので、run_something()には関数オブジェクトを受け取るパラメーターと関数に渡す引数のための2つのパラメーターを用意しました。

以上が本の内容になります。

質問 ②の関数run_something()のパラメーター、arg1,arg2、また、その下のfunc(arg1,arg2)の役割がわかりません。
本によると、関数に渡すパラメーターだそうですが、①でパラメーターが(a,s)となっているのに、なぜ②でまた新しいパラメーターを定義する必要があるのですか?
①の関数でprint(a,"-->"s)、②でarg1,arg2を定義して③に行き、③の引数が(attack_sound,"ドロップショット","ポワーン")となっています。"ドロップショット","ポワーン"がarg1,arg2の引数だということまではわかりましたが、実行結果で「ドロップショット-->ポワーン」となり、②の引数と順番が異なり急に①で定義したprint(a,"-->"s)が反映されています。print()で、「①でprint(a,"-->"s)を定義したから実行結果は同じ形になるんだな」ということはわかりますが、構造自体がわかりません。

意味不明な文章で上手く説明できず申し訳ありませんが
よろしくお願いします。

退会済みユーザー👍を押しています

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

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

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

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

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

guest

回答3

0

ベストアンサー

なんというか、実用的でない例であるために混乱しているような気がします。
個人的に分かりやすいと思う例を挙げます。

別の例

Pythonのinput関数は、入力を文字列で返します。
ですから、数値の入力を得たい場合は、キャストしなければなりません。

『整数用』と『浮動小数用』の二つの関数を定義したとします。

Python

1def input_int(message): 2 tmp = input(message) 3 return int(tmp) 4 5def input_float(message): 6 tmp = input(message) 7 return float(tmp)

使うときはこんな感じです。

Python

1>>> hoge = input_int('整数を入れてね: ') 2整数を入れてね: 42 3>>> print(hoge, type(hoge)) 442 <class 'int'> 5>>> 6>>> fuga = input_float('小数を入れてね: ') 7小数を入れてね: 3.14 8>>> print(fuga, type(fuga)) 93.14 <class 'float'>

ここでは二つだけですが、全く同じような関数を複数書くのは無駄なように思えませんか?
こういうときに高階関数を使うと便利です。

Python

1def input_type(t_func, message): 2 tmp = input(message) 3 return t_func(tmp)

使うときはこんな感じ。

Python

1>>> hoge = input_type(int, '整数を入れてね: ') 2整数を入れてね: 42 3>>> print(hoge, type(hoge)) 442 <class 'int'> 5>>> 6>>> fuga = input_type(float, '小数を入れてね: ') 7小数を入れてね: 3.14 8>>> print(fuga, type(fuga)) 93.14 <class 'float'>

ちょっと発展

なお、高階関数はクロージャと深い結びつきがあります。
これはちょっと難しい概念ですが、例えば次のように利用できます。

Python

1def make_input_type(t_func): 2 def input_type(message): 3 tmp = input(message) 4 return t_func(tmp) 5 return input_type 6 7input_int = make_input_type(int) 8input_float = make_input_type(float)

使うときはこんな感じ。

Python

1>>> hoge = input_int('整数を入れてね: ') 2整数を入れてね: 42 3>>> print(hoge, type(hoge)) 442 <class 'int'> 5>>> 6>>> fuga = input_float('小数を入れてね: ') 7小数を入れてね: 3.14 8>>> print(fuga, type(fuga)) 93.14 <class 'float'>

とりあえず、ここでは同じことを何度も書かなくてよい、という明確なメリットが生じています。

投稿2018/02/14 10:30

編集2018/02/20 16:44
LouiS0616

総合スコア35660

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

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

a_441

2018/02/15 01:54

実用的な例を挙げてくださりありがとうございます。 理解できました!
guest

0

1は1だけで完結しなければならない、2は2だけで完結しなければならないと考えてはいかがでしょうか。

2だけ切り抜くと、

python

1def run_something(func,arg1,arg2): 2 func(arg1,arg2)

となり、run_something(...)の内部ではfuncarg1arg2欠かせない存在になっています。

もしrun_something(...)の中をfunc(a,s)などに変更すると、2だけ切り抜いた世界ではasも未知の変数にでエラーになってしまいます。

このように「変数は閉じた世界で既知でなければならない(≒閉じた世界で完結しなければならない)」と考えると良いと思います。

投稿2018/02/14 10:13

YouheiSakurai

総合スコア6142

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

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

a_441

2018/02/15 01:53 編集

分かりやすく説明して下さりありがとうございます。 そのような考え方で勉強を進めていきたいと思います!
guest

0

Pythonでは関数も普通の変数のように引数として渡すことができます。
質問文では自作の関数を使ったので少し混乱しているのかな?と思いましたので、少し違う例で説明してみたいと思います。直接の回答でなくてすみません。

下記にbuilt-in関数のabsとsumを使った例をかいてみたのですが、bar()を実行したときの結果を追いかけられますでしょうか?

python

1def foo(func, args): 2 print("fooの中です。funcの中身は-> ",func) 3 return func(args) 4 5def bar(): 6 print("test1 : abs") 7 a = foo(abs, -3) 8 print(a, "\n") 9 10 print("test2 : sum") 11 s = foo(sum, [1, 4, -3]) 12 print(s, "\n")

実行結果は

>>> bar() test1 : abs fooの中です。funcの中身は-> <built-in function abs> 3 test2 : sum fooの中です。funcの中身は-> <built-in function sum> 2

のようになります。

投稿2018/02/14 10:13

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

a_441

2018/02/15 02:01

回答ありがとうございます。理解できました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問