Пересматриваются ли переменные в функциях Python при каждом вызове функции? - PullRequest
1 голос
/ 25 января 2011

Предположим, у меня есть две функции

def myfunction1(number):

    biglist = [1,2,3,4,5,6,7,8,9]

    print number*biglist


biglist = [1,2,3,4,5,6,7,8,9]

def myfunction2(number, biglist):

    print number*biglist

Я рассчитываю их с помощью волшебного% timeit ipython:

In [5]: %timeit myfunction2(number, biglist)
1000000 loops, best of 3: 607 ns per loop

In [6]: %timeit myfunction1(number)
1000000 loops, best of 3: 841 ns per loop

Означает ли это, что переменная biglist повторно объявляется каждый разЯ называю myfunction1?Я бы догадался, что после первого вызова функции Python каким-то образом сохранит переменную biglist с функцией, так что ему не придется повторно инициализировать список при каждом вызове функции.

IЯ не знаю внутреннюю работу Python, поэтому я просто догадываюсь.Может кто-нибудь объяснить, что на самом деле происходит?

Ответы [ 3 ]

2 голосов
/ 25 января 2011

Python не может делать то, что вы предлагаете, не выполняя довольно сложный анализ. оператор присваивания - это просто оператор присваивания, если я дважды набираю x=3 в интерпретаторе, я ожидаю, что x будет 3 сразу после того, как я его напечатал, независимо от того, что я сделал с x в промежутке ... это действительно не отличается

для иллюстрации - эта функция легко может быть

def myfunction1(number):
    biglist = [1,2,3,4,5,6,7,8,9]
    biglist = number*biglist
    print biglist

В этом случае вы хотите переназначить биг-лист.

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

0 голосов
/ 25 января 2011

Python должен создавать новый список для каждой записи в myfunction1 () и назначать его для «большого списка».

В myfunction2 () вы передаете ссылку на глобальный «большой список», поэтому копирование не требуется.

Есть и другие, тонкие различия между ними. Передача этой ссылки оставляет глобальные данные открытыми для (возможно, нежелательного) вмешательства:

>>> biglist = [ 1,2,3,4,5,6,7,8,9 ]
>>> def myfunction3(mylist):
...     mylist[2] = 99
...
>>> biglist
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> myfunction3(biglist)
>>> biglist
[1, 2, 99, 4, 5, 6, 7, 8, 9]

... тогда как объявление его в области действия означает, что оно создается каждый раз заново. Так, например:

>>> def myfunction4():
...     mylist = [ 1,2,3,4,5 ]
...     print mylist
...     mylist[2] = 99
...
>>> myfunction4()
[1, 2, 3, 4, 5]
>>> myfunction4()
[1, 2, 3, 4, 5]

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

Итак, как вы получаете лучшее из обоих миров? Попробуйте это:

>>> def myfunction5():
...     mylist = biglist+[] # Make a private copy
...     mylist[4] = 99
...
>>> biglist
[1, 2, 99, 4, 5, 6, 7, 8, 9]
>>> myfunction5()
>>> biglist
[1, 2, 99, 4, 5, 6, 7, 8, 9]

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

def myfunction1a(number):
    mylist = biglist+[] # Copy-safe version
    print number*mylist

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

0 голосов
/ 25 января 2011

Да. Он находится в области действия myfunction1, а в myfunction2 - в глобальной области действия, которая не завершится до завершения программы. Когда myfunction1 будет завершен, все связанные с ним переменные будут помечены как недоступные. И каждый вызов будет создавать новые переменные только в своей области.

- Сай

...