Przejdź do treści
> 💻 🧠 Kod 1001 > 📚 Materiały Edukacyjne > 🐍 Python > 📘 Kolekcje w Pythonie Kolekcje w Pythonie

📘 Kolekcje w Pythonie Kolekcje w Pythonie

Kolekcje zwykle obsługują:

  • iterację (for element in kolekcja)
  • sprawdzanie przynależności (x in kolekcja)
  • wyznaczanie długości (len(kolekcja))
  • dostęp przez indeks lub klucz (jeśli uporządkowane lub asocjacyjne)

Python nie ma ścisłego „interfejsu kolekcji”, ale stosuje nieformalne protokoły. Jeśli obiekt implementuje __iter__, __len__, __contains__, można go uznać za kolekcję.


Co NIE jest kolekcją

Następujące typy nie są kolekcjami, ponieważ nie zawierają grup elementów:

  • int, float, bool — wartości skalarne
  • None — brak wartości
  • funkcje, moduły, klasy — to obiekty, ale nie kontenery danych (chyba że zawierają __dict__)

Wbudowane kolekcje

Dostępne bez importowania:

TypOpis
listUporządkowana, mutowalna sekwencja.
tupleUporządkowana, niemutowalna sekwencja.
dictUporządkowane (od Pythona 3.7) mapowanie klucz-wartość.
setNieuporządkowana kolekcja unikalnych elementów.
frozensetNiemutowalna wersja set.

Rozszerzone kolekcje z biblioteki standardowej

TypModułPrzeznaczenie
SimpleNamespacetypesObiekt z dynamicznymi atrybutami (alternatywa dla dict z dostępem przez .).
namedtuplecollectionsNiemutowalna krotka z nazwanymi polami.
dequecollectionsKolejka dwustronna — wydajna dla operacji na obu końcach.
CountercollectionsPodklasa dict do zliczania obiektów hashowalnych.
defaultdictcollectionsSłownik z wartościami domyślnymi dla brakujących kluczy.
dataclassdataclassesAutomatycznie generuje __init__, __repr__, __eq__ itd.
UserListcollectionsKlasa bazowa dla niestandardowych list.
UserDictcollectionsKlasa bazowa dla niestandardowych słowników.

Inne typy podobne do kolekcji

Choć nie zawsze nazywane „kolekcjami”, te typy również reprezentują lub przechowują grupy danych.

1. str — łańcuch znaków

Uporządkowana, niemutowalna sekwencja znaków.

s = "Python"
print(len(s))        # → 6
print(s[0])          # → P
print('y' in s)      # → True
print(list(s))       # → ['P', 'y', 't', 'h', 'o', 'n']

2. bytes, bytearray

  • bytes — niemutowalna sekwencja bajtów.
  • bytearray — mutowalna wersja.
b = b"czesc"
print(b[0])          # → 99
print(len(b))        # → 5

ba = bytearray(b"czesc")
ba[0] = 72
print(ba)            # → bytearray(b'Hzesc')

3. range

Leniwa, uporządkowana sekwencja liczb. Nie przechowuje elementów w pamięci.

r = range(3)
print(list(r))       # → [0, 1, 2]
print(1 in r)        # → True
print(r[2])          # → 2

4. array.array

Przechowuje jednorodne dane liczbowe kompaktowo (jak w C).

from array import array
arr = array('i', [1, 2, 3])  # 'i' = liczba całkowita ze znakiem
print(arr)                   # → array('i', [1, 2, 3])

5. Generatory i iteratory

Nie przechowują danych — generują je na żądanie. Nie obsługują len() ani indeksowania.

gen = (x * 2 for x in range(3))
print(list(gen))     # → [0, 2, 4]
# len(gen) → TypeError

6. ChainMap (z collections)

Grupuje wiele słowników w jedną widokową kolekcję — wyszukiwanie przechodzi przez mapy w kolejności.

from collections import ChainMap

d1 = {'a': 1}
d2 = {'b': 2}
cm = ChainMap(d1, d2)
print(cm['a'])       # → 1
print(cm['b'])       # → 2

7. OrderedDict (z collections)

Słownik, który zapamiętuje kolejność wstawiania. Istotny dla Pythona < 3.7.

