Область видимости у декоратора
Есть такой код:
def logger(f):
def inner(*args, **kwargs):
a = 6
return f(*args, **kwargs)
return inner
@logger
def nothing():
print(a)
Выходит ошибка, что переменная a неопределенна, не совсем понимаю по какому принципу он ищет ее в области видимости. Можете объяснить?
Ответы (1 шт):
у "декоратора" такая же область видимости что и у любого другого метода. в данном случае переменная a объявлена в методе inner и видна только в нем.
если вынести объявление переменной a из inner в logger, то a будет видна и в logger и в inner. поэтому слово декоратор я взял в ковычки, потому что декоратор это паттерн, а вопрос об области видимости вложенных методов. однако в методе nothing переменная a не будет доступна никогда, потому что он выполняется в своей области видимости.
def logger(f):
a = ""
print("logger:", locals())
def inner(*args, **kwargs):
nonlocal a
b = ""
print("logger.inner:", locals())
return f(*args, **kwargs)
return inner
@logger
def nothing():
c = ""
print("nothing:", locals())
nothing()
logger: {'a': '', 'f': <function nothing at 0x7f981115f4d0>}
logger.inner: {'args': (), 'kwargs': {}, 'b': '', 'a': '', 'f': <function nothing at 0x7f981115f4d0>}
nothing: {'c': ''}
для вложенной функции inner переменные объявленные в функции logger доступны в режиме read-only. ключевое слово nonlocal в данном случае позволяет изменять переменную объявленнию на скоуп выше.
интересно, что без nonlocal переменная a не видна в locals() если она не упоминается в коде inner.
def logger(f):
a = ""
print("logger:", locals())
def inner(*args, **kwargs):
b = ""
print("logger.inner:", locals())
print(a)
return f(*args, **kwargs)
return inner
@logger
def nothing():
c = ""
print("nothing:", locals())
nothing()
logger: {'a': '', 'f': <function nothing at 0x7faa790214d0>}
logger.inner: {'args': (), 'kwargs': {}, 'b': '', 'a': '', 'f': <function nothing at 0x7faa790214d0>}
nothing: {'c': ''}
def logger(f):
a = ""
print("logger:", locals())
def inner(*args, **kwargs):
b = ""
print("logger.inner:", locals())
return f(*args, **kwargs)
return inner
@logger
def nothing():
c = ""
print("nothing:", locals())
nothing()
logger: {'a': '', 'f': <function nothing at 0x7f20117c44d0>}
logger.inner: {'args': (), 'kwargs': {}, 'b': '', 'f': <function nothing at 0x7f20117c44d0>}
nothing: {'c': ''}
а вот метод nothing никакого отношения к logger и inner не имеет.