First off, der direkte Ansatz, wenn the CO_NESTED
flag is set on the function's code object zu überprüfen ist:
import inspect
...
def is_nested(func):
return func.__code__.co_flags & inspect.CO_NESTED
def deco(func):
if is_nested(func):
# This is a nested function, return it unchanged
return func
... otherwise, do your decoration here ...
That sagte, es gibt einen anderen Ansatz, wenn was dich interessiert, ist, ob du wirklich über alles geschlossen hast. Eine Funktion, die nichts aus dem umschließenden Bereich verwendet, ist zwar verschachtelt, aber kein Abschluss, und diese Unterscheidung ist oft wichtig. So zum Beispiel:
def foo(x):
def bar(y):
pass
return bar
ist nicht Herstellung einer Schließung, weil bar
Verwendung von nicht-Variablen aus dem Anwendungsbereich des Anrufs foo
macht. Im Gegensatz dazu, obwohl es ein Müll Referenz, diese ist einen Verschluss macht einfach durch den Wert von x
aus dem umschließenden Umfang zu lesen:
def foo(x):
def baz(y):
pass
return bar
Sie den Unterschied zwischen bar
und baz
sagen kann durch Testen des __closure__
Attribut (das ist None
, wenn keine verschachtelten Variablen geschlossen wurden) oder durch Überprüfung des co_freevars
Attributs des Objekts (das ein Tupel von Namen ist, das geschlossen ist, also wenn es leer ist, dann ist es entweder kein Abschluss, obwohl es immer noch sein kann eine verschachtelte Funktion):
def is_closure(func):
return func.__closure__ is not None
# Or using documented names, since __closure__ isn't for some reason,
# co_freevars is a tuple of names captured from nested scope
return bool(func.__code__.co_freevars)
# Or on 3.3+, you even get a function to aid you:
return bool(inspect.getclosurevars(func).nonlocals)
Ich denke, das ist eine recht gute Lösung. '__qualname__' ist auch das, was (zumindest in CPython) verwendet wird, um den' repr' der Funktion zu erstellen, es gibt keine anderen versteckten Attribute, die geprüft werden. –
@JimFasarakisHilliard Ja, ich spielte mit 'inspect.currentframe() herum. F_back.f_locals ist globals()', was auch zu funktionieren scheint, aber ich mag das sogar * weniger *. –