LoginSignup
0
0

More than 3 years have passed since last update.

Pythonの高階関数(デコレータ)のサンプル

Last updated at Posted at 2020-07-11

自前のマシンではSchemeで各種ツールやWebスクリプトを作ってきたが,昨今の安価・高機能・高性能なPaaS,SaaSでSchemeに対応しているはずもなく,代替言語としてのPythonで,Schemeの特徴のひとつである高階関数を扱うためのサンプルを作成・整理した.

なお,高階関数(Higher-order Function)とは,簡単に言えば『関数自体を値として引数にとったり戻り値としたりする関数』である.詳細は,『Structure and Interpretation of Computer Programs』"1.3 Formulating Abstractions with Higher-Order Procedures"を参照.

高階関数の定義と利用

Pythonでもlambdaが使えるが単一の式としてしか扱えないため,defでローカル定義した関数を返す書き方が一般的らしい.

higherorder.py
def threetimes(f):
    def retfunc(x, y):
        print(f(f(f(x, y), y), y))
    return (retfunc)

def f(x, y):
    return (2 * x + y)

threetimes(f)(10, 5)
# => f(f(f(x, y), y), y)
# => (2 * (2 * (2 * 10 + 5) + 5) + 5) => "115"

def threetimes_message(mes = ""):
    def _threetimes(f):
        def retfunc(x, y):
            print(mes, end="")
            print(f(f(f(x, y), y), y))
        return (retfunc)
    return (_threetimes)

threetimes_message("Result = ")(f)(10, 5)
# => "Result = 115"

threetimes_message()(f)(10, 5)
# => "115"

なお,対応するSchemeコードの例は次の通り.実行はGaucheで確認.

higherorder.scm
(define threetimes
  (lambda (f)
    (lambda (x y)
      (print (f (f (f x y) y) y)))))

(define f (lambda (x y) (+ (* 2 x) y)))
((threetimes f) 10 5)
; => (f (f (f 10 5) 5) 5)
; => (+ (* 2 (+ (* 2 (+ (* 2 10) 5)) 5)) 5) => "115"

(define threetimes_message
  (lambda (f . mes)
    (lambda (x y)
      (if (not (null? mes)) (display (car mes)))
      (print (f (f (f x y) y) y)))))

((threetimes_message f "Result = ") 10 5)
; => "Result = 115"
((threetimes_message f) 10 5)
; => "115"

デコレータ

高階関数を使用する際のsyntax sugar.語源は,デザインパターンの一種.Flaskなどのフレームワークを高階関数群として定義し,本来の処理を行うユーザ定義関数に機能追加するようにしたい場合に便利な書き方.

decorators.py
# threetimes,threetimes_message は higherorder.py の定義を使用

@threetimes
def f(x, y):
    return(2 * x + y)

f(10, 5) # => "115"

@threetimes_message(mes = "Result = ")
def f(x, y):
    return(2 * x + y)

f(10, 5) # => "Result = 115"

@threetimes_message()
def f(x, y):
    return (2 * x + y)

f(10, 5) # => "115"

lambda等を使ったその他サンプル

Wikipediaの記事(高階関数)にある例をいくつか抜粋.

others.py
def args_10_5(f):
    def _args_10_5():
        f(10, 5)
    return (_args_10_5)

def f(x, y):
  print("x = ", x, ", y = ", y)

args_10_5(f)() # => "x =  10 , y =  5"

def f(x, y, z, w):
  return (4 * x + 3 * y + 2 * z + w)

f(2, 3, 4, 5) # => 30

def f(x):
    return (lambda y: lambda z: lambda w: 4 * x + 3 * y + 2 * z + w)

f(2)(3)(4)(5) # => 30

def unfold(pred, f, update, seed):
    if pred(seed):
        return ([])
    else:
        r = unfold(pred, f, update, update(seed))
        r.insert(0, f(seed))
        return (r)

unfold(lambda x: x > 10, lambda x: x * x, lambda x: x + 1, 1)
# => [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0