Jak mogę przekazać liczbę całkowitą przez odwołanie w Pythonie?
Chcę zmodyfikować wartość zmiennej, którą przekazuję do funkcji. Czytałem, że wszystko w Pythonie jest przekazywane przez wartość, ale musi być prosta sztuczka. Na przykład w Javie można przekazać typów referencyjnych Integer
, Long
itp
- Jak mogę przekazać liczbę całkowitą do funkcji przez odwołanie?
- Jakie są najlepsze praktyki?
python
function
pass-by-reference
pass-by-value
CodeKingPlusPlus
źródło
źródło
Odpowiedzi:
W Pythonie nie działa to w ten sposób. Python przekazuje odniesienia do obiektów. Wewnątrz swojej funkcji masz obiekt - możesz dowolnie modyfikować ten obiekt (jeśli to możliwe). Jednak liczby całkowite są niezmienne . Jedynym sposobem obejścia tego problemu jest przekazanie liczby całkowitej w kontenerze, który można zmodyfikować:
def change(x): x[0] = 3 x = [1] change(x) print x
W najlepszym razie jest to brzydkie / niezdarne, ale w Pythonie nic nie da się osiągnąć. Powodem jest to, że w Pythonie przypisanie (
=
) pobiera dowolny obiekt będący wynikiem prawej strony i wiąże go z tym, co znajduje się po lewej stronie * (lub przekazuje go do odpowiedniej funkcji).Rozumiejąc to, możemy zobaczyć, dlaczego nie ma sposobu, aby zmienić wartość niezmiennego obiektu wewnątrz funkcji - nie możesz zmienić żadnego z jego atrybutów, ponieważ jest niezmienny i nie możesz po prostu przypisać „zmiennej” nowego wartość, ponieważ wtedy faktycznie tworzysz nowy obiekt (który różni się od starego) i nadajesz mu nazwę, jaką stary obiekt miał w lokalnej przestrzeni nazw.
Zazwyczaj sposobem obejścia tego problemu jest po prostu zwrócenie żądanego obiektu:
def multiply_by_2(x): return 2*x x = 1 x = multiply_by_2(x)
* W pierwszym przykładzie powyżej,
3
faktycznie zostaje przekazany dox.__setitem__
.źródło
C
. (Na przykład nie trzeba ich wyłuskiwać). W moim modelu myślowym łatwiej jest myśleć o rzeczach jako o „nazwach” i „przedmiotach”. Przypisanie wiąże „Nazwę” (y) po lewej stronie z „Obiektem” (-ami) po prawej stronie. Kiedy wywołujesz funkcję, przekazujesz „Obiekt” (skutecznie wiążąc go z nową nazwą lokalną w funkcji)..
operator po prostu wyłuskuje lewą stronę. Operatory mogą być różne w różnych językach.W większości przypadków, w których musisz przekazać przez odwołanie, musisz zwrócić więcej niż jedną wartość z powrotem do wywołującego. „Najlepszą praktyką” jest używanie wielu zwracanych wartości, co jest znacznie łatwiejsze w Pythonie niż w językach takich jak Java.
Oto prosty przykład:
def RectToPolar(x, y): r = (x ** 2 + y ** 2) ** 0.5 theta = math.atan2(y, x) return r, theta # return 2 things at once r, theta = RectToPolar(3, 4) # assign 2 things at once
źródło
Nie jest to dokładne przekazywanie wartości bezpośrednio, ale używanie jej tak, jakby została przekazana.
x = 7 def my_method(): nonlocal x x += 1 my_method() print(x) # 8
Ostrzeżenia:
nonlocal
został wprowadzony w Pythonie 3global
zamiastnonlocal
.źródło
Naprawdę, najlepszą praktyką jest cofnięcie się i pytanie, czy naprawdę musisz to zrobić. Dlaczego chcesz zmodyfikować wartość zmiennej, którą przekazujesz do funkcji?
Jeśli chcesz to zrobić, aby szybko się zhakować, najszybszym sposobem jest przekazanie
list
liczby całkowitej trzymającej i przyklejenie[0]
wokół każdego jej użycia, jak pokazuje odpowiedź mgilsona.Jeśli trzeba zrobić coś bardziej znaczącego, napisać
class
, że maint
jako atrybut, więc można po prostu ustawić go. Oczywiście zmusza cię to do wymyślenia dobrej nazwy dla klasy i dla atrybutu - jeśli nie możesz nic wymyślić, wróć i przeczytaj zdanie jeszcze raz kilka razy, a następnie użyjlist
.Mówiąc bardziej ogólnie, jeśli próbujesz przenieść jakiś idiom Java bezpośrednio do Pythona, robisz to źle. Nawet jeśli istnieje coś bezpośrednio odpowiadającego (jak w przypadku
static
/@staticmethod
), nadal nie chcesz go używać w większości programów w Pythonie tylko dlatego, że używałbyś go w Javie.źródło
W Pythonie każda wartość jest odniesieniem (wskaźnikiem do obiektu), podobnie jak nieprymitywy w Javie. Podobnie jak Java, Python ma tylko przekazywanie wartości. Więc semantycznie są prawie takie same.
Ponieważ w swoim pytaniu wspominasz o Javie, chciałbym zobaczyć, w jaki sposób osiągasz to, co chcesz w Javie. Jeśli możesz to pokazać w Javie, mogę ci pokazać, jak to zrobić dokładnie równoważnie w Pythonie.
źródło
Jednoelementowa tablica numpy jest zmienna, a jednak w większości zastosowań może być oceniana tak, jakby była numeryczną zmienną Pythona. Dlatego jest to wygodniejszy kontener na numery referencyjne niż lista jednoelementowa.
import numpy as np def triple_var_by_ref(x): x[0]=x[0]*3 a=np.array([2]) triple_var_by_ref(a) print(a+1)
wynik:
3
źródło
Może nie jest to sposób pythonowy, ale możesz to zrobić
import ctypes def incr(a): a += 1 x = ctypes.c_int(1) # create c-var incr(ctypes.ctypes.byref(x)) # passing by ref
źródło
class PassByReference: def Change(self, var): self.a = var print(self.a) s=PassByReference() s.Change(5)
źródło
Być może nieco bardziej samodokumentująca się sztuczka niż trik z listą długości-1 jest stara sztuczka z pustym typem:
def inc_i(v): v.i += 1 x = type('', (), {})() x.i = 7 inc_i(x) print(x.i)
źródło
W Pythonie wszystko jest przekazywane przez wartość, ale jeśli chcesz zmodyfikować jakiś stan, możesz zmienić wartość liczby całkowitej wewnątrz listy lub obiektu, który jest przekazywany do metody.
źródło
everything is passed by value
to nieprawda. Cytuj dokumenty:arguments are passed using call by value (where the value is always an object reference, not the value of the object)
Prawidłową odpowiedzią jest użycie klasy i umieszczenie wartości wewnątrz klasy, co pozwala na przekazywanie przez odwołanie dokładnie tak, jak chcesz.
class Thing: def __init__(self,a): self.a = a def dosomething(ref) ref.a += 1 t = Thing(3) dosomething(t) print("T is now",t.a)
źródło