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

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

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

Python 2.7は2.xシリーズでは最後のメジャーバージョンです。Python3.1にある機能の多くが含まれています。

Python 3.x

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

Python

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

Q&A

解決済

1回答

6054閲覧

Pythonで クラス内において、関数内関数でdecoratorを使用したい

super_hogehoge

総合スコア29

Python 2.7

Python 2.7は2.xシリーズでは最後のメジャーバージョンです。Python3.1にある機能の多くが含まれています。

Python 3.x

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

Python

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

0グッド

1クリップ

投稿2016/10/24 04:22

###前提・実現したいこと

Pythonで クラス内において、関数内関数でdecoratorを使用したい

###発生している問題・エラーメッセージ

Traceback (most recent call last): File "deco2.py", line 23, in <module> temp.print_hoge() File "deco2.py", line 8, in inner func(*args, **kwargs) File "deco2.py", line 15, in print_hoge @decorator NameError: global name 'decorator' is not defined

###該当のソースコード

python

1class MyClass(object): 2 def __init__(self): 3 pass 4 5 def decorator(func): 6 def inner(*args, **kwargs): 7 print "pre_func" 8 func(*args, **kwargs) 9 print "after_func" 10 return inner 11 12 @decorator 13 def print_hoge(self): 14 15 @decorator #この行をコメントアウトすると問題無く動きます 16 def inner_print_hoge(): 17 print "inner_hoge" 18 19 print "hoge" 20 inner_print_hoge() 21 22temp = MyClass() 23temp.print_hoge()

###試したこと
【該当のソースコード】の「#この行をコメントアウトすると問題無く動きます」をコメントアウトすると動きます。ただ、関数内関数でクラス内にある
decoratorを使おうとすると上記のエラーが出てしまいます。

###補足情報(言語/FW/ツール等のバージョンなど)
いつも参考にさせていただいております。
数日前に質問させていただいたhttps://teratail.com/questions/52151
内容と近いので追記しようとも思ったのですが、広く皆様のお知恵をお借りしたいと思い新規に投稿させて
いただきました。

関数内関数で同じclass内にあるdecoratorを使うにはどう書けば良いのか分からないのでご教授下さい。
よろしくお願い致します。

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

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

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

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

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

yohhoy

2016/10/24 06:37

素直にdecoratorメソッドをグローバルスコープで定義すれば解決します。そうしない強い理由がありますか?
super_hogehoge

2016/10/24 08:48

ご確認ありがとうございます。強い理由は有りません。 ただ、実際にはクラス内でしか使用しない処理内容なのでなるべくclass内に置いてそこで完結させたいと考えています。 
guest

回答1

0

ベストアンサー

yohhoy様のおっしゃるように、decoratorメソッドをグローバルスコープで定義すれば解決します。

python

1def decorator(func): 2 def inner(*args, **kwargs): 3 print("pre_func") 4 func(*args, **kwargs) 5 print("after_func") 6 return inner 7 8 9class MyClass(object): 10 def __init__(self): 11 pass 12 13 @decorator 14 def print_hoge(self): 15 16 @decorator 17 def inner_print_hoge(): 18 print("inner_hoge") 19 20 print("hoge") 21 inner_print_hoge() 22 23temp = MyClass() 24temp.print_hoge()

クラス内でしか使用しない、ということであれば、MyClassとdecorator関数を、実行用のモジュールとは別にしてそれっぽいモジュール名をつけて一緒に置いておくだけで良いように感じます。
クラス内にデコレータを定義するのは、個人的にはあまりお勧めしません。

どうしても、ということであれば以下のようにして呼び出すことは可能です。
Python3系で動作します。

python

1class MyClass(object): 2 def __init__(self): 3 pass 4 5 def decorator(func): 6 def inner(*args, **kwargs): 7 print "pre_func" 8 func(*args, **kwargs) 9 print "after_func" 10 return inner 11 12 @decorator 13 def print_hoge(self): 14 15 @MyClass.decorator 16 def inner_print_hoge(): 17 print "inner_hoge" 18 19 print "hoge" 20 inner_print_hoge() 21 22temp = MyClass() 23temp.print_hoge()

投稿2016/10/24 11:30

編集2016/10/24 12:45
toritoritorina

総合スコア972

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

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

super_hogehoge

2016/10/24 11:44

回答ありがとうございます。 すいません、教えていただいたコードなのですが、python2.7.3の環境で動かないようです。何か別途宣言等必要でしょうか… >クラス内にデコレータを定義するのは、個人的にはあまりお勧めしません。 これはどのような理由からなのでしょうか、class内で完結する物は全て内部で完結させて 外部になるべく出さないという考えでclass内decoratorを用いていました。 何か指標となる考え方や、参考書籍等をご教授いただけると今後の勉強の 足がかりになるので参考にさせて下さい。 質問を御願いばかりして大変ご迷惑をお掛けしますが何卒よろしくお願い致します。
toritoritorina

2016/10/24 13:47 編集

まずですが、ある特定のクラスや機能と強い結びつきがある場合、そもそもデコレータを使用するのも少し考え直すべきです。 少し古い書籍ですが、「エキスパートPythonプログラミング」 https://www.amazon.co.jp/エキスパートPythonプログラミング-Tarek-Ziade/dp/4048686291 でもこのデコレータのベストプラクティクスについては触れられています。 しかし、ある特定のクラスや機能が巨大になってくると、そのためのデコレータを作らざるを得ないという場合も実際にはあるのも事実です。その場合でも、モジュールのグローバルな関数として定義をすることをお勧めします。 将来的に他のクラスでも使用する可能性がありますし、逆に言うと他の関数にも適用したくなるほどデコレータとは汎用的で、強力です。 また、PythonのZENにも「Flat is better than nested.」とある通り、あるモジュールのクラス内の関数としてデコレータを定義するよりは、モジュールの関数として定義するほうがフラットです。 フラットな方が見やすいですし、読む人間にとってはクラス内に書いてしまうと、考えたり見るべきことが増えます。 クラスやインスタンスの変数、関数を参照していないか、参照していればどこにあるだろうか、そこでは何の処理をしているか、なぜクラス内にあるのか、等です。 クラスやデコレータ関数のドキュメントでしっかりとガイドをしたとしても、モジュールのグローバスな関数に比べると手間が増えます。
toritoritorina

2016/10/24 12:58

Python2系だと少し厳しそうなため、回答にpython3系で動作と追記しました。
super_hogehoge

2016/10/25 02:03

toritoritorina様 ご回答ありがとうございます。 >Python2系だと少し厳しそうなため、回答にpython3系で動作と追記しました。 なるほど、教えていただいた内容を含めてクラス内decoratorはあまり褒められた方法では無いと理解しました。 違う方向で再度検討してみようと思います。 >少し古い書籍ですが、「エキスパートPythonプログラミング」 お薦めありがとうございます、過去数ページ読んで難しそうで回避していました…。 早速amazonで中古で注文しました。 >フラットな方が見やすいですし、読む人間にとってはクラス内に書いてしまうと、考えたり見るべきことが増えます。 何も考えず、必要無いものは一箇所に!という安直な考えを元にコードを書いていました。 今後はPythonのZEN等を参考により「pythonic」な書き方を心がけようと思います。 丁寧にご回答下さり、とても助かりました。 ありがとうございました、ベストアンサーとさせていただきます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問