Доступ к внешней области видимости в Python 2.6 - PullRequest
7 голосов
/ 22 января 2011

Скажем, у меня есть область видимости с переменными, и функция, вызываемая в этой области, хочет изменить некоторые неизменяемые переменные:

def outer():
    s = 'qwerty'
    n = 123
    modify()

def modify():
    s = 'abcd'
    n = 456

Возможно ли как-то получить доступ к внешнему объему? Что-то вроде nonlocal переменных из Py3k.

Конечно, я могу сделать s,n = modify(s,n) в этом случае, но что, если мне понадобится какая-то общая «инъекция», которая выполняется там и должна иметь возможность переназначения произвольным переменным?

Я имею в виду производительность, поэтому, если возможно, eval & проверка фрейма стека не приветствуются:)


UPD : Это невозможно. Период. Однако есть несколько вариантов доступа к переменным во внешней области:

  1. Используйте глобалы. Кстати, func.__globals__ - изменчивый словарь;)
  2. Хранить переменные в dict / экземпляре класса / любом другом изменяемом контейнере
  3. Задать переменные в качестве аргументов и вернуть их в виде кортежа: a,b,c = innerfunc(a,b,c)
  4. Вставить байт-код другой функции. Это возможно с byteplay модулем Python.

Ответы [ 5 ]

7 голосов
/ 22 января 2011

Иногда я сталкиваюсь с таким кодом. Вложенная функция изменяет изменяемый объект вместо присвоения nonlocal:

def outer():
    s = [4]
    def inner():
        s[0] = 5
    inner()
7 голосов
/ 22 января 2011

Определите переменные вне функций и используйте ключевое слово global.

s, n = "", 0

def outer():
    global n, s
    n = 123
    s = 'qwerty'
    modify()

def modify():
    global n, s
    s = 'abcd'
    n = 456
3 голосов
/ 22 января 2011

Вы можете использовать глобальные переменные,

s = None
n = None

def outer(self):
    global s
    global n
    s = 'qwerty'
    n = 123
    modify()

def modify(self):
    global s
    global n
    s = 'abcd'
    n = 456

или определить их как методы и использовать переменную класса или экземпляра.

class Foo(object):
    def __init__(self):
        self.s = None
        self.n = None

    def outer(self):
        self.s = 'qwerty'
        self.n = 123
        self.modify()

    def modify(self):
        self.s = 'abcd'
        self.n = 456
3 голосов
/ 22 января 2011

Это , а не , как nonlocal работает.Он не обеспечивает динамическую область видимости (это просто огромная PITA, ожидающая своего появления, и даже более редко полезная, чем ваша обычная «злая» функция).Это просто исправляет лексическую область видимости.

В любом случае, вы не можете делать то, что имеете в виду (и я бы сказал, что это хорошо).Нет даже грязного, но легкого хака (и пока мы на нем: такие хаки не обескураживают, потому что они обычно работают немного хуже!).Просто забудьте об этом и правильно решите реальную проблему (вы не назвали ее, поэтому мы ничего не можем сказать по этому поводу).

Самое близкое, что вы можете получить, - это определить какой-то объект, который несет в себе все, что вы хотитеподелиться и передать это явно (например, сделать класс и использовать self, как предложено в другом ответе).Но это относительно громоздко, чтобы делать везде, и все же хакерские (хотя и лучше, чем динамическая область видимости, потому что «явный лучше, чем неявный»).

1 голос
/ 13 августа 2012

Вы, вероятно, также можете сделать это (не говоря, что это правильно);

определить функцию, которая возвращает массив со строками, например

["a = qwerty","n = 123"]

Затем выполните в нужной области видимостипеременные

for row in array:
  eval(row)

это чертовски хакерский.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...