from collections import OrderedDict

od = OrderedDict([('a', 1), ('b', 2)])
print(od)            # → OrderedDict([('a', 1), ('b', 2)])

8. enum.Enum, enum.Flag

Zbiory nazwanych stałych.

from enum import Enum

class Kolor(Enum):
    CZERWONY = 1
    ZIELONY = 2

print(list(Kolor))   # → [<Kolor.CZERWONY: 1>, <Kolor.ZIELONY: 2>]

9. typing.NamedTuple, typing.TypedDict

Typowane otoczki wokół namedtuple i dict.

from typing import NamedTuple, TypedDict

class Osoba(NamedTuple):
    imie: str
    wiek: int

p = Osoba("Anna", 25)

class Film(TypedDict):
    tytul: str
    rok: int

m: Film = {"tytul": "Matrix", "rok": 1999}

10. heapq, bisect — narzędzia, nie kolekcje

Działają na kolekcjach, ale nimi nie są:

  • heapq — algorytm kolejki priorytetowej przez listy.
  • bisect — utrzymuje porządek w posortowanych listach.

1. Listy — list

Uporządkowana, mutowalna kolekcja. Elementy mogą się powtarzać, dozwolone są wszystkie typy.

Używana, gdy potrzebna jest elastyczna sekwencja: dodawanie, usuwanie, modyfikowanie elementów.

Tworzenie: []

piotr_list = ["Piotr", "Warszawa", 30, "inżynier"]
print(f"Tworzenie listy: {piotr_list}")
# → Tworzenie listy: ['Piotr', 'Warszawa', 30, 'inżynier']

print(f"Element na indeksie 0: {piotr_list[0]}")
# → Element na indeksie 0: Piotr

piotr_list[2] = 31
print(f"Po zmianie: {piotr_list}")
# → Po zmianie: ['Piotr', 'Warszawa', 31, 'inżynier']

piotr_list.append("żonaty")
print(f"Po append: {piotr_list}")
# → Po append: ['Piotr', 'Warszawa', 31, 'inżynier', 'żonaty']

piotr_list.insert(1, "Polska")
print(f"Po insert: {piotr_list}")
# → Po insert: ['Piotr', 'Polska', 'Warszawa', 31, 'inżynier', 'żonaty']

piotr_list.remove("inżynier")
print(f"Po remove (wartość): {piotr_list}")
# → Po remove (wartość): ['Piotr', 'Polska', 'Warszawa', 31, 'żonaty']

del piotr_list[2]
print(f"Po usunięciu (indeks): {piotr_list}")
# → Po usunięciu (indeks): ['Piotr', 'Polska', 31, 'żonaty']

piotr_list.extend(["hobby", "wędkarstwo"])
print(f"Po extend: {piotr_list}")
# → Po extend: ['Piotr', 'Polska', 31, 'żonaty', 'hobby', 'wędkarstwo']

piotr_list.pop()
print(f"Po pop: {piotr_list}")
# → Po pop: ['Piotr', 'Polska', 31, 'żonaty', 'hobby']

2. Słowniki — dict

Kolekcja par klucz → wartość. Klucze muszą być hashowalne. Od Pythona 3.7 zachowana jest kolejność wstawiania.

Przydatne do danych strukturalnych: profile, konfiguracje, JSON.

Tworzenie: {}

anna_dict = {"imie": "Anna", "wiek": 25, "miasto": "Kraków", "zawod": "artystka"}
print(f"Tworzenie dict: {anna_dict}")
# → Tworzenie dict: {'imie': 'Anna', 'wiek': 25, 'miasto': 'Kraków', 'zawod': 'artystka'}

print(f"Wartość dla klucza 'imie': {anna_dict['imie']}")
# → Wartość dla klucza 'imie': Anna

anna_dict["wiek"] = 26
print(f"Po aktualizacji: {anna_dict}")
# → Po aktualizacji: {'imie': 'Anna', 'wiek': 26, 'miasto': 'Kraków', 'zawod': 'artystka'}

anna_dict["hobby"] = "malarstwo"
print(f"Po dodaniu pary: {anna_dict}")
# → Po dodaniu pary: {'imie': 'Anna', 'wiek': 26, 'miasto': 'Kraków', 'zawod': 'artystka', 'hobby': 'malarstwo'}

