2016-04-11 8 views
0

Ich möchte diese (Dummy-Beispiel) tun:Wie Zugriff auf nonlocal Bereich innerhalb der Klassendefinition in Python?

def func(): 
    nonlocal var 
    print (var) 

class A: 
    var = 'hola' 
    func() 

Aber ich bekomme: „Syntaxerror: keine Bindung für nicht-lokale‚var‘gefunden“

Was will ich wirklich, ist ein Methodennamen anhängen zu einer Liste im Bereich der Klasse, wenn diese Methode eingerichtet ist. Etwas wie dieses:

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

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

'nonlocal' sucht im Gültigkeitsbereich der Funktionsdefinition, nicht den Funktionsaufruf. Es gibt Möglichkeiten, in den Bereich des Funktionsaufrufs zu schauen, aber es wird im Allgemeinen empfohlen, sie zu vermeiden, wenn es Ihnen möglich ist. Versuchen Sie, dem Dekorator die Liste als Argument zu geben, oder verwenden Sie einen Klassendekorator, um die Klasse nachzubearbeiten und die "dekorierte" Liste einzurichten. – user2357112

Antwort

1

Python lässt Sie das einfach nicht tun. Sie können auf den Klassennamespace zugreifen, indem Sie locals() verwenden. Aber an dieser Stelle können Sie die Variable, an der Sie interessiert sind, einfach an den Dekorateur übergeben.

# 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 

Im Allgemeinen ist es einfach, ein Paar Dekorateure zu verwenden. Eine, um die Funktionen zu markieren, an denen Sie interessiert sind, und eine, um sie zu sammeln.

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 

Aber in Ihrem Fall könnte es einfach einfacher sein, den Satz von Funktionsnamen am Ende der Klasse zu erstellen. z.B.

class C: 
    def func(self): 
     pass 

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

Danke! Sehr klare und vollständige Antwort – nadapez

0

Wie wäre das?

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 

NOTES:

Der Code, den Sie bereitgestellt erlebt das Problem, das Sie da var beschrieben habe, ist Klassenvariable, so dass es als A.var referenziert werden muss aber Sie können das nicht in Ihrem Code tun, weil Sie versuchen, es zu verwenden, bevor A definiert ist. wenn es verschiedene Klassen wären, würde es möglich sein:

class X: 
    decorated = [] 

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

class A: 

    @decorator 
    def f(self): 
     pass 

print(X.decorated) 

Bitte beachten Sie, dass Sie nicht nonlocal angeben müssen, wenn Sie nicht zuordnen zu variabel, aber Aufruf Methoden wie append().

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

nonlocal Qualifier bezieht sich auf einen Namen in dem äußeren Umfang-Funktion, die das Modul nicht Umfang enthält. Während global tut das Komplementär. Sie verwenden also nonlocal falsch.

1

Verwenden Sie den Dekorateur, um die Funktionen zu markieren, dann haben Sie eine Klassenmethode eingerichtet, die alle dekorierten Funktionen zurückgibt.

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>] 
Verwandte Themen