Потеря переменной области видимости внутри декоратора Python - PullRequest
1 голос
/ 23 февраля 2011

Этот простой декоратор работает как положено:

def protect(*permissions):
    def outer(f):
        def inner(*args):
            print permissions[0]
            return f(*args)  
        return inner  
    return outer

@protect('protected')
def func(var):
    return var

print func('something')

Вывод:

protected
something

Выход за пределы оболочки Python и использование декоратора в более широком контексте моего проекта, что-топроисходит странное: в то время как внутри функции inner, permissions не определено.

Я думаю, что должны быть какие-то тонкости области видимости / декорации переменных Python, о которых я не подозреваю, это может быть причиной этого,Любые идеи приветствуются.

Ответы [ 2 ]

1 голос
/ 24 февраля 2011

По моему мнению, я могу понять, что происходит - позвольте мне попытаться объяснить это:

это связано с тем, что Python не «воспринимает» переменную «permissions», как существующую в областях видимости вне«внутренняя» функция - поскольку, когда «внутреннее» само определено, «разрешения» долго бы определялись в «самой внешней» области защиты.Таким образом, при компиляции inner переменная считается глобальной переменной.(Вот почему необходимо сообщение об ошибке точный - NameErrors может быть для локальных переменных, используемых до определения, или для несуществующих глобальных переменных - точное сообщение в этом случае многое скажет)

* 1007Другими словами, вы, скорее всего, столкнулись с ошибкой реализации - пожалуйста, попробуйте указать минимальное количество кода, вызывающего проблему, и точную версию Python, которую вы используете.Если возможно, попробуйте использовать последнюю доступную микро-версию - и десять будет пора открыть проблему на bugs.python.org

Я вижу два обходных пути - первый будет хаком, который подтвердитмой диагноз - и может вообще не сработать: создать доступ для чтения к переменной permissions в функции outer вне тела inner: это должно заставить интерпретатора "воспринимать" ее как нелокальную переменнуюво внешнем, и распространите его во внутреннее.

Другой обходной путь является более надежным и непротиворечивым - и, возможно, в этом случае может даже улучшить стилизацию кода для yu: в этом случае использовать класс в качестве декоратора вместополагаясь на несколько вложенных функций и их замыканий.

Приведенный выше фрагмент может быть переписан как:

class Protect(object):
    def __init__(self, *permissions):
        self.permissions = permissions
    def __call__(self, f):
        def inner(*args):
            print self.permissions[0]
            return f(*args)  
        return inner  

@Protect('protected')
def func(var):
    return var

print func('something')

Этот код не основан на вложенных замыканиях, поэтому следует избегать ошибок, с которыми вы столкнулись.Кроме того, из этого следует, что «плоский лучше, чем вложенный» и «явный лучше, чем неявный» рекомендации по кодированию.

Но, пожалуйста, помогите всем отследить эту ошибку, предоставив нам свою версию и код, который фактически вызывает этоповедение, если не открывается проблема на python.org

0 голосов
/ 24 февраля 2011

Однажды я столкнулся с этой проблемой, потому что вы не можете установить переменную, которую вы помещаете в замыкание. Не знаю, так ли это для вас, но это полезно знать.

...