del anna_dict["miasto"]
print(f"Po usunięciu pary: {anna_dict}")
# → Po usunięciu pary: {'imie': 'Anna', 'wiek': 26, 'zawod': 'artystka', 'hobby': 'malarstwo'}

hobby = anna_dict.pop("hobby")
print(f"Po pop: {anna_dict}, wartość: {hobby}")
# → Po pop: {'imie': 'Anna', 'wiek': 26, 'zawod': 'artystka'}, wartość: malarstwo

print(f"Klucz 'imie' istnieje: {'imie' in anna_dict}")
# → Klucz 'imie' istnieje: True

3. Krotki — tuple

Uporządkowana, niemutowalna kolekcja. Nadaje się do danych stałych.

Używana, gdy niemutowalność jest ważna: współrzędne, parametry, wartości zwracane.

Tworzenie: ()

piotr_tuple = ("Piotr", "Warszawa", 30, "inżynier")
print(f"Tworzenie krotki: {piotr_tuple}")
# → Tworzenie krotki: ('Piotr', 'Warszawa', 30, 'inżynier')

print(f"Element na indeksie 2: {piotr_tuple[2]}")
# → Element na indeksie 2: 30

# piotr_tuple[0] = "Jan"  → TypeError
# piotr_tuple.append("coś") → AttributeError
  • Krotki zużywają mniej pamięci i są szybsze niż listy.
  • Idealne, gdy nie potrzebna jest mutowalność.

4. SimpleNamespace

Prosta klasa z types do tworzenia obiektów z dynamicznymi atrybutami. Dostęp przez notację kropkową (obj.attr).

Przydatna, gdy potrzebna jest składnia obj.imie bez definiowania klasy.

from types import SimpleNamespace

anna_ns = SimpleNamespace(imie="Anna", wiek=25, miasto="Kraków")
print(f"Obiekt: {anna_ns}")
# → Obiekt: namespace(imie='Anna', wiek=25, miasto='Kraków')

print(f"Imię: {anna_ns.imie}")
# → Imię: Anna

anna_ns.wiek = 26
print(f"Po zmianie: {anna_ns}")
# → Po zmianie: namespace(imie='Anna', wiek=26, miasto='Kraków')

anna_ns.zawod = "artystka"
print(f"Z nowym atrybutem: {anna_ns}")
# → Z nowym atrybutem: namespace(imie='Anna', wiek=26, miasto='Kraków', zawod='artystka')

del anna_ns.miasto
print(f"Po usunięciu: {anna_ns}")
# → Po usunięciu: namespace(imie='Anna', wiek=26, zawod='artystka')

setattr(anna_ns, "hobby", "malarstwo")
print(f"Przez setattr: {anna_ns}")
# → Przez setattr: namespace(imie='Anna', wiek=26, zawod='artystka', hobby='malarstwo')

delattr(anna_ns, "hobby")
print(f"Przez delattr: {anna_ns}")
# → Przez delattr: namespace(imie='Anna', wiek=26, zawod='artystka')
  • Alternatywa dla dict, gdy obj.imie jest lepsze niż obj['imie'].

5. Zbiory — set

Nieuporządkowana kolekcja unikalnych elementów. Obsługuje operacje na zbiorach: suma, przecięcie, różnica.

Używana do usuwania duplikatów i sprawdzania przynależności.

Tworzenie: {} lub set()

liczby = {1, 2, 3, 3, 2, 1}
print(f"Zbiór: {liczby}")
# → Zbiór: {1, 2, 3}

liczby.add(4)
print(f"Po dodaniu: {liczby}")
# → Po dodaniu: {1, 2, 3, 4}

liczby.remove(2)
print(f"Po usunięciu: {liczby}")
# → Po usunięciu: {1, 3, 4}

inne = {3, 4, 5}
print(f"Suma: {liczby | inne}")
# → Suma: {1, 3, 4, 5}

print(f"Przecięcie: {liczby & inne}")
# → Przecięcie: {3, 4}

print(f"Różnica: {liczby - inne}")
# → Różnica: {1}

