Python — вызов функции несколько раз изменит переменную разных экземпляров функции

#python #recursion

#python #рекурсия

Вопрос:

Позвольте мне объяснить, показав вам проблемный код и его соответствующий вывод:

 def find_amount_of(victim, key, value):
    def eval(v, k, dir, sc):
        hits = 0
        print("{}: {} -> {}".format(dir, k, v))
        
        # Currently only triggers when both have been hit
        if k == key or k == None:
            if v == value:
                hits  = 1
        
        if type(v) == list or type(v) == dict:
            hits  = second(k, v, hits, dir, sc)
        
        return hits
    
    def second(name, vv, hits, dir, sc):
        # Setup vars
        sc  = 1
        hc = hits
        if name != "":
            dir.append(name)
        
        # Decide treatment of vv
        if type(vv) == dict:
            for k, v in vv.items():
                print("Second Counter: "   str(sc)   ", "   str(dir))
                hc  = eval(v, k, dir, sc)
        elif type(vv) == list:
            for v in vv:
                hc  = eval(v, None, dir, sc)
        
        # Return hits throughout entire thing
        return hc
    
    return second("", victim, 0, [], 0)

ex3 = {
    "1": {
        "1.1": 1
    },
    "2": {
        "2.1": 2
    }
}

print(find_amount_of(ex3, "1.3", 2))
  

Вывод:

 Second Counter: 1, []
[]: 1 -> {'1.1': 1}
Second Counter: 2, ['1']
['1']: 1.1 -> 1
Second Counter: 1, ['1']
['1']: 2 -> {'2.1': 2}
Second Counter: 2, ['1', '2']
['1', '2']: 2.1 -> 2
0
  

Чего я не понимаю, так это почему dir изменился в первом экземпляре второго вызова функции (извините за мое ужасное название, это была просто быстрая тестовая функция, которую я сделал).
Когда вы смотрите на вывод, вы можете увидеть строку «Второй счетчик: 1, []». Это первый экземпляр, а dir — это просто список emtpy.
Теперь, чуть позже, строка «Второй счетчик: 1, [‘1’]» вызывает меня. Это все еще первый экземпляр, но по какой-то причине dir изменился.
Мой первый вопрос: почему он меняется, когда функция eval не изменяет вторую функцию, которая его вызвала?

Мой второй вопрос: как я могу это исправить? Нужен ли мне совершенно другой подход?

Прямо сейчас целью этого кода является перебор dicts и списков, чтобы всегда отслеживать, где именно он находится.

Комментарии:

1. Да, разберитесь с вашими именами, чтобы не использовать встроенные модули. dir всегда ссылается на один и тот же экземпляр списка, который можно изменить, добавив второй.

Ответ №1:

Я понял это.

Ответ на первый вопрос «Почему?» заключается в том, что python передает списки по ссылке, а не по значению.

Ответ на второй вопрос «Как исправить?» заключается в том, чтобы просто передать копию списка вместо фактического списка, например:

 second(k, v, hits, dir.copy(), sc)
  

вместо этого:

 second(k, v, hits, dir, sc)