Funkcje Pythona są wywoływane przez odniesienie


84

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?


5
Najlepszym źródłem, które znalazłem do zrozumienia modelu wywoływania w Pythonie, jest ten artykuł o effbot: effbot.org/zone/call-by-object.htm
Wilduck.

1
powinieneś przeczytać o zmiennych Pythonie, obiektach mutable i inmutable. Również w pierwszym przykładzie, dlaczego miałoby nzostać zmienione, używasz nowej zmiennej squaredo przechowywania wyniku obliczeń.
Facundo Casco

6
Nie wysyłaj dwóch niepowiązanych pytań w jednym. Definicja funkcji kontra procedura jest kwestią definicji i wydaje się, że twoja definicja jest nastawiona na Pascala. W żargonie Pythona nie ma czegoś takiego jak procedura.
Fred Foo

2
Spójrz także na tę poprzednią odpowiedź StackOverflow. stackoverflow.com/a/10262945/173292 Dość intuicyjnie wyjaśnia wywołanie przez model odniesienia obiektu.
Wilduck

1
Zobacz także to pytanie SO, aby uzyskać bardzo przydatne wyjaśnienie: jak przekazać zmienną przez odniesienie
Michael Ohlrogge

Odpowiedzi:


79

Nie możesz zmienić niezmiennego obiektu, takiego jak strlub tuple, 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

2
Warto byłoby zobaczyć wyniki programów. Na przykład czy „print x [0]” zwraca 25? (Tak, ale to powinno być pokazane.)
Ray Salemi,

11
@alexey clear_aotrzymuje odwołanie zi przechowuje je w x. Następnie natychmiast zmienia się, xaby odwołać się do innej tablicy. Oryginalna ztablica jest zapomniana w zakresie clear_a, ale w rzeczywistości nie jest zmieniana. Pozostaje niezmieniony po powrocie do zakresu globalnego. Porównaj to, z clear_bczym pobiera odwołanie, za następnie działa bezpośrednio na nim, bez tworzenia nowej tablicy lub wskazywania w inny sposób xi czegoś innego.
dave mankoff,

dzięki, dave! Próbowałem „tworząc nową tablicę” w clear_b, y = x, y: y.pop()a następnie nazywa clear_b(z), z wciąż mam opróżniane ... Więc musimy coś y = list(x)stworzyć kopię X (List (x) wyjaśnione tutaj )
Alexey

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
Alex Punnen

W przeciwieństwie do Java, w Pythonie nie ma prymitywnego typu. Obiekty instancji wszystkich typów.
Marco Sulla

184

Istnieją zasadniczo trzy rodzaje „wywołań funkcji”:

  • Podaj wartość
  • Przekaż przez odniesienie
  • Przekaż przez odwołanie do obiektu

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ą, xjest zmienną wskazującą na pustą listę, ale xsama nie jest pustą listą.

Potraktuj zmienną ( xw 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ść lijest TAKA SAMA co zawartość pudełka x. 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 przez libędzie również odzwierciedlona przez obiekt wskazany przez x.

Podsumowując, wynik powyższego programu będzie:

[0, 1]

Uwaga:

Jeśli zmienna lizostanie ponownie przypisana w funkcji, liwskaże oddzielny obiekt w pamięci. xjednak 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.


4
Czy mógłbyś podać przykłady „przekazywania przez odniesienie” i „przekazywania przez wartość”, tak jak w przypadku „przekazywania przez odniesienie do obiektu”.
TJain

@TJain Przekazywanie przez referencję i przekazywanie przez wartość można zobaczyć w C ++. Ta odpowiedź daje dobre wyjaśnienie: stackoverflow.com/a/430958/5076583
Shobhit Verma

3
Nadal nie rozumiem, czym różni się to od przekazywania przez odniesienie. Ta odpowiedź rozpaczliwie potrzebuje przykładu, jak identyczny pseudokod dałby różne wyniki dla wszystkich 3 paradygmatów. Nie pomaga powiązanie z inną odpowiedzią, która wyjaśnia tylko różnicę między przekazywaniem przez odniesienie a przekazywaniem wartości.
Jess Riedel,

Czy nie łatwiej jest powiedzieć, że „wszystkie zmienne w Pythonie są wskaźnikami ” i „wszystkie zmienne przypisane do parametrów w wywołaniu funkcji są przypisane do nowych wskaźników?”. Jeśli zdasz sobie z tego sprawę, zobaczysz, że Python jest jak Java: po prostu zawsze przekazuje wskaźniki według wartości . Zobacz odpowiedź Kirka Strausera
Marco Sulla

27

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 do barbycia wskaźnikiem do „jakiejś wartości”.

Kiedy dzwonisz foo(bar), nie omijasz barsiebie. Przekazujesz barwartość ': 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 „nadpisz xnową 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ść” (ze barwskazaniem) i „inna wartość” (ze xwskazaniem).

To nie jest niezdarne. Kiedy zrozumiesz, jak to działa, jest to pięknie elegancki, wydajny system.


3
Ale co, jeśli chcę, aby funkcja zmieniła zawartość mojej zmiennej? Rozumiem, że nie da się tego zrobić?
aquirdturtle

1
Możesz zmienić obiekt, na który wskazuje nazwa , np. Poprzez dodanie do listy, jeśli obiekt ten jest zmienny. W Pythonie nie ma semantyki mówiącej „zmień przestrzeń nazw zakresu, który wywołał mnie, tak aby nazwa na mojej liście argumentów wskazywała teraz na coś innego niż wtedy, gdy wywołała mnie”.
Kirk Strauser

2
W rzeczywistości pytam, czy istnieje prosty sposób, aby Python nie utworzył nowego wskaźnika do tego samego obiektu, ale zamiast tego używał oryginalnego wskaźnika. Rozumiem, że nie da się tego zrobić. Z innych odpowiedzi wynika, że ​​normalnym obejściem do osiągnięcia tego, co robi przekazywanie przez odniesienie, jest po prostu zwrócenie większej liczby parametrów. jeśli tak jest, widzę pewną słuszność w argumencie, że a, b, c, d, e = foo (a, b, c, d, e) jest trochę bardziej niezgrabne niż po prostu foo (a, b, c, d, e).
aquirdturtle

2
@aquirdturtle Nie ma to nic wspólnego z faktem, że tworzony jest nowy wskaźnik. Musisz zwrócić nowy obiekt, ponieważ string, tuples i inne obiekty są niezmienne . Jeśli przekazujesz zmienny obiekt, taki jak a list, 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.
Marco Sulla

24

Mam nadzieję, że poniższy opis dobrze to podsumowuje:

Należy wziąć pod uwagę dwie rzeczy - zmienne i obiekty.

  1. Jeśli przekazujesz zmienną, jest ona przekazywana przez wartość, co oznacza, że ​​zmiany dokonane w zmiennej w ramach funkcji są lokalne dla tej funkcji i dlatego nie będą odzwierciedlane globalnie. To bardziej przypomina zachowanie „C”.

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
  1. Jeśli przekazujesz zmienne spakowane w zmiennym obiekcie, takim jak lista, to zmiany wprowadzone w obiekcie są odzwierciedlane globalnie, o ile obiekt nie zostanie ponownie przypisany.

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']]
  1. Rozważmy teraz przypadek, w którym obiekt został ponownie przypisany. W tym przypadku obiekt odnosi się do nowej lokalizacji pamięci, która jest lokalna dla funkcji, w której to się dzieje, a zatem nie jest odzwierciedlana globalnie.

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]