6. Niemutowalne zbiory — frozenset

Niemutowalna wersja set. Może być użyta jako klucz słownika lub element innego zbioru.

frozen = frozenset([1, 2, 3, 2])
print(f"frozenset: {frozen}")
# → frozenset: frozenset({1, 2, 3})

inne = frozenset([3, 4])
print(f"Przecięcie: {frozen & inne}")
# → Przecięcie: frozenset({3})

print(f"Suma: {frozen | inne}")
# → Suma: frozenset({1, 2, 3, 4})

# frozen.add(5) → AttributeError

7. namedtuple — krotki nazwane

Niemutowalna struktura z dostępem przez nazwę pola. Bardziej czytelna niż zwykłe krotki.

from collections import namedtuple

Osoba = namedtuple("Osoba", ["imie", "wiek", "miasto"])
anna = Osoba("Anna", 25, "Kraków")

print(f"Obiekt: {anna}")
# → Obiekt: Osoba(imie='Anna', wiek=25, miasto='Kraków')

print(f"Imię: {anna.imie}")
# → Imię: Anna

print(f"Wiek: {anna[1]}")
# → Wiek: 25

# anna.wiek = 26 → AttributeError

anna_nowe = anna._replace(wiek=26)
print(f"Kopia z zmianą: {anna_nowe}")
# → Kopia z zmianą: Osoba(imie='Anna', wiek=26, miasto='Kraków')
  • Idealne do rekordów: punkty, użytkownicy, konfiguracje — gdy liczą się niemutowalność i czytelność.

8. deque — kolejka dwustronna

Zoptymalizowana pod szybkie operacje na obu końcach. Wydajniejsza niż list dla appendleft, popleft.

from collections import deque

d = deque([1, 2, 3])
print(f"Początkowy deque: {d}")
# → Początkowy deque: deque([1, 2, 3])

d.appendleft(0)
print(f"Po appendleft: {d}")
# → Po appendleft: deque([0, 1, 2, 3])

d.append(4)
print(f"Po append: {d}")
# → Po append: deque([0, 1, 2, 3, 4])

lewy = d.popleft()
print(f"Po popleft: {lewy}, pozostałe: {d}")
# → Po popleft: 0, pozostałe: deque([1, 2, 3, 4])

prawy = d.pop()
print(f"Po pop: {prawy}, pozostałe: {d}")
# → Po pop: 4, pozostałe: deque([1, 2, 3])
  • Używane w algorytmach: BFS, cache LRU, bufory — gdy operacje na końcach muszą być szybkie.

9. Counter — licznik elementów

Liczy częstotliwość elementów w iterowalnym obiekcie. Przydatne do statystyk i analiz.

from collections import Counter

tekst = "abracadabra"
c = Counter(tekst)
print(f"Liczenie liter: {c}")
# → Liczenie liter: Counter({'a': 5, 'b': 2, 'r': 2, 'c': 1, 'd': 1})

print(f"Częstotliwość 'a': {c['a']}")
# → Częstotliwość 'a': 5

print(f"Top 3: {c.most_common(3)}")
# → Top 3: [('a', 5), ('b', 2), ('r', 2)]

c2 = Counter("bukva")
c.update(c2)
print(f"Po update: {c}")
# → Po update: Counter({'a': 6, 'b': 3, 'r': 2, 'c': 1, 'd': 1, 'u': 1, 'k': 1, 'v': 1})
  • Przydatne do analizy tekstu, logów, głosowań — wszędzie tam, gdzie trzeba policzyć „co pojawia się najczęściej”.

10. defaultdict — słownik z wartościami domyślnymi

Automatycznie tworzy wartości domyślne dla brakujących kluczy. Eliminuje sprawdzanie if key in dict.

from collections import defaultdict

dd_list = defaultdict(list)
dd_list["owoce"].append("jabłko")
dd_list["owoce"].append("banan")
print(f"Lista: {dict(dd_list)}")
# → Lista: {'owoce': ['jabłko', 'banan']}

dd_int = defaultdict(int)
for char in "abracadabra":
    dd_int[char] += 1
print(f"Liczniki: {dict(dd_int)}")
# → Liczniki: {'a': 5, 'b': 2, 'r': 2, 'c': 1, 'd': 1}

