W języku Python uzyskujemy dostęp do wartości obiektów poprzez referencjereferencjareferencje. Referencja to nazwa odnosząca się do określonej lokalizacji w pamięci wartości obiektu. Referencje przyjmują często postać zmiennych, atrybutów i elementów.
Zadeklarujmy zmienną x. Kiedy przypiszemy jej wartość 12, nowy obiekt typu int jest alokowany w pamięci, a referencja odwołująca się do niego przypisana jest zmiennej x.
Linia 1. x znak równości 12.
x = 12
Zadeklarujmy nową zmienną y i przypiszmy jej zmienną x.
Linia 1. x znak równości 12.
Linia 2. y znak równości x.
x = 12
y = x
W tym momencie dwie referencje wskazują na obiekt w pamięci przechowujący wartość 12. Aby się o tym przekonać, możemy sprawdzić, do jakiego adresu w pamięci odwołują się referencje – w tym celu użyjemy funkcji id().
Ważne!
W języku Python funkcja id() służy do zwracania identyfikatora obiektu. Identyfikator obiektu jest unikalnym numerem identyfikacyjnym, który jest przypisany do obiektu podczas jego tworzenia. Każdy obiekt w Pythonie ma swój własny identyfikator, który jest unikatowy dla danego uruchomienia interpretera Pythona.
Linia 1. x znak równości 12 kratka Tworzenie zmiennej x i przypisanie jej wartości 12.
Linia 2. y znak równości x kratka Tworzenie zmiennej y i przypisanie jej wartości zmiennej x przecinek co oznacza przecinek że obie zmienne wskazują na ten sam obiekt w pamięci.
Linia 4. kratka Sprawdzenie przecinek czy identyfikatory obu zmiennych są takie same przecinek czyli czy wskazują na ten sam obiekt.
Linia 5. print otwórz nawias okrągły id otwórz nawias okrągły x zamknij nawias okrągły znak równości znak równości id otwórz nawias okrągły y zamknij nawias okrągły zamknij nawias okrągły kratka Wynik będzie True przecinek ponieważ zarówno x przecinek jak i y wskazują na ten sam obiekt w pamięci.
Linia 7. kratka Sprawdzenie przecinek czy obie zmienne x i y wskazują na ten sam obiekt przecinek używając operatora is.
Linia 8. print otwórz nawias okrągły x is y zamknij nawias okrągły kratka Wynik będzie True przecinek ponieważ operator is porównuje identyfikatory obiektów przecinek a x i y wskazują na ten sam obiekt.
x = 12 # Tworzenie zmiennej x i przypisanie jej wartości 12
y = x # Tworzenie zmiennej y i przypisanie jej wartości zmiennej x, co oznacza, że obie zmienne wskazują na ten sam obiekt w pamięci
# Sprawdzenie, czy identyfikatory obu zmiennych są takie same, czyli czy wskazują na ten sam obiekt
print(id(x) == id(y)) # Wynik będzie True, ponieważ zarówno x, jak i y wskazują na ten sam obiekt w pamięci
# Sprawdzenie, czy obie zmienne x i y wskazują na ten sam obiekt, używając operatora is
print(x is y) # Wynik będzie True, ponieważ operator is porównuje identyfikatory obiektów, a x i y wskazują na ten sam obiekt
Zdefiniujemy teraz kolejną zmienną, tym razem o nazwie z. Przypiszemy jej wartość równą 13.
Linia 1. x znak równości 12 kratka Tworzenie zmiennej x i przypisanie jej wartości 12.
Linia 2. y znak równości x kratka Tworzenie zmiennej y i przypisanie jej wartości zmiennej x przecinek co oznacza przecinek że obie zmienne wskazują na ten sam obiekt w pamięci.
Linia 4. kratka Wyświetlenie identyfikatorów obiektów x i y.
Linia 5. print otwórz nawias okrągły id otwórz nawias okrągły x zamknij nawias okrągły zamknij nawias okrągły kratka Wynik będzie 1726522816 przecinek identyfikator obiektu przechowującego wartość 12.
Linia 6. print otwórz nawias okrągły id otwórz nawias okrągły y zamknij nawias okrągły zamknij nawias okrągły kratka Wynik będzie 1726522816 przecinek ponieważ zarówno x przecinek jak i y wskazują na ten sam obiekt w pamięci.
Linia 8. z znak równości 13 kratka Tworzenie zmiennej z i przypisanie jej wartości 13.
Linia 9. kratka Wyświetlenie identyfikatora obiektu z.
Linia 10. print otwórz nawias okrągły id otwórz nawias okrągły z zamknij nawias okrągły zamknij nawias okrągły kratka Wynik będzie 1726522848 przecinek identyfikator obiektu przechowującego wartość 13.
x = 12 # Tworzenie zmiennej x i przypisanie jej wartości 12
y = x # Tworzenie zmiennej y i przypisanie jej wartości zmiennej x, co oznacza, że obie zmienne wskazują na ten sam obiekt w pamięci
# Wyświetlenie identyfikatorów obiektów x i y
print(id(x)) # Wynik będzie 1726522816, identyfikator obiektu przechowującego wartość 12
print(id(y)) # Wynik będzie 1726522816, ponieważ zarówno x, jak i y wskazują na ten sam obiekt w pamięci
z = 13 # Tworzenie zmiennej z i przypisanie jej wartości 13
# Wyświetlenie identyfikatora obiektu z
print(id(z)) # Wynik będzie 1726522848, identyfikator obiektu przechowującego wartość 13
Ważne!
Jeśli uruchomisz program na swoim komputerze, wartości id będą inne, ponieważ identyfikator jest przypisywany w momencie utworzenia obiektu, nie zostanie przeniesiony.
W ten sposób w pamięci alokowany jest nowy obiekt przechowujący wartość 13. Zmienna z jest referencją do nowo utworzonego obiektu. Nietrudno zauważyć, że referencje y i z nawiązują do dwóch różnych adresów w pamięci
Sytuacja staje się ciekawsza, jeśli zmiennej y przypiszemy wartość o 1 większą.
Linia 1. x znak równości 12.
Linia 2. y znak równości x.
Linia 3. print otwórz nawias okrągły id otwórz nawias okrągły x zamknij nawias okrągły zamknij nawias okrągły kratka wynik znak równości 1726522816.
Linia 4. print otwórz nawias okrągły id otwórz nawias okrągły y zamknij nawias okrągły zamknij nawias okrągły kratka wynik znak równości 1726522816.
Linia 6. z znak równości 13.
Linia 7. print otwórz nawias okrągły id otwórz nawias okrągły z zamknij nawias okrągły zamknij nawias okrągły kratka wynik znak równości 1726522848.
Linia 9. y znak równości y plus 1.
Linia 10. print otwórz nawias okrągły id otwórz nawias okrągły x zamknij nawias okrągły zamknij nawias okrągły kratka wynik znak równości 1726522816.
Linia 11. print otwórz nawias okrągły id otwórz nawias okrągły y zamknij nawias okrągły zamknij nawias okrągły kratka wynik znak równości 1726522848.
Linia 12. print otwórz nawias okrągły id otwórz nawias okrągły z zamknij nawias okrągły zamknij nawias okrągły kratka wynik znak równości 1726522848.
x = 12
y = x
print(id(x)) # wynik = 1726522816
print(id(y)) # wynik = 1726522816
z = 13
print(id(z)) # wynik = 1726522848
y = y + 1
print(id(x)) # wynik = 1726522816
print(id(y)) # wynik = 1726522848
print(id(z)) # wynik = 1726522848
Możemy zauważyć, że przypisanie zmiennej y wartości 13 sprawiło, że referencja y odwołuje się do tego samego miejsca w pamięci, co referencja z.
Wynika to z tego, że interpreter Python optymalizuje zużycie pamięci. Przypisuje nową referencję do obiektu, jeśli obiekt o tej samej wartości już istnieje w pamięci.
Spójrzmy teraz na inny przykład. Stworzymy dwie różne listy o tej samej zawartości.
Linia 1. liczby znak równości otwórz nawias kwadratowy 2 przecinek 3 przecinek 5 przecinek 7 zamknij nawias kwadratowy.
Linia 2. pierwsze znak równości otwórz nawias kwadratowy 2 przecinek 3 przecinek 5 przecinek 7 zamknij nawias kwadratowy.
liczby = [2, 3, 5, 7]
pierwsze = [2, 3, 5, 7]
Kiedy sprawdzimy, do jakich adresów odwołują się referencje liczby i pierwsze, zauważymy, że będą to dwie różne lokalizacje.
Linia 1. liczby znak równości otwórz nawias kwadratowy 2 przecinek 3 przecinek 5 przecinek 7 zamknij nawias kwadratowy.
Linia 2. pierwsze znak równości otwórz nawias kwadratowy 2 przecinek 3 przecinek 5 przecinek 7 zamknij nawias kwadratowy.
Linia 4. print otwórz nawias okrągły id otwórz nawias okrągły liczby zamknij nawias okrągły zamknij nawias okrągły kratka wynik znak równości 2602280317512.
Linia 5. print otwórz nawias okrągły id otwórz nawias okrągły pierwsze zamknij nawias okrągły zamknij nawias okrągły kratka wynik znak równości 2602280285384.
liczby = [2, 3, 5, 7]
pierwsze = [2, 3, 5, 7]
print(id(liczby)) # wynik = 2602280317512
print(id(pierwsze)) # wynik = 2602280285384
Dzieje się tak, ponieważ stworzyliśmy dwa różne obiekty. Co więcej, wyrazy o tych samych wartościach z obu list odwołują się do jednakowych lokalizacji.
Linia 1. liczby znak równości otwórz nawias kwadratowy 2 przecinek 3 przecinek 5 przecinek 7 zamknij nawias kwadratowy.
Linia 2. pierwsze znak równości otwórz nawias kwadratowy 2 przecinek 3 przecinek 5 przecinek 7 zamknij nawias kwadratowy.
Linia 4. print otwórz nawias okrągły id otwórz nawias okrągły liczby otwórz nawias kwadratowy 0 zamknij nawias kwadratowy zamknij nawias okrągły zamknij nawias okrągły kratka wynik znak równości 1726522496.
Linia 5. print otwórz nawias okrągły id otwórz nawias okrągły pierwsze otwórz nawias kwadratowy 0 zamknij nawias kwadratowy zamknij nawias okrągły zamknij nawias okrągły kratka wynik znak równości 1726522496.
Linia 7. print otwórz nawias okrągły id otwórz nawias okrągły liczby otwórz nawias kwadratowy 1 zamknij nawias kwadratowy zamknij nawias okrągły zamknij nawias okrągły kratka wynik znak równości 1726522528.
Linia 8. print otwórz nawias okrągły id otwórz nawias okrągły pierwsze otwórz nawias kwadratowy 1 zamknij nawias kwadratowy zamknij nawias okrągły zamknij nawias okrągły kratka wynik znak równości 1726522528.
liczby = [2, 3, 5, 7]
pierwsze = [2, 3, 5, 7]
print(id(liczby[0])) # wynik = 1726522496
print(id(pierwsze[0])) # wynik = 1726522496
print(id(liczby[1])) # wynik = 1726522528
print(id(pierwsze[1])) # wynik = 1726522528
Możemy przypisać referencję liczby do zmiennej referencyjnej pierwsze, wtedy obie zmienne referencyjne będą wskazywać na ten sam adres w pamięci.
Linia 1. liczby znak równości otwórz nawias kwadratowy 2 przecinek 3 przecinek 5 przecinek 7 zamknij nawias kwadratowy.
Linia 2. pierwsze znak równości otwórz nawias kwadratowy 2 przecinek 3 przecinek 5 przecinek 7 zamknij nawias kwadratowy.
Linia 4. print otwórz nawias okrągły id otwórz nawias okrągły liczby zamknij nawias okrągły zamknij nawias okrągły kratka wynik znak równości 2602280317512.
Linia 5. print otwórz nawias okrągły id otwórz nawias okrągły pierwsze zamknij nawias okrągły zamknij nawias okrągły kratka wynik znak równości 2602280285384.
Linia 7. pierwsze znak równości liczby.
Linia 9. print otwórz nawias okrągły id otwórz nawias okrągły liczby zamknij nawias okrągły zamknij nawias okrągły kratka wynik znak równości 2602280317512.
Linia 10. print otwórz nawias okrągły id otwórz nawias okrągły pierwsze zamknij nawias okrągły zamknij nawias okrągły kratka wynik znak równości 2602280317512.
liczby = [2, 3, 5, 7]
pierwsze = [2, 3, 5, 7]
print(id(liczby)) # wynik = 2602280317512
print(id(pierwsze)) # wynik = 2602280285384
pierwsze = liczby
print(id(liczby)) # wynik = 2602280317512
print(id(pierwsze)) # wynik = 2602280317512
Ważne!
Zwróć uwagę na to, że przy kolejnych wywołaniach wyniki różnią się od siebie. Wynika to z tego, że język Python zarządza alokacją pamięci dla obiektów dynamicznie. Kiedy tworzony jest nowy obiekt (np. liczba całkowita, lista, słownik), język Python przydziela mu miejsce w pamięci. Lokalizacja ta jest określana przez system w momencie tworzenia obiektu i może się różnić za każdym razem, gdy uruchamiasz program.
Przykład 1
Z użyciem referencji tworzy się struktury danych z dowiązaniami. Przykładem takiej struktury jest poznana już wcześniej lista jednokierunkowaPuhk7mD92lista jednokierunkowa, której implementacja w języku Python wygląda następująco:
Linia 1. kratka Definicja klasy reprezentującej pojedynczy węzeł listy jednokierunkowej.
Linia 2. class Wezel dwukropek.
Linia 3. def podkreślnik podkreślnik init podkreślnik podkreślnik otwórz nawias okrągły self przecinek klucz znak równości None przecinek nastepny podkreślnik wezel znak równości None zamknij nawias okrągły dwukropek.
Linia 4. self kropka klucz znak równości klucz kratka Wartość przechowywana w węźle.
Linia 5. self kropka nastepny znak równości nastepny podkreślnik wezel kratka Referencja do następnego węzła.
Linia 7. kratka Definicja klasy reprezentującej listę jednokierunkową.
Linia 8. class ListaJednokierunkowa dwukropek.
Linia 9. def podkreślnik podkreślnik init podkreślnik podkreślnik otwórz nawias okrągły self przecinek glowa znak równości None zamknij nawias okrągły dwukropek.
Linia 10. self kropka glowa znak równości glowa kratka Początkowy węzeł listy.
Linia 12. kratka Dodaje element na początek listy.
Linia 13. def dodaj podkreślnik na podkreślnik poczatek otwórz nawias okrągły self przecinek klucz zamknij nawias okrągły dwukropek.
Linia 14. nowy podkreślnik wezel znak równości Wezel otwórz nawias okrągły klucz przecinek self kropka glowa zamknij nawias okrągły kratka Tworzy nowy węzeł jako głowę.
Linia 15. self kropka glowa znak równości nowy podkreślnik wezel kratka Ustawia nowy węzeł jako głowę listy.
Linia 17. kratka Dodaje element na koniec listy.
Linia 18. def dodaj podkreślnik na podkreślnik koniec otwórz nawias okrągły self przecinek klucz zamknij nawias okrągły dwukropek.
Linia 19. if self kropka glowa is None dwukropek.
Linia 20. self kropka glowa znak równości Wezel otwórz nawias okrągły klucz zamknij nawias okrągły kratka Jeśli lista jest pusta przecinek nowy węzeł staje się głową.
Linia 21. else dwukropek.
Linia 22. biezacy znak równości self kropka glowa.
Linia 23. while biezacy kropka nastepny dwukropek kratka Przechodzi przez listę do ostatniego węzła.
Linia 24. biezacy znak równości biezacy kropka nastepny.
Linia 25. biezacy kropka nastepny znak równości Wezel otwórz nawias okrągły klucz zamknij nawias okrągły kratka Dodaje nowy węzeł na koniec listy.
Linia 27. kratka Usuwa i zwraca element z początku listy.
Linia 28. def usun podkreślnik z podkreślnik poczatku otwórz nawias okrągły self zamknij nawias okrągły dwukropek.
Linia 29. if self kropka glowa dwukropek.
Linia 30. usuniety podkreślnik wezel znak równości self kropka glowa kratka Zapamiętuje węzeł do usunięcia.
Linia 31. self kropka glowa znak równości self kropka glowa kropka nastepny kratka Ustawia następny węzeł jako nową głowę.
Linia 32. usuniety podkreślnik wezel kropka nastepny znak równości None kratka Usuwa referencję do następnego węzła.
Linia 33. return usuniety podkreślnik wezel kropka klucz kratka Zwraca wartość usuniętego węzła.
Linia 34. else dwukropek.
Linia 35. return None.
Linia 37. kratka Usuwa i zwraca element z końca listy.
Linia 38. def usun podkreślnik z podkreślnik konca otwórz nawias okrągły self zamknij nawias okrągły dwukropek.
Linia 39. if self kropka glowa is None dwukropek.
Linia 40. return None kratka Lista jest pusta.
Linia 41. elif self kropka glowa kropka nastepny is None dwukropek.
Linia 42. klucz znak równości self kropka glowa kropka klucz kratka Przypadek jednoelementowej listy.
Linia 43. self kropka glowa znak równości None kratka Lista staje się pusta.
Linia 44. return klucz.
Linia 45. else dwukropek.
Linia 46. biezacy znak równości self kropka glowa.
Linia 47. while biezacy kropka nastepny kropka nastepny dwukropek kratka Szuka przedostatniego węzła.
Linia 48. biezacy znak równości biezacy kropka nastepny.
Linia 49. klucz znak równości biezacy kropka nastepny kropka klucz kratka Zapamiętuje wartość ostatniego węzła.
Linia 50. biezacy kropka nastepny znak równości None kratka Usuwa ostatni węzeł z listy.
Linia 51. return klucz.
Linia 53. kratka Reprezentacja listy jako ciągu znaków.
Linia 54. def podkreślnik podkreślnik str podkreślnik podkreślnik otwórz nawias okrągły self zamknij nawias okrągły dwukropek.
Linia 55. elementy znak równości otwórz nawias kwadratowy zamknij nawias kwadratowy.
Linia 56. biezacy znak równości self kropka glowa.
Linia 57. while biezacy dwukropek kratka Przechodzi przez listę przecinek dodając klucze do ciągu wynikowego.
Linia 58. elementy kropka append otwórz nawias okrągły str otwórz nawias okrągły biezacy kropka klucz zamknij nawias okrągły zamknij nawias okrągły.
Linia 59. biezacy znak równości biezacy kropka nastepny.
Linia 60. return cudzysłów minus zamknij nawias ostrokątny cudzysłów kropka join otwórz nawias okrągły elementy zamknij nawias okrągły if elementy else cudzysłów Pusta cudzysłów kratka Zwraca łańcuch znaków.
Linia 62. kratka Zwraca długość listy.
Linia 63. def podkreślnik podkreślnik len podkreślnik podkreślnik otwórz nawias okrągły self zamknij nawias okrągły dwukropek.
Linia 64. licznik znak równości 0.
Linia 65. biezacy znak równości self kropka glowa.
Linia 66. while biezacy dwukropek kratka Liczy elementy w liście.
Linia 67. licznik plus znak równości 1.
Linia 68. biezacy znak równości biezacy kropka nastepny.
Linia 69. return licznik.
Linia 71. kratka Demonstracja użycia klasy ListaJednokierunkowa.
Linia 72. if podkreślnik podkreślnik name podkreślnik podkreślnik znak równości znak równości apostrof podkreślnik podkreślnik main podkreślnik podkreślnik apostrof dwukropek.
Linia 73. liczby znak równości ListaJednokierunkowa otwórz nawias okrągły zamknij nawias okrągły.
Linia 74. liczby kropka dodaj podkreślnik na podkreślnik koniec otwórz nawias okrągły 4 zamknij nawias okrągły.
Linia 75. liczby kropka dodaj podkreślnik na podkreślnik koniec otwórz nawias okrągły 5 zamknij nawias okrągły.
Linia 76. print otwórz nawias okrągły liczby zamknij nawias okrągły kratka Wyświetla dwukropek 4 minus zamknij nawias ostrokątny 5.
Linia 78. liczby kropka dodaj podkreślnik na podkreślnik poczatek otwórz nawias okrągły 1 zamknij nawias okrągły.
Linia 79. liczby kropka dodaj podkreślnik na podkreślnik poczatek otwórz nawias okrągły 2 zamknij nawias okrągły.
Linia 81. print otwórz nawias okrągły zamknij nawias okrągły.
Linia 82. print otwórz nawias okrągły liczby zamknij nawias okrągły kratka Wyświetla dwukropek 2 minus zamknij nawias ostrokątny 1 minus zamknij nawias ostrokątny 4 minus zamknij nawias ostrokątny 5.
Linia 83. print otwórz nawias okrągły apostrof Długość ciągu dwukropek apostrof przecinek len otwórz nawias okrągły liczby zamknij nawias okrągły zamknij nawias okrągły kratka Wyświetla dwukropek długość dwukropek 4.
Linia 85. print otwórz nawias okrągły zamknij nawias okrągły.
Linia 86. liczby kropka usun podkreślnik z podkreślnik poczatku otwórz nawias okrągły zamknij nawias okrągły.
Linia 87. print otwórz nawias okrągły liczby zamknij nawias okrągły kratka Wyświetla dwukropek 1 minus zamknij nawias ostrokątny 4 minus zamknij nawias ostrokątny 5.
Linia 88. print otwórz nawias okrągły apostrof Długość ciągu dwukropek apostrof przecinek len otwórz nawias okrągły liczby zamknij nawias okrągły zamknij nawias okrągły kratka Wyświetla dwukropek długość dwukropek 3.
Linia 90. liczby kropka usun podkreślnik z podkreślnik konca otwórz nawias okrągły zamknij nawias okrągły.
Linia 91. print otwórz nawias okrągły zamknij nawias okrągły.
Linia 92. liczby kropka usun podkreślnik z podkreślnik poczatku otwórz nawias okrągły zamknij nawias okrągły.
Linia 93. print otwórz nawias okrągły liczby zamknij nawias okrągły kratka Wyświetla dwukropek 1 minus zamknij nawias ostrokątny 4.
Linia 94. print otwórz nawias okrągły apostrof Długość ciągu dwukropek apostrof przecinek len otwórz nawias okrągły liczby zamknij nawias okrągły zamknij nawias okrągły kratka Wyświetla dwukropek długość dwukropek 2.
Linia 96. liczby kropka usun podkreślnik z podkreślnik konca otwórz nawias okrągły zamknij nawias okrągły.
Linia 97. print otwórz nawias okrągły zamknij nawias okrągły.
Linia 98. liczby kropka usun podkreślnik z podkreślnik poczatku otwórz nawias okrągły zamknij nawias okrągły.
Linia 99. print otwórz nawias okrągły apostrof Długość ciągu dwukropek apostrof przecinek len otwórz nawias okrągły liczby zamknij nawias okrągły zamknij nawias okrągły kratka Wyświetla dwukropek długość dwukropek 1.
Linia 101. liczby kropka usun podkreślnik z podkreślnik konca otwórz nawias okrągły zamknij nawias okrągły.
# Definicja klasy reprezentującej pojedynczy węzeł listy jednokierunkowej
class Wezel:
def __init__(self, klucz=None, nastepny_wezel=None):
self.klucz = klucz # Wartość przechowywana w węźle
self.nastepny = nastepny_wezel # Referencja do następnego węzła
# Definicja klasy reprezentującej listę jednokierunkową
class ListaJednokierunkowa:
def __init__(self, glowa=None):
self.glowa = glowa # Początkowy węzeł listy
# Dodaje element na początek listy
def dodaj_na_poczatek(self, klucz):
nowy_wezel = Wezel(klucz, self.glowa) # Tworzy nowy węzeł jako głowę
self.glowa = nowy_wezel # Ustawia nowy węzeł jako głowę listy
# Dodaje element na koniec listy
def dodaj_na_koniec(self, klucz):
if self.glowa is None:
self.glowa = Wezel(klucz) # Jeśli lista jest pusta, nowy węzeł staje się głową
else:
biezacy = self.glowa
while biezacy.nastepny: # Przechodzi przez listę do ostatniego węzła
biezacy = biezacy.nastepny
biezacy.nastepny = Wezel(klucz) # Dodaje nowy węzeł na koniec listy
# Usuwa i zwraca element z początku listy
def usun_z_poczatku(self):
if self.glowa:
usuniety_wezel = self.glowa # Zapamiętuje węzeł do usunięcia
self.glowa = self.glowa.nastepny # Ustawia następny węzeł jako nową głowę
usuniety_wezel.nastepny = None # Usuwa referencję do następnego węzła
return usuniety_wezel.klucz # Zwraca wartość usuniętego węzła
else:
return None
# Usuwa i zwraca element z końca listy
def usun_z_konca(self):
if self.glowa is None:
return None # Lista jest pusta
elif self.glowa.nastepny is None:
klucz = self.glowa.klucz # Przypadek jednoelementowej listy
self.glowa = None # Lista staje się pusta
return klucz
else:
biezacy = self.glowa
while biezacy.nastepny.nastepny: # Szuka przedostatniego węzła
biezacy = biezacy.nastepny
klucz = biezacy.nastepny.klucz # Zapamiętuje wartość ostatniego węzła
biezacy.nastepny = None # Usuwa ostatni węzeł z listy
return klucz
# Reprezentacja listy jako ciągu znaków
def __str__(self):
elementy = []
biezacy = self.glowa
while biezacy: # Przechodzi przez listę, dodając klucze do ciągu wynikowego
elementy.append(str(biezacy.klucz))
biezacy = biezacy.nastepny
return " -> ".join(elementy) if elementy else "Pusta" # Zwraca łańcuch znaków
# Zwraca długość listy
def __len__(self):
licznik = 0
biezacy = self.glowa
while biezacy: # Liczy elementy w liście
licznik += 1
biezacy = biezacy.nastepny
return licznik
# Demonstracja użycia klasy ListaJednokierunkowa
if __name__ == '__main__':
liczby = ListaJednokierunkowa()
liczby.dodaj_na_koniec(4)
liczby.dodaj_na_koniec(5)
print(liczby) # Wyświetla: 4 -> 5
liczby.dodaj_na_poczatek(1)
liczby.dodaj_na_poczatek(2)
print()
print(liczby) # Wyświetla: 2 -> 1 -> 4 -> 5
print('Długość ciągu:', len(liczby)) # Wyświetla: długość: 4
print()
liczby.usun_z_poczatku()
print(liczby) # Wyświetla: 1 -> 4 -> 5
print('Długość ciągu:', len(liczby)) # Wyświetla: długość: 3
liczby.usun_z_konca()
print()
liczby.usun_z_poczatku()
print(liczby) # Wyświetla: 1 -> 4
print('Długość ciągu:', len(liczby)) # Wyświetla: długość: 2
liczby.usun_z_konca()
print()
liczby.usun_z_poczatku()
print('Długość ciągu:', len(liczby)) # Wyświetla: długość: 1
liczby.usun_z_konca()
Program demonstruje działanie listy jednokierunkowej poprzez serię operacji dodawania i usuwania elementów. Używamy klas do reprezentacji struktury danych (listy jednokierunkowej) oraz operacji wykonywanych na tej liście.
Wynik działania programu:
Linia 1. 4 minus zamknij nawias ostrokątny 5.
Linia 3. 2 minus zamknij nawias ostrokątny 1 minus zamknij nawias ostrokątny 4 minus zamknij nawias ostrokątny 5.
Linia 4. Długość ciągu dwukropek 4.
Linia 6. 1 minus zamknij nawias ostrokątny 4 minus zamknij nawias ostrokątny 5.
Linia 7. Długość ciągu dwukropek 3.
Linia 9. 4.
Linia 10. Długość ciągu dwukropek 1.
Linia 12. Długość ciągu dwukropek.
4 -> 5
2 -> 1 -> 4 -> 5
Długość ciągu: 4
1 -> 4 -> 5
Długość ciągu: 3
4
Długość ciągu: 1
Długość ciągu:
Zarządzanie pamięcią
W momencie uruchomienia skryptu języka Python interpreter obsługuje pamięć RAM w określony sposób. Na początku rezerwowana jest pewna określona ilość pamięci potrzebna do wykonania programu. To, jak wielki obszar pamięci będzie zarezerwowany, zależy od systemu operacyjnego, wersji interpretera itp.
Wyróżniamy dwa rodzaje pamięci obsługiwane przez interpreter Python.
Stos – pamięć o szybkim dostępie, przechowuje referencje niezbędne do wykonania funkcji. Operacje na stosie wykonywane są w kolejności LIFO. W momencie wywołania funkcji na stosie tworzony jest blok zawierający wartości zmiennych prymitywnychzmienne prymitywnezmiennych prymitywnych i referencji do obiektów – są to parametry wymagane do działania funkcji.
Sterta – pamięć o powolnym odczycie i dostępie, zawiera wszystkie utworzone obiekty. Nieużywane obiekty są regularnie sprawdzane i usuwane przez odpowiednie mechanizmy interpretera.
Implementacja Pythona o nazwie CPython ma wbudowane komponenty odpowiadające za usuwanie z pamięci nieużywanych obiektów.
Pierwszym mechanizmem czyszczenia pamięci w CPythonie jest licznik referencji. Za każdym razem, gdy tworzony jest obiekt w Pythonie, bazowy obiekt C ma zarówno typ Pythona, jak i liczbę referencji wskazujących do niego.
Liczba referencji do obiektu w Pythonie jest zwiększana za każdym razem, gdy pojawia się nowa referencja do obiektu. Zmniejsza się natomiast, gdy następuje dereferencjadereferencjadereferencja. Jeśli liczba odwołań do obiektu wynosi 0, obiekt jest zwalniany z pamięci.
Licznik referencji ma pewne wady, w tym niezdolność do wykrywania cyklicznych referencji. Dzieje się tak, ponieważ licznik referencji w takim przypadku zawsze będzie pokazywać liczbę większą od 0.
Problem ten rozwiązuje odśmiecacz (garbage collectorgarbage collectorgarbage collector), który ma za zadanie przerwać cykliczne referencje.
Słownik
dereferencja
dereferencja
proces pobierania wartości, na którą wskazuje referencja lub odwołanie; Python jest językiem wysokiego poziomu i automatycznie zajmuje się alokacją i dealokacją pamięci, co eliminuje potrzebę bezpośredniego korzystania z referencji; wszystkie zmienne są odwołaniami do obiektów, a operacje, które można by uznać za „dereferencje” w innych językach, są w języku Python operacjami na obiektach; przy przypisaniu zmiennej do innej zmiennej w języku Python przypisywane jest odwołanie do tego samego obiektu, nie powstaje jego kopia:
Linia 1. a znak równości otwórz nawias kwadratowy 1 przecinek 2 przecinek 3 zamknij nawias kwadratowy.
Linia 2. b znak równości a.
a = [1, 2, 3]
b = a
garbage collector
garbage collector
mechanizm automatycznego zarządzania pamięcią
referencja
referencja
nazwa odnosząca się do określonej lokalizacji w pamięci wartości obiektu
zmienne prymitywne
zmienne prymitywne
zmienne typu prymitywnego przechowują w pamięci konkretne wartości; w języku Python mówimy o typach wbudowanych