2
To najlepsze podsumowanie! ^^^ NAJLEPSZE PODSUMOWANIE ^^^ wszyscy czytają tę odpowiedź! 1.
Przekaż

4
Ta odpowiedź jest bardzo zagmatwana. Python nie przekazuje różnych rodzajów wartości w różny sposób: wszystkie argumenty funkcji w Pythonie otrzymują swoje wartości przez przypisanie i zachowują się dokładnie tak samo, jak przypisanie zachowuje się gdziekolwiek indziej w języku. („Chociaż z początku może to nie być oczywiste, chyba że jesteś Holendrem”)
Daniel Pryden

9

Python nie jest przekazywany przez wartość ani przekazywany przez odniesienie. To bardziej „odniesienia do obiektów są przekazywane przez wartość”, jak opisano tutaj :

  1. 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.

  1. 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

4

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'}

1
„Niezmienne argumenty są skutecznie przekazywane przez wartość: ciąg, liczba całkowita, krotka są przekazywane przez odniesienie” to zdanie ma wewnętrzną sprzeczność
eral

@eral, jeśli rozumiesz pełny kontekst, nie zaprzecza sobie. Zredagowałem to, aby było jaśniejsze.
Watki02,

2

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.


to odpowiada na połowę pytania, więc jak napisałbym tę samą funkcję set_3 (x), aby nie zmieniała wartości l, ale zwracała nową listę, która została zmieniona?
Timothy Lawman

Po prostu zrób nową listę i zmodyfikuj ją:y = [a for a in x]; y[0] = 3; return y
Izaak

cała sprawa obejmuje listy i kopiowanie list, które w pewnym sensie prowadzą do odpowiedzi, ale jak mogę to zrobić bez konieczności konwertowania int na listę, czy jest to najlepsze, co mamy?
Timothy Lawman

Nie możesz modyfikować prostego argumentu, takiego jak int. Musisz go włożyć do jakiegoś pojemnika. Mój przykład umieścił to na liście. Możesz również umieścić go w klasie lub słowniku. Naprawdę jednak powinieneś po prostu ponownie przypisać go poza funkcją za pomocą czegoś takiego jak x = foo(x).
Izaak

0

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?


0

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 .


0
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)

-2

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.


1
To całkowicie błędne. Python zawsze przechodzi przez „odwołanie do obiektu” (które różni się od odwołania do zmiennej).
Kirk Strauser

Miałem na myśli analogie zmienne obiekty - przekazywanie przez odniesienie i niezmienne obiekty - przekazywanie przez wartość. jest to całkowicie poprawne, co mówię. prawdopodobnie nie złapałeś tego, co mówiłem
jkalivas

1
Złapałem to i jest źle. Nie ma to nic wspólnego z tym, czy obiekt jest zmienny, czy niezmienny; zawsze robi się to w ten sam sposób.
Kirk Strauser

-2

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

Nie, to nieprawdadef 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))
Zohaib Ijaz
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.