Подтвердить что ты не робот

Переписывание переменных Python во вложенных функциях

Предположим, у меня есть следующий код 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, потому что строка не является глобальной, она просто живет во внешней области. Идеи?

4b9b3361

Ответ 1

В 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]

Ответ 2

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

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

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

Ответ 3

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

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

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

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

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

Ответ 4

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

В 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)