dd_set = defaultdict(set)
dd_set["miasta"].add("Warszawa")
dd_set["miasta"].add("Kraków")
print(f"Zbiór: {dict(dd_set)}")
# → Zbiór: {'miasta': {'Warszawa', 'Kraków'}}
  • Eliminuje powtarzalny kod jak if key not in d: d[key] = [].
  • Czyni kod czystszy i bezpieczniejszy.

11. dataclass — klasy danych

Dekorator, który automatycznie generuje __init__, __repr__, __eq__ itd.

from dataclasses import dataclass

@dataclass
class Osoba:
    imie: str
    wiek: int
    miasto: str = "Nieokreślone"

anna = Osoba("Anna", 25)
print(f"Obiekt: {anna}")
# → Obiekt: Osoba(imie='Anna', wiek=25, miasto='Nieokreślone')

print(f"Imię: {anna.imie}")
# → Imię: Anna

anna.wiek = 26
print(f"Po zmianie: {anna}")
# → Po zmianie: Osoba(imie='Anna', wiek=26, miasto='Nieokreślone')

bob = Osoba("Bob", 30)
print(f"Anna == Bob: {anna == bob}")
# → Anna == Bob: False

@dataclass(frozen=True)
class OsobaNiemutowalna:
    imie: str
    wiek: int

ivan = OsobaNiemutowalna("Ivan", 40)
# ivan.wiek = 41 → FrozenInstanceError
  • Zastępuje ręczne pisanie __init__, __repr__, __eq__.
  • Idealne do DTO, konfiguracji, modeli.

12. UserList — niestandardowe listy

Dziedziczy po collections.UserList. Używana do tworzenia list z niestandardowym zachowaniem.

from collections import UserList

class ListaZLogiem(UserList):
    def append(self, item):
        print(f"[LOG] Dodawanie: {item}")
        super().append(item)

    def remove(self, item):
        print(f"[LOG] Usuwanie: {item}")
        super().remove(item)

log_list = ListaZLogiem([1, 2, 3])
print(f"Początkowa: {log_list}")
# → Początkowa: [1, 2, 3]

log_list.append(4)
# → [LOG] Dodawanie: 4
print(f"Po append: {log_list}")
# → Po append: [1, 2, 3, 4]

log_list.remove(2)
# → [LOG] Usuwanie: 2
print(f"Po remove: {log_list}")
# → Po remove: [1, 3, 4]
  • Przydatne do dodawania logowania, walidacji lub modyfikowania standardowego zachowania list.

13. UserDict — niestandardowe słowniki

Dziedziczy po collections.UserDict. Używana do tworzenia słowników z niestandardowym zachowaniem.

from collections import UserDict

class SlownikMaleLitery(UserDict):
    def __setitem__(self, key, value):
        key = key.lower() if isinstance(key, str) else key
        super().__setitem__(key, value)

    def __getitem__(self, key):
        key = key.lower() if isinstance(key, str) else key
        return super().__getitem__(key)

ld = SlownikMaleLitery()
ld["Imie"] = "Anna"
print(f"Wartość dla 'Imie': {ld['Imie']}")
# → Wartość dla 'Imie': Anna
print(f"Wartość dla 'imie': {ld['imie']}")
# → Wartość dla 'imie': Anna
print(f"Klucze: {list(ld.keys())}")
# → Klucze: ['imie']
  • Używana do normalizacji kluczy, walidacji, logowania, cache’owania itp.

📈 Porównanie pamięci i wydajności

Wybór kolekcji wpływa na wydajność i zużycie pamięci. Poniżej praktyczne benchmarki.


1. Pamięć: list vs tuple vs array.array

import sys
from array import array

n = 1_000_000
data = list(range(n))
data_t = tuple(range(n))
data_a = array('i', range(n))

print(f"list:  {sys.getsizeof(data) / 1024 / 1024:.2f} MB")
# → list:  8.00 MB

print(f"tuple: {sys.getsizeof(data_t) / 1024 / 1024:.2f} MB")
# → tuple: 8.00 MB

