Использование переменной из вложенной функции

class Solution:
    def isBalanced(self, root: Optional[TreeNode]) -> bool:
        balanced = [True]
        
        def node_height(root):
            if not root or not balanced[0]:
                return 0
            
            left_height = node_height(root.left)
            right_height = node_height(root.right)
            
            if abs(left_height - right_height) > 1:
                balanced[0] = False
                return 0
            
            return 1 + max(left_height, right_height)
            
        node_height(root)
        return balanced[0]

Я понимаю, почему приведенный выше код работает, но когда я меняю значение переменной «сбалансированный» на balanced = True вместо balanced = [True] в строке 3 и измените баланс[0] на баланс в строках 6, 13 и 19, я получаю ошибку.

class solution:
    def func(): 
        a = 5
        b = 7
        c = True
        def nested_func():
            return (a + b, c)
        return nested_func()
        
    print('sum is:', func())

Поэтому я попробовал приведенный выше код для проверки (возможно, вложенная функция не может получить переменную, имеющую логическое значение), но смог получить результат «сумма: (12, True)». который показывает, что вложенные функции могут получать переменные вне себя.

Может ли кто-нибудь объяснить это?

Какая у вас ошибка?

SIGHUP 04.07.2024 08:11

Вы правильно поняли UnboundLocalError?

Sharim09 04.07.2024 08:11

Я получаю сообщение «UnboundLocalError: невозможно получить доступ к локальной переменной «сбалансированный», если она не связана со значением», когда я меняю значение сбалансированного на логическое значение.

DHK 04.07.2024 08:12
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
4
3
58
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Для этого вы можете использовать ключевое слово nonlocal :

...
        balanced = True
        def node_height(root):
            nonlocal balanced
...

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

В вашем случае node_height вложен в isBalanced, поэтому nonlocal balanced сообщит интерпретатору использовать ту же ссылку balanced, что и isBalanced, вместо создания новой ссылки, которая затеняет другую.

Во втором примере nonlocal не требуется, потому что nested_func только читает переменные. Если вы посмотрите на следующее сравнение:

>>> import dis
>>> dis.dis("def f(): return a")
<7 lines omitted>
Disassembly of <code object f at 0x0000026F07FDC510, file "<dis>", line 1>:
  1           0 RESUME                   0
              2 LOAD_GLOBAL              0 (a)
             12 RETURN_VALUE
>>> dis.dis("""
... def f():
...     a = 7
...     return a""")
<7 lines omitted>
Disassembly of <code object f at 0x0000026F07FDE4C0, file "<dis>", line 2>:
  2           0 RESUME                   0

  3           2 LOAD_CONST               1 (7)
              4 STORE_FAST               0 (a)

  4           6 LOAD_FAST                0 (a)
              8 RETURN_VALUE

Вы можете видеть, что первая функция имеет инструкцию LOAD_GLOBAL, тогда как вторая функция использует LOAD_FAST, поскольку она присваивает значение a, сообщая интерпретатору, что это локальная переменная.

Спасибо, но не могли бы вы объяснить, как работает приведенный ниже код без использования ключевого слова nonlocal?

DHK 04.07.2024 08:17

@DHK Я добавил пояснения для обоих случаев

Aemyl 04.07.2024 08:27
Ответ принят как подходящий

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

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

Итак, в этом коде

    def node_height(root):
        if not root or not balanced:
            return 0
        
        left_height = node_height(root.left)
        right_height = node_height(root.right)
        
        if abs(left_height - right_height) > 1:
            balanced = False #  You are creating the variable here, 
                             #  but you are trying to access it above in the first if-else statement. 
                             # That is why you are getting the UnboundlocalError
            return 0
        
        return 1 + max(left_height, right_height)

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


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

class solution:
    def func(): 
        a = 5
        b = 7
        c = True
        def nested_func():
            return (a + b, c)
        return nested_func()
        
    print('sum is:', func())

@DHK Добро пожаловать, братан

Sharim09 04.07.2024 08:24

Другие вопросы по теме