2012-07-20 7 views
13

Mam pytanie dotyczące wywoływania funkcji w Pythonie. Powiedzmy, że chcę napisać funkcję o nazwie superLongFunc (expr). Funkcja jest bardzo długa i bardzo trudna do debugowania. Chcę podzielić funkcję na mniejsze funkcje pomocnicze dla lepszej czytelności, na coś takiego jak smallFunc1 (expr), smallFunc2 (expr), itp.Python - jak działają przekazywane wartości?

Moje pytanie brzmi, czy to ma wpływ na wydajność kodu w ogóle? Jak dokładnie działają funkcje wywołujące w Pythonie? Czy Python przekazuje zmienne do funkcji przez odwołanie? Lub czy tworzy kopię zmiennej przed przekazaniem jej do funkcji?

Wiem, że to dość nieprzyjemne pytanie, ale przez jakiś czas mnie dręczyło. Z góry dziękuję!

+1

Istnieją empiryczne sposoby na to również. Przychodzą mi na myśl moduły 'timeit' i' dis'. Czasami warto przetestować rzeczy dla siebie. –

Odpowiedz

16

Python używa systemu czasami nazywanego call-by-object. Nic nie jest kopiowane podczas przekazywania argumentów do funkcji. Nazwy argumentów funkcji są lokalnie powiązane w treści funkcji, z tymi samymi obiektami podanymi w wywołaniu funkcji.

Różni się to od tego, co większość ludzi uważa za "połączenie według wartości", ponieważ nie kopiuje obiektów. Ale różni się także od "wywołania przez odwołanie", ponieważ odwołanie dotyczy obiektu --- jest powiązane, ale do tego samego obiektu. Oznacza to, że możesz zmutować obiekt przekazany, ale ponowne powiązanie nazwy wewnątrz funkcji nie ma wpływu poza funkcją. Prostym przykładem różnicy:

>>> def func(x): 
...  x[0] = 2 # Mutating the object affects the object outside the function 
>>> myList = [1] 
>>> func(myList) 
>>> myList # myList has changed 
[2] 
>>> def func(x): 
...  x = 2 # rebinding name has no effect outside the function 
>>> myList = [1] 
>>> func(myList) 
>>> myList # myList is unaffected 
[1] 

mój prosty sposób myślenia o to, że przypisanie do gołej nazwą --- czyli wypowiedzi postaci name = value --- jest zupełnie inna od wszystkiego innego w Pythonie . Sposób działania na nazwach, a nie na wartościach, polega na wykonaniu name = value. (Są tu dziwne wyjątki, takie jak zgranie z globals() itd., Ale i tak są to niebezpieczne obszary). W szczególności name = value różni się od obj.prop = value, obj[0] = value, obj += value i innych podobnych rzeczy, które wyglądają jak przypisanie, ale faktycznie działają na obiektach a nie na nazwiska.

To powiedziawszy, wywołania funkcji w Pythonie mają pewną ilość narzutów samych w sobie (do ustawienia ramki wykonawczej itp.). Jeśli funkcja jest wywoływana wiele razy, ten narzut może spowodować zauważalny wpływ na wydajność. Podział jednej funkcji na wiele może mieć wpływ na wydajność, ponieważ każde dodatkowe wywołanie funkcji doda trochę narzutów.

+3

To, co opisujesz, jest po prostu wartością wywołania, gdzie wartości są odniesieniami do obiektów. – Marcin

+0

Tak, to jest inny sposób opisu wywołania przez obiekt. – BrenBarn

+0

Jest to prawie tak samo jak wywołanie przez odwołanie, co najmniej tak samo zaimplementowane w C++, z tą różnicą, że wiele wbudowanych typów jest niezmiennych w Pythonie :) –