print(f"array: {sys.getsizeof(data_a) / 1024 / 1024:.2f} MB")
# → array: 3.81 MB
  • array.array zużywa ~2x mniej pamięci dla liczb.
  • list i tuple zużywają podobną pamięć, ale tuple jest nieco szybszy przy iteracji.

2. Szybkość dostępu: list vs tuple vs array.array

import time

def time_access(collection, name):
    start = time.perf_counter()
    total = 0
    for i in range(len(collection)):
        total += collection[i]
    end = time.perf_counter()
    print(f"{name}: {end - start:.4f} sekund")

n = 10_000_000
lst = list(range(n))
tpl = tuple(range(n))
arr = array('i', range(n))

time_access(lst, "list")   # → list: 1.2000 sekund
time_access(tpl, "tuple")  # → tuple: 1.0000 sekund
time_access(arr, "array")  # → array: 0.8000 sekund
  • array.array jest najszybszy dla danych liczbowych.
  • tuple jest 10–20% szybszy niż list.
  • Różnica zauważalna przy dużych zbiorach.

3. Pamięć: dict vs SimpleNamespace vs dataclass

d = {"imie": "A", "wiek": 25, "miasto": "X", "hobby": "Y", "praca": "Z"}
ns = SimpleNamespace(imie="A", wiek=25, miasto="X", hobby="Y", praca="Z")
dc = OsobaDC("A", 25, "X", "Y", "Z")

print(f"dict:      {sys.getsizeof(d)} bajtów")          # → 232
print(f"SimpleNamespace: {sys.getsizeof(ns)} bajtów")   # → 64
print(f"dataclass: {sys.getsizeof(dc)} bajtów")         # → 64
print(f"ns.__dict__: {sys.getsizeof(ns.__dict__)} bajtów")  # → 232
  • SimpleNamespace i dataclass zużywają tyle samo pamięci co dict z powodu __dict__.
  • Użyj __slots__ do oszczędzania pamięci.

4. Optymalizacja pamięci: dataclass z __slots__

@dataclass
class OsobaSlots:
    __slots__ = ("imie", "wiek", "miasto", "hobby", "praca")
    imie: str
    wiek: int
    miasto: str
    hobby: str
    praca: str

dc_slots = OsobaSlots("A", 25, "X", "Y", "Z")
print(f"dataclass + slots: {sys.getsizeof(dc_slots)} bajtów")
# → 80 bajtów

# dc_slots.nowe = "wartość" → AttributeError
  • __slots__ oszczędza pamięć i przyspiesza dostęp do atrybutów.
  • Wada: nie można dodawać atrybutów dynamicznie.

5. Szybkość wyszukiwania: list vs set

n = 1_000_000
lst = list(range(n))
st = set(range(n))

def time_in(collection, target, name):
    start = time.perf_counter()
    for _ in range(1000):
        _ = target in collection
    end = time.perf_counter()
    print(f"{name} (szukanie {target}): {end - start:.4f} sekund")

time_in(lst, 999_999, "list")   # → 10.0000 sekund
time_in(st, 999_999, "set")     # → 0.0005 sekund
  • set jest tysiące razy szybszy niż list przy sprawdzaniu przynależności.
  • Zawsze używaj set do częstych sprawdzeń x in collection.

6. Pamięć: set vs frozenset

s = set(range(1000))
fs = frozenset(range(1000))

print(f"set:       {sys.getsizeof(s)} bajtów")     # → 32792
print(f"frozenset: {sys.getsizeof(fs)} bajtów")   # → 32792
  • frozenset i set zużywają identyczną pamięć.
  • Różnica tylko w mutowalności.

7. Szybkość dodawania: list.append vs deque.append vs deque.appendleft

from collections import deque
import time

def time_append(collection, n, method='append'):
    start = time.perf_counter()
    for i in range(n):
        if method == 'appendleft' and hasattr(collection, 'appendleft'):
            collection.appendleft(i)
        else:
            collection.append(i)
    end = time.perf_counter()
    return end - start

n = 100_000

lst = []
dq = deque()

time_list_append = time_append(lst, n)              # → 0.0100 sekund
time_deque_append = time_append(dq, n)              # → 0.0100 sekund
time_deque_appendleft = time_append(deque(), n, 'appendleft')  # → 0.0100 sekund

