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

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

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

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

Q&A

解決済

2回答

787閲覧

decoratorのサンプルコードでのargsとkwargsの役割について

sequelanonymous

総合スコア123

Python 3.x

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

1グッド

0クリップ

投稿2018/08/10 02:09

編集2018/08/10 02:39

このようなサンプルコードをよく見かけますが、出力が同じでargsとkwargsのある意味がわかりません。
なんとなく、雰囲気でみなさん書いているのか、もしくは僕の理解が間違っているのか気になるのでご確認させてください。
個人的には、argsとkwargsはなくていいと思っています。さらに、コード内で入れ子にして def wrapper(): を記載する必要があるのかも疑問です、意図が理解できる方はおしえていただけませんか?何の確認のために記載するかわかりませんが、仮になにか確認のためにdef wrapper(): を書いているとしたら、どんな時にこういうコードを実際の開発でかきますか?

argsとkwargsの理解は以下です。

*args: 複数の引数をタプルとして受け取る

example

1def my_sum2(*args): 2 print('args: ', args) 3 print('type: ', type(args)) 4 print('sum : ', sum(args)) 5 6my_sum2(1, 2, 3, 4) 7# args: (1, 2, 3, 4) 8# type: <class 'tuple'> 9# sum : 10

**kwargs: 複数のキーワード引数を辞書として受け取る
**をつけた引数を定義すると、任意の数のキーワード引数を指定することができる。関数の中では引数名がキーkey、値がvalueとなる辞書として受け取られる。

example

1def func_kwargs(**kwargs): 2 print('kwargs: ', kwargs) 3 print('type: ', type(kwargs)) 4 5func_kwargs(key1=1, key2=2, key3=3) 6# kwargs: {'key1': 1, 'key2': 2, 'key3': 3} 7# type: <class 'dict'>

decoratorのサンプルコードでのargsとkwargs

argsとkwargs記載有りのコード

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() 13 14## -- End pasted text -- 15--start-- 16Hello Decorator 17--end--

argsとkwargs記載なしのコード

python

1def deco(func): 2 def wrapper(): 3 print('--start--') 4 func() 5 print('--end--') 6 return wrapper 7 8@deco 9def test(): 10 print('Hello Decorator') 11 12test() 13 14## -- End pasted text -- 15--start-- 16Hello Decorator 17--end--

この def wrapper()をデコレーターにすると(@wraps(func))どういうメリットがあるのでしょうか?
@wraps(func)
発展型の理解

from functools import wraps def validation_objecs(func): @wraps(func) def wrapper(request):     ....    ....    .... return func(request) return wrapper .... .... .... @validation_objecs def start_batch(request):       ....    ....    ....
tachikoma👍を押しています

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

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

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

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

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

guest

回答2

0

ベストアンサー

decorateする関数に引数がない場合は*args**kwargsはなくても問題ありませんが、引数を要求する関数をdecoratorでwrapするときには便利です。

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(name): 10 print(f'Hello Decorator - {name}') 11 12test("master") 13# --start-- 14# Hello Decorator - master 15# --end--

@wrapsなしだと何をwrapしたのか分からなくなってしまう問題があります。

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(name): 10 """How to use""" 11 print(f'Hello Decorator - {name}') 12 13print(test.__doc__) 14# None 15print(test) 16# <function deco.<locals>.wrapper at 0x102dc38c8>

@wrapsを使うと、もとのオブジェクトの属性を引き継ぐことができます。

Python

1def deco(func): 2 @wraps 3 def wrapper(*args, **kwargs): 4 print('--start--') 5 func(*args, **kwargs) 6 print('--end--') 7 return wrapper 8 9@deco 10def test(name): 11 """How to use""" 12 print(f'Hello Decorator - {name}') 13 14print(test.__doc__) 15# How to use 16print(test) 17# <function test at 0x102e98488>

投稿2018/08/10 02:22

編集2018/08/10 02:52
tachikoma

総合スコア3601

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

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

sequelanonymous

2018/08/10 02:35

つまり、 def wrapper(*args, **kwargs):の行が必要な理由は、decorateする関数に引数を追記し、それをデコレートされた関数を引数にとる関数の中で引数をうけとるために、入れ子で引数受け取る用の関数(def wrapper(*args, **kwargs):)を書く必要があるという理解であっていますでしょうか? また、デコレーターの発展系だと思いますが、以下の様なコードの場合、@wrapperの役割はどうでしょうか? ``` from functools import wraps def validation_objecs(func): @wraps(func) def wrapper(request): .... .... .... return func(request) return wrapper @validation_objecs def start_batch(request): ```
sequelanonymous

2018/08/10 02:40

上記の@wrapperについては、上記の質問に追記しました。
tachikoma

2018/08/10 02:43

その理解であっています。*args, **kwargsの仕組みを使っておくと、decoratorはwrapする関数がどんな引数を取るか知らなくて済みます。 functoolsのほうは少しお待ちを。単純にdecorateしてしまうと、もともとの関数に仕込んでいたdocstringなどの属性にアクセスできなくなってしまう問題があった気がします。
sequelanonymous

2018/08/10 04:20 編集

ありがとうございます。 > 単純にdecorateしてしまうと、もともとの関数に仕込んでいたdocstringなどの属性にアクセスできなくなってしまう問題があった気がします。 この点については、おっしゃる通りです。docstringなどの属性にアクセスできないです。しかし、@wrapsをかくことでどう処理の順番になるのか、困惑しています。 return wrapperがどこに正確には変えるのかが気になっています。
sequelanonymous

2018/08/10 04:58

そうですよね、不毛な質問でした。ありがとうございます!
guest

0

下記、コードは、start_batchが走る前に、start_batchの引数であるrequestオブジェクトを引数としてデコレーター(def validation_objecs(func):)におくり、def wrapper(request): を入れ子にして書くことでその引数を関数内にひきつぐようにしている。return func(request)で def wrapperの処理結果を出力し、その出力結果をreturn wrapperでまとめてデコレートされたstart_batchに値を渡す。

return func(request)は、デコレートされたメソッドを実行している。func = start_batch。

*@wraps(func)はデコレートされたメソッド内の__docs__を引き継いてくれる。@wrapsがないと引き継がれない。
*def wrapper(request):のwrapperとう命名は実際は何でもよいのだが、最後にreturnする名前と合わせる必要がある。

1 def deco(func): 2 @wraps(func) 3 def w(*args, **kwargs): 4 print('--start--') 5 func(*args, **kwargs) 6 print('--end--') 7 print("w"+str(w)) 8 9 return w 10 11 @deco 12 def test(name): 13 print(f'Hello Decorator - {name}') 14 15 test("master") ~
from functools import wraps def validation_objecs(func): @wraps(func) def wrapper(request):     ....    ....    .... return func(request) return wrapper .... .... .... @validation_objecs def start_batch(request):       ....    ....    ....

投稿2018/08/13 03:35

sequelanonymous

総合スコア123

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問