2016-04-11 2 views
0

私はこの(ダミーの例を)やりたい:Pythonでクラス定義内の非ローカルスコープにアクセスするには?

def func(): 
    nonlocal var 
    print (var) 

class A: 
    var = 'hola' 
    func() 

しかし、私が手:私は本当にするつもり何

は、メソッド名を追加している:「にSyntaxErrorなし非ローカル 『VAR』の結合が見つかりました」そのメソッドが装飾されている場合は、クラスのスコープ内のリストに追加します。このようなもの:

def decorator(func): 
    nonlocal decorated 
    decorated.append(func.__name__) 
    return func 

class A: 
    decorated = [] 
    @decorate 
    def f(self): 
     pass 
+1

'nonlocal'は、関数呼び出しではなく関数定義の範囲内にあります。関数呼び出しの範囲を調べる方法はありますが、可能であれば、それらを避けることが一般的に推奨されています。デコレータにリストを引数として渡すか、クラスデコレータを使ってクラスを後処理し、 'decorated'リストを設定してみてください。 – user2357112

答えて

1

Pythonでこれを行うことはできません。 locals()を使用すると、クラスの名前空間にアクセスできます。しかし、この時点で、興味のある変数をデコレータに渡すこともできます。

# using locals() 

def decorator(class_namespace): 
    def _decorator(func): 
     class_namespace["decorated"].append(func) 
     return func 
    return _decorator 

class A: 
    store = decorator(locals()) 

    decorated = [] 

    @store 
    def func(self): 
     pass 

    del store 

通常、一対のデコレータを使用するのは簡単です。 1つは関心のある機能をマークし、もう1つはそれらを収集する機能です。

from types import FunctionType 

def collect(cls): 
    for item in vars(cls).values(): 
     print(item) 
     if isinstance(item, FunctionType) and getattr(item, "marked", False): 
      cls.marked_funcs.append(item) 
    return cls 

def mark(func): 
    func.marked = True 
    return func 

@collect 
class B: 
    marked_funcs = [] 

    @mark 
    def func(self): 
     pass 

あなたのケースでは、クラスの最後に関数名のセットを作成する方が簡単かもしれません。例えば。

class C: 
    def func(self): 
     pass 

    func_names = [f.__name__ for f in [func]] 
+0

ありがとう!非常に明確で完全な答え – nadapez

0

どうしますか?

decorated = [] 

def decorator(func): 
    decorated.append(func.__name__) 
    def wrapper(self): 
     print('wrapper called') 
     func(self) 
    return wrapper 

class A: 
    @decorator 
    def f(self): print('function called') 

print(decorated) 
A().f() 

OUTPUT:

['f'] 
wrapper called 
function called 

注意:あなたはそれがA.varとして参照する必要がありますので、varはクラス変数であるので、あなたが説明してきた問題が発生しますが提供

コードAが定義される前にコードを使用しようとするので、コード内でそのことを行うことはできません。それは可能でしょう別のクラスだったら:

class X: 
    decorated = [] 

def decorator(func): 
    X.decorated.append(func.__name__) 
    return func 

class A: 

    @decorator 
    def f(self): 
     pass 

print(X.decorated) 

あなたが変数に割り当てるが、append()のようなメソッドを呼び出さない場合は、nonlocalを指定する必要はありませんのでご注意ください。

0
y = 20 
def f(): 
    x = 7 
    def g(): 
     nonlocal x # 7 
     global y # 20 
nonlocal

修飾子はモジュールスコープが含まれていない外側の関数スコープに名前を指します。一方、globalは補完します。したがって、nonlocalを間違って使用しています。

1

デコレータを使用して関数をマークし、デコレータを使用してすべての装飾された関数を返すクラスメソッドをデコレートします。

import inspect 

def decorate(func): 
    func.decorated = True 
    return func 

class A: 
    def foo(): 
     print('foo') 

    @decorate 
    def bar(): 
     print('bar') 

    @classmethod 
    def decorated(cls): 
     def is_decorated_method(obj): 
      try: 
       return inspect.isfunction(obj) and obj.decorated 
      except AttributeError: 
       # The object has no decorated attribute 
       return False 

     return [result[1] for result in inspect.getmembers(cls, predicate=is_decorated_method)] 

print(A.decorated()) 
# [<function A.bar at 0x6ffffc0aa60>] 
関連する問題