# list.insert(0):
lst = []
start = time.perf_counter()
for i in range(n):
    lst.insert(0, i)
end = time.perf_counter()
print(f"list.insert(0):   {end - start:.4f} sekund")   # → 5.0000 sekund
  • deque.appendleft działa w O(1), w przeciwieństwie do list.insert(0), które jest O(n).
  • Używaj deque do częstych operacji na obu końcach.

🧠 Zalecenia dotyczące wydajności

SytuacjaUżyjPowód
Przechowywanie liczb, pamięć krytycznaarray.array2x mniej pamięci, szybszy dostęp
Dane niemutowalnetupleSzybszy niż list, bezpieczniejszy
Częste sprawdzanie x in collectionset / frozensetO(1) vs O(n) dla list
Operacje na obu końcachdequeappendleft/popleft w O(1)
Dane strukturalne, pamięć krytycznadataclass + __slots__Brak __dict__, mniej pamięci
Zliczanie częstotliwościCounterZoptymalizowane pod to zadanie
Niestandardowe zachowanieUserList / UserDictBezpieczne rozszerzenie wbudowanych kolekcji

📊 Porównanie kolekcji

TypUporządkowanyMutowalnyUnikalne elementyDostęp przez indeksDuplikaty
list✅ Tak✅ Tak❌ Nie✅ Tak✅ Tak
tuple✅ Tak❌ Nie❌ Nie✅ Tak✅ Tak
dict✅ Tak*✅ TakTylko klucze❌ NieWartości: ✅
set❌ Nie✅ Tak✅ Tak❌ Nie❌ Nie
frozenset❌ Nie❌ Nie✅ Tak❌ Nie❌ Nie
SimpleNamespace✅ Tak (atrybuty)✅ Tak❌ Nie (atrybuty mogą się powtarzać semantycznie)❌ Nie✅ Tak
namedtuple✅ Tak❌ Nie❌ Nie✅ Tak✅ Tak
deque✅ Tak✅ Tak❌ Nie✅ Tak✅ Tak
Counter❌ Nie✅ Tak❌ Nie❌ Nie (ale ma klucze)✅ Tak
defaultdict✅ Tak*✅ TakTylko klucze❌ NieWartości: ✅
dataclass✅ Tak (pola)✅ Tak (jeśli nie frozen)❌ Nie❌ Nie✅ Tak
UserList✅ Tak✅ Tak❌ Nie✅ Tak✅ Tak
UserDict✅ Tak*✅ TakTylko klucze❌ NieWartości: ✅
str✅ Tak❌ Nie❌ Nie✅ Tak✅ Tak
bytes✅ Tak❌ Nie❌ Nie✅ Tak✅ Tak
bytearray✅ Tak✅ Tak❌ Nie✅ Tak✅ Tak
range✅ Tak❌ Nie❌ Nie✅ Tak❌ Nie
array.array✅ Tak✅ Tak❌ Nie✅ Tak✅ Tak
ChainMap✅ Tak*✅ TakTylko klucze❌ NieWartości: ✅
Enum✅ Tak❌ Nie✅ Tak (elementy)❌ Nie❌ Nie
  • — od Pythona 3.7, dict, defaultdict, UserDict, ChainMap zachowują kolejność wstawiania.

💡 Kiedy użyć czego?

ZadanieKolekcja
Mutowalna sekwencjalist / deque / UserList / bytearray
Dane niemutowalnetuple / namedtuple / frozenset / str / bytes
Szybkie wyszukiwanie, usuwanie duplikatówset / frozenset
Dane strukturalnedict / dataclass / SimpleNamespace / UserDict / TypedDict
Używalne jako klucz słownikafrozenset
Tymczasowe obiekty z dostępem przez .SimpleNamespace / dataclass
Zliczanie częstotliwościCounter
Wartości domyślne dla kluczydefaultdict
Wydajne operacje na końcachdeque
Niestandardowe zachowanie listyUserList
Niestandardowe zachowanie słownikaUserDict
Dane binarnebytes / bytearray / array.array
Konfiguracje z hierarchiąChainMap
Nazwane stałeEnum
Leniwe sekwencjerange / generatory

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Wymagane pola są oznaczone *