Перезапись переменных Python во вложенных функциях - PullRequest
51 голосов
/ 29 октября 2011

Предположим, у меня есть следующий код Python:

def outer():
    string = ""
    def inner():
        string = "String was changed by a nested function!"
    inner()
    return string

Я хочу, чтобы вызов external () возвращал «String был изменен вложенной функцией!», Но я получаю «». Я пришел к выводу, что Python считает, что строка string = "string was changed by a nested function!" является объявлением новой переменной local to inner (). Мой вопрос: как мне сказать Python, что он должен использовать строку external ()? Я не могу использовать ключевое слово global, потому что строка не глобальная, она просто находится во внешней области видимости. Идеи? * * 1006

Ответы [ 4 ]

45 голосов
/ 29 октября 2011

В Python 3.x вы можете использовать ключевое слово nonlocal:

def outer():
    string = ""
    def inner():
        nonlocal string
        string = "String was changed by a nested function!"
    inner()
    return string

В Python 2.x вы можете использовать список с одним элементом и перезаписатьэтот единственный элемент:

def outer():
    string = [""]
    def inner():
        string[0] = "String was changed by a nested function!"
    inner()
    return string[0]
24 голосов
/ 12 января 2015

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

def outer():
    def inner():
        inner.string = "String was changed by a nested function!"
    inner.string = ""
    inner()
    return inner.string

Уточнение: это работает как в Python 2.x, так и в 3.x.

4 голосов
/ 12 июля 2015

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

, но у меня был опыт работы с анонимным объектом JAVA (т. Е. Определением исполняемого объекта), и было правило, что анонимный объект создает точную копию своей внешней среды, в данном случае переменных внешней области. Таким образом, если внешняя переменная является неизменяемой (int, char), они не могут быть изменены анонимным объектом, поскольку они копируются с помощью value , тогда как если это изменяемая переменная (collection, * 1008) *) они могут быть изменены ... так как они копируются " указатель " (их адрес в памяти)

если вы знаете о программировании, думайте о нем как о передаче по значению и передаче по ссылке.

в питоне, это очень похоже. x=123 является присваиванием, они дают переменной x новое значение (не изменяет старый x), list[i]/dict[key] являются операциями доступа к объектам, они действительно изменяют вещи

В заключение, вам нужен изменяемый объект ... для изменения (даже если вы можете получить доступ к кортежу с помощью [], вы не можете использовать его здесь, так как он не изменяемый)

2 голосов
/ 19 ноября 2014

Чтобы добавить к ответ Свена :

В Python 2.x вы можете только читать переменные внешней области из внутренней области.При назначении будет просто создана новая локальная (т.е. внутренняя область) переменная, которая скрывает внешнюю область.

Если вы хотите прочитать и изменить , вы можете использовать dict для храненияпеременные во внешней области видимости, а затем доступ к ним через dict во внутренней области видимости, также сохраняя ваш код достаточно чистым и читаемым при наличии нескольких переменных внешней области видимости:

def outer():
    # hold some text, plus the number of spaces in the text
    vars = {'text': 'Some text.', 'num_spaces': 1}
    def inner():
        # add some more text
        more_text = ' Then some more text.'
        vars['text'] += more_text
        # keep track of the number of spaces
        vars['num_spaces'] += more_text.count(' ')
    inner()
    return vars['text'], vars['num_spaces']

вывод:

>>> outer()
('Some text. Then some more text.', 5)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...