W niektórych językach można przekazać parametr przez odniesienie lub wartość, używając specjalnego słowa zastrzeżonego, takiego jak ref lub val . Kiedy przekazujesz parametr do funkcji Pythona, nigdy nie zmienia wartości parametru przy opuszczaniu funkcji. Jedynym sposobem na to jest użycie globalnego słowa zastrzeżonego (lub jak rozumiem to obecnie).
Przykład 1:
k = 2
def foo (n):
n = n * n #clarity regarding comment below
square = n
return square
j = foo(k)
print j
print k
pokaże
>>4
>>2
pokazując, że k nie zmienia się
W tym przykładzie zmienna n nigdy nie jest zmieniana
Przykład 2:
n = 0
def foo():
global n
n = n * n
return n
W tym przykładzie zmienna n została zmieniona
Czy w Pythonie jest jakiś sposób na wywołanie funkcji i poinformowanie Pythona, że parametr jest albo wartością, albo parametrem odniesienia , zamiast używać wartości globalnej?
Po drugie, na egzaminach Cambridge na poziomie A mówi się, że funkcja zwraca jedną wartość, podczas gdy procedura zwraca więcej niż jedną wartość. W latach 80-tych uczono mnie, że funkcja ma instrukcję powrotu, a procedura nie. Dlaczego jest to teraz niepoprawne?
n
zostać zmienione, używasz nowej zmiennejsquare
do przechowywania wyniku obliczeń.Odpowiedzi:
Nie możesz zmienić niezmiennego obiektu, takiego jak
str
lubtuple
, wewnątrz funkcji w Pythonie, ale możesz zrobić takie rzeczy, jak:def foo(y): y[0] = y[0]**2 x = [5] foo(x) print x[0] # prints 25
Jest to jednak dziwny sposób, chyba że zawsze musisz wyrównać pewne elementy w tablicy do kwadratu.
Zauważ, że w Pythonie możesz również zwrócić więcej niż jedną wartość, dzięki czemu niektóre przypadki użycia przekazywania przez odwołanie są mniej ważne:
def foo(x, y): return x**2, y**2 a = 2 b = 3 a, b = foo(a, b) # a == 4; b == 9
Kiedy zwracasz takie wartości, są one zwracane jako krotka, która z kolei jest rozpakowywana.
edit: Innym sposobem myślenia o tym jest to, że chociaż nie możesz jawnie przekazywać zmiennych przez odwołanie w Pythonie, możesz modyfikować właściwości obiektów, które zostały przekazane. W moim przykładzie (i innych) możesz modyfikować członków listy która została przekazana. Nie byłbyś jednak w stanie całkowicie zmienić przypisania przekazanej zmiennej. Na przykład zobacz następujące dwa fragmenty kodu, które wyglądają, jakby mogły robić coś podobnego, ale kończyć się różnymi wynikami:
def clear_a(x): x = [] def clear_b(x): while x: x.pop() z = [1,2,3] clear_a(z) # z will not be changed clear_b(z) # z will be emptied
źródło
clear_a
otrzymuje odwołaniez
i przechowuje je wx
. Następnie natychmiast zmienia się,x
aby odwołać się do innej tablicy. Oryginalnaz
tablica jest zapomniana w zakresieclear_a
, ale w rzeczywistości nie jest zmieniana. Pozostaje niezmieniony po powrocie do zakresu globalnego. Porównaj to, zclear_b
czym pobiera odwołanie,z
a następnie działa bezpośrednio na nim, bez tworzenia nowej tablicy lub wskazywania w inny sposóbx
i czegoś innego.y = x
,y: y.pop()
a następnie nazywaclear_b(z)
, z wciąż mam opróżniane ... Więc musimy cośy = list(x)
stworzyć kopię X (List (x) wyjaśnione tutaj )run_thread = [True] t= threading.Thread(target=module2.some_method, \ args=(11,1,run_thread)) --do something - and when you want to sop run_thread[0] =False
Istnieją zasadniczo trzy rodzaje „wywołań funkcji”:
Python jest językiem programowania PASS-BY-OBJECT-REFERENCE.
Po pierwsze, ważne jest, aby zrozumieć, że zmienna i wartość zmiennej (obiektu) to dwie odrębne rzeczy. Zmienna „wskazuje” obiekt. Zmienna nie jest obiektem. Jeszcze raz:
ZMIENNA NIE JEST PRZEDMIOTEM
Przykład: w następującym wierszu kodu:
>>> x = []
[]
jest pustą listą,x
jest zmienną wskazującą na pustą listę, alex
sama nie jest pustą listą.Potraktuj zmienną (
x
w powyższym przypadku) jako ramkę, a „wartość” zmiennej ([]
) jako obiekt wewnątrz ramki.PRZEJDŹ WEDŁUG OBIEKTU ODNIESIENIA (przypadek w Pythonie):
Tutaj „Odwołania do obiektów są przekazywane przez wartość”.
def append_one(li): li.append(1) x = [0] append_one(x) print x
W tym przypadku instrukcja
x = [0]
tworzy zmiennąx
(ramkę) wskazującą na obiekt[0]
.Na wywoływanej funkcji tworzone jest nowe pudełko
li
. Zawartośćli
jest TAKA SAMA co zawartość pudełkax
. Oba pudełka zawierają ten sam obiekt. Oznacza to, że obie zmienne wskazują ten sam obiekt w pamięci. Dlatego każda zmiana obiektu wskazanego przezli
będzie również odzwierciedlona przez obiekt wskazany przezx
.Podsumowując, wynik powyższego programu będzie:
[0, 1]
Uwaga:
Jeśli zmienna
li
zostanie ponownie przypisana w funkcji,li
wskaże oddzielny obiekt w pamięci.x
jednak będzie nadal wskazywać na ten sam obiekt w pamięci, na który wskazywał wcześniej.Przykład:
def append_one(li): li = [0, 1] x = [0] append_one(x) print x
Wynik programu będzie:
[0]
PRZEJŚCIE WEDŁUG REFERENCJI:
Ramka funkcji wywołującej jest przekazywana do wywoływanej funkcji. Niejawnie zawartość pola (wartość zmiennej) jest przekazywana do wywoływanej funkcji. W związku z tym każda zmiana zawartości pola w wywołanej funkcji zostanie odzwierciedlona w funkcji wywołującej.
PRZEJDŹ WEDŁUG WARTOŚCI:
Nowa skrzynka jest tworzona w wywołanej funkcji, a kopie zawartości skrzynki z funkcji wywołującej są przechowywane w nowych skrzynkach.
Mam nadzieję że to pomoże.
źródło
OK, ja się tym zajmę. Python przekazuje przez odniesienie do obiektu, które różni się od tego, o czym normalnie myślisz „przez odniesienie” lub „według wartości”. Weź ten przykład:
def foo(x): print x bar = 'some value' foo(bar)
Więc tworzysz obiekt typu string z wartością „jakaś wartość” i „wiążesz” go ze zmienną o nazwie
bar
. W C byłoby to podobne dobar
bycia wskaźnikiem do „jakiejś wartości”.Kiedy dzwonisz
foo(bar)
, nie omijaszbar
siebie. Przekazujeszbar
wartość ': wskaźnik do' jakiejś wartości '. W tym momencie istnieją dwa „wskaźniki” do tego samego obiektu łańcuchowego.Teraz porównaj to z:
def foo(x): x = 'another value' print x bar = 'some value' foo(bar)
Oto, na czym polega różnica. W wierszu:
x = 'another value'
w rzeczywistości nie zmieniasz zawartości
x
. W rzeczywistości to nawet nie jest możliwe. Zamiast tego tworzysz nowy obiekt typu string z wartością „inna wartość”. Ten operator przypisania? Nie mówi „nadpiszx
nową wartością, na którą wskazuje rzecz ”. Mówi „aktualizacjax
aby zamiast tego wskazywać na nowy obiekt”. Po tej linii znajdują się dwa obiekty typu string: „jakaś wartość” (zebar
wskazaniem) i „inna wartość” (zex
wskazaniem).To nie jest niezdarne. Kiedy zrozumiesz, jak to działa, jest to pięknie elegancki, wydajny system.
źródło
str
ing,tuple
s i inne obiekty są niezmienne . Jeśli przekazujesz zmienny obiekt, taki jak alist
, możesz go zmienić wewnątrz funkcji, bez konieczności zwracania go, ponieważ wszystkie parametry funkcji są wskaźnikami do tych samych przekazanych obiektów.Mam nadzieję, że poniższy opis dobrze to podsumowuje:
Należy wziąć pod uwagę dwie rzeczy - zmienne i obiekty.
Przykład:
def changeval( myvar ): myvar = 20; print "values inside the function: ", myvar return myvar = 10; changeval( myvar ); print "values outside the function: ", myvar
O / P:
values inside the function: 20 values outside the function: 10
Przykład:
def changelist( mylist ): mylist2=['a']; mylist.append(mylist2); print "values inside the function: ", mylist return mylist = [1,2,3]; changelist( mylist ); print "values outside the function: ", mylist
O / P:
values inside the function: [1, 2, 3, ['a']] values outside the function: [1, 2, 3, ['a']]
Przykład:
def changelist( mylist ): mylist=['a']; print "values inside the function: ", mylist return mylist = [1,2,3]; changelist( mylist ); print "values outside the function: ", mylist
O / P:
values inside the function: ['a'] values outside the function: [1, 2, 3]
źródło
Python nie jest przekazywany przez wartość ani przekazywany przez odniesienie. To bardziej „odniesienia do obiektów są przekazywane przez wartość”, jak opisano tutaj :
Oto dlaczego nie jest to wartość przekazana. Dlatego
def append(list): list.append(1) list = [0] reassign(list) append(list)
zwraca [0,1] wskazując, że jakiś rodzaj odniesienia został wyraźnie przekazany jako przekazana wartość nie pozwala funkcji w ogóle zmienić zakresu nadrzędnego .
Wygląda więc na przekazanie odniesienia, co? Nie.
Oto dlaczego nie jest to przekazywanie przez odniesienie. Dlatego
def reassign(list): list = [0, 1] list = [0] reassign(list) print list
zwraca [0] wskazując, że oryginalne odniesienie zostało zniszczone podczas ponownego przypisywania listy. funkcja pass-by-reference zwróciłaby [0,1] .
Więcej informacji znajdziesz tutaj :
Jeśli chcesz, aby Twoja funkcja nie manipulowała poza zakresem, musisz utworzyć kopię parametrów wejściowych, które utworzą nowy obiekt.
from copy import copy def append(list): list2 = copy(list) list2.append(1) print list2 list = [0] append(list) print list
źródło
Technicznie rzecz biorąc, Python nie przekazuje argumentów według wartości: wszystkie przez odniesienie. Ale ... ponieważ Python ma dwa typy obiektów: niezmienne i zmienne, oto co się dzieje:
Niezmienne argumenty są skutecznie przekazywane przez wartość : ciąg, liczba całkowita, krotka są niezmiennymi typami obiektów. Chociaż technicznie rzecz biorąc są one „przekazywane przez referencję” (jak wszystkie parametry), ponieważ nie można ich zmienić w miejscu wewnątrz funkcji, wygląda / zachowuje się tak, jakby była przekazywana przez wartość.
Zmienne argumenty są skutecznie przekazywane przez referencje : listy lub słowniki są przekazywane przez ich wskaźniki. Każda zmiana lokalna wewnątrz funkcji, taka jak (append lub del), wpłynie na oryginalny obiekt.
Oto jak został zaprojektowany Python: żadnych kopii i wszystkie są przekazywane przez odniesienie. Możesz jawnie przekazać kopię.
def sort(array): # do sort return array data = [1, 2, 3] sort(data[:]) # here you passed a copy
Ostatni punkt, o którym chciałbym wspomnieć, to funkcja, która ma swój własny zakres.
def do_any_stuff_to_these_objects(a, b): a = a * 2 del b['last_name'] number = 1 # immutable hashmap = {'first_name' : 'john', 'last_name': 'legend'} # mutable do_any_stuff_to_these_objects(number, hashmap) print(number) # 1 , oh it should be 2 ! no a is changed inisde the function scope print(hashmap) # {'first_name': 'john'}
źródło
Jest to więc trochę subtelny punkt, ponieważ podczas gdy Python przekazuje zmienne tylko według wartości, każda zmienna w Pythonie jest odniesieniem. Jeśli chcesz mieć możliwość zmiany wartości za pomocą wywołania funkcji, potrzebujesz modyfikowalnego obiektu. Na przykład:
l = [0] def set_3(x): x[0] = 3 set_3(l) print(l[0])
W powyższym kodzie funkcja modyfikuje zawartość obiektu List (który jest modyfikowalny), więc wyjście ma wartość 3 zamiast 0.
Piszę tę odpowiedź tylko po to, aby zilustrować, co oznacza „przez wartość” w Pythonie. Powyższy kod jest w złym stylu i jeśli naprawdę chcesz zmodyfikować swoje wartości, powinieneś napisać klasę i wywołać metody w tej klasie, jak sugeruje MPX.
źródło
y = [a for a in x]; y[0] = 3; return y
x = foo(x)
.Podana odpowiedź brzmi
def set_4(x): y = [] for i in x: y.append(i) y[0] = 4 return y
i
l = [0] def set_3(x): x[0] = 3 set_3(l) print(l[0])
co jest najlepszą odpowiedzią, o ile robi to, co mówi w pytaniu. Wydaje się jednak, że jest to bardzo niezdarny sposób w porównaniu z VB czy Pascalem, czy to najlepsza metoda, jaką mamy?
Jest nie tylko niezgrabny, ale wymaga ręcznej mutacji oryginalnego parametru, np. Poprzez zmianę oryginalnego parametru na listę: lub skopiowanie go na inną listę, zamiast po prostu powiedzieć: „użyj tego parametru jako wartości” lub „użyj tego jako odniesienie ”. Czy prosta odpowiedź może być taka, że nie ma na to zarezerwowanego słowa, ale są to świetne obejścia?
źródło
Weź pod uwagę, że zmienna to pudełko, a wartość, na którą wskazuje, to „rzecz” wewnątrz pola:
1. Przekaż przez odniesienie: funkcja ma to samo pudełko, a tym samym to, co jest w środku.
2. Przekaż wartość: funkcja tworzy nowe pudełko, replikę starego, włączając kopię tego, co się w nim znajduje. Na przykład. Java - funkcje tworzą kopię pudełka i rzeczy wewnątrz niego, która może być: prymitywem / odniesieniem do obiektu. (zwróć uwagę, że skopiowane odniesienie w nowym pudełku i oryginał nadal wskazują na ten sam obiekt, tutaj odniesienie JEST tym przedmiotem wewnątrz pudełka, a nie obiektem, na który wskazuje)
3. Przekaż przez odniesienie do obiektu : funkcja tworzy ramkę, ale zawiera to samo, co obejmowała ramka początkowa. Więc w Pythonie :
a) jeśli rzecz wewnątrz wspomnianego pudełka jest zmienna , wprowadzone zmiany zostaną odzwierciedlone z powrotem w oryginalnym pudełku (np. listy)
b) jeśli rzecz jest niezmienna (np. ciągi znaków Pythona i typy numeryczne), to pole wewnątrz funkcji będzie zawierało to samo, DO DOPÓKI nie spróbujesz zmienić jego wartości. Raz zmieniony element w pudełku funkcji jest zupełnie nowy w porównaniu do oryginału. Stąd id () dla tego pola poda teraz tożsamość nowej rzeczy, którą zawiera .
źródło
class demoClass: x = 4 y = 3 foo1 = demoClass() foo1.x = 2 foo2 = demoClass() foo2.y = 5 def mySquare(myObj): myObj.x = myObj.x**2 myObj.y = myObj.y**2 print('foo1.x =', foo1.x) print('foo1.y =', foo1.y) print('foo2.x =', foo2.x) print('foo2.y =', foo2.y) mySquare(foo1) mySquare(foo2) print('After square:') print('foo1.x =', foo1.x) print('foo1.y =', foo1.y) print('foo2.x =', foo2.x) print('foo2.y =', foo2.y)
źródło
W Pythonie przekazywanie przez referencję lub przez wartość ma związek z faktycznymi obiektami, które przekazujesz, więc jeśli przekazujesz na przykład listę, to faktycznie dokonujesz tego przejścia przez referencję, ponieważ lista jest zmiennym obiektem. W ten sposób przekazujesz wskaźnik do funkcji i możesz modyfikować obiekt (listę) w treści funkcji.
Kiedy przekazujesz ciąg, to przekazywanie jest wykonywane przez wartość, więc tworzony jest nowy obiekt ciągu, a gdy funkcja kończy działanie, jest niszczony. Wszystko to ma więc związek z obiektami zmiennymi i niezmiennymi.
źródło
Python już wywołuje przez ref ..
weźmy przykład:
def foo(var): print(hex(id(var))) x = 1 # any value print(hex(id(x))) # I think the id() give the ref... foo(x)
Wynik
0x50d43700 #with you might give another hex number deppend on your memory 0x50d43700
źródło
def foo(var): print(id(var)) var = 1234 print(id(var)) x = 123 print(id(x)) # I think the id() give the ref... foo(x) print(id(x))