前回のエントリ
の続き。
前回は下記sample1.pyから別の関数forloop()にもデコレーターを反映させたsample1fl.pyを作って、デコレーターは関数の一つ一つの出力をデコレートするのでは無く、全体をデコレートする事が分かった。
def deco(func): # decorator関数の宣言、funcにはfunction printscript()が引数として与えられる def wrapper(*args, **kwargs): # デコレーターの中身、*args, **kwargsはデコレートする関数の引数。幾つあっても大丈夫な書き方。 print('*'*len("Hello world")) func(*args, **kwargs) # 引数として渡された関数(printscript)を実行 print('*'*len("Hello world")) return wrapper @deco def printscript(): print("Hello world") printscript()
今回はforloop()関数は忘れて元のprintscript()を使用して、deco()を変更したdeco2()によるsample2.pyを使用して続ける。
def deco2(func): import os def wrapper(*args,**kwargs): res = '*'*(len("Hello world") + 3) + os.linesep res += '*' + func(*args,**kwargs) + '!' + '*' + os.linesep res += '*'*(len("Hello world") + 3) return res return wrapper @deco2 def printscript(): return "Hello world" print(printscript())
sample2.pyでは5行目、デコレーターの”func(args,*kwargs)”で引数として渡された関数printscript()の戻り値を加工している点が大きな違い。
ここで加工する為に、関数printscript()ではsample1.pyの時の’print(“Hello world”)’ではなく、’return “Hello world”‘としている。
returnで渡す = 加工できる形で戻している。
他には、デコレーターの中で変数”res”を設定し、そこに
アスタリスク(asterisk)”*”を元のHello worldの字数 + エクスクラメーションマーク(exclamation mark)”!”の1つ +前後の2つ
を最初と最後(4行目、6行目)に入れて、
5行目ではprintscript()の戻り値の後ろにexclamation markを追加した上で、この前後にasteriskを1つづつ追加、
4行目と5行目には末尾にos.linesepで改行を入れた。
この出来上がった”res”を関数wrapperからの戻り値とし、
その戻り値を受けたデコレーターの関数deco2からの戻り値wrapperとしています。
このwrapperからの戻り値が最終的にdeco2でレコレートされた関数printscript()の出力になる。
このsample2.pyのを実行した時の出力は下記。
見た目的には些細な違いだが、
asteriskが全体を囲む様になっている事、Hello worldにexclamation markが付いている事が分かる。
% python3 sample2.py ************** *Hello world!* **************
先程のsample2.pyでは、出力する文字を”Hello world”に決め打ちしていたので、自由に好きな文字で同様の事をしてみたい。
と言う事で加工した下記コードをsample3.pyとして保存する。
実行時に単語、文を続けて書けば、その単語、文をデコレートして出力するコード。
import sys if len(sys.argv) == 2: wd = sys.argv[1] else: wd = "" for i in range(1, len(sys.argv)): if i == len(sys.argv) - 1: wd += sys.argv[i] else: wd += sys.argv[i] + " " def deco2(func): import os def wrapper(*args,**kwargs): res = '*'*(len(wd) + 3) + os.linesep res += '*' + func(*args,**kwargs) + '!' + '*' + os.linesep res += '*'*(len(wd) + 3) return res return wrapper @deco2 def printscript(): return(wd) print(printscript())
1行目でモジュールsysをインポート、sys.argvでターミナルにおける実行コマンドの後に続けた文字列を取ってきて、その末尾にexclamation markをつけ、全体をasteriskで囲う。
sys.argvはリスト。
このリスト中身はsys.argv[0]はファイル名、sys.argv[1]以降はファイル名に続けて入力した文から来た「単語」が入る。「単語」はスペースで区切られた一塊を一つの「単語」として扱う。
「単語」を認識し、打った通りに変数wdに追加する為、if else文を使用。
最初から途中の「単語」は「単語」+ スペースでwdに追加、最後は「単語」のみの追加。
これで入力した通りの文字列となる。
デコレーターでこの文字列にexclamation markをつけ、全体をasteriskで囲う加工をし、出力する。
出力結果は下記の通り。
因みに、sys.argvの後に続ける文字列のPython’sの箇所に、アポストロフィー(apostrophe)”‘”が含まれているので、入力時にはエスケープのためのバックスラッシュ(backslash)”\”を”‘”の前に置いた”Python\’s”としている。
% python3 sample3.py Hello Python\'s World *********************** *Hello Python's World!* ***********************
これでどんな文字列を続けて書いても、exclamation markをつけ、全体をasteriskで囲う加工がされる様になった。
Decoratorから始まり脱線で終わった気がするけれど、前よりDecoratorが分かった気がするので良しとする。
11/10追記:pythonファイルの実行と出力結果のソースコードについて、Visual Studioでの出力結果を記載していた為にターミナル表記と異なっていた点を修正しました。
コメント