Last modified: June 06, 2026
This article is written in: 🇵🇱
Serializacja to proces przekształcania obiektów lub struktur danych w format, który można łatwo przechowywać, przesyłać i odtwarzać. Dzięki serializacji możemy zapisać stan obiektu w pliku, przesłać go przez sieć lub przechowywać w bazie danych, a następnie w dowolnym momencie przywrócić go do pierwotnej postaci poprzez deserializację. Jest to kluczowy mechanizm w programowaniu, który umożliwia efektywną wymianę danych między różnymi systemami i komponentami.
+--------------------+ Serializacja +-----------------+
| Obiekt Pythona | ------------------------> | Bajty |
+--------------------+ +-----------------+
^ |
| |
| Deserializacja |
| |
| v
+--------------------+ Deserializacja +-----------------+
| Bajty | <------------------------ | Obiekt Pythona |
+--------------------+ +-----------------+
Serializacja znajduje zastosowanie w wielu obszarach programowania:
pickleW Pythonie jednym z podstawowych narzędzi do serializacji jest moduł pickle. Pozwala on na konwersję niemal dowolnych obiektów Pythona do ciągu bajtów i odwrotnie. Poniżej przedstawiono przykład, jak można zserializować i deserializować obiekt klasy Czlowiek:
import pickle
class Czlowiek:
def __init__(self, imie, numer):
self.imie = imie
self.numer = numer
def __repr__(self):
return f'Imię: {self.imie}, Numer: {self.numer}'
# Ścieżka do pliku, w którym zapiszemy dane
sciezka = 'przyklad.pickle'
# Serializacja obiektu
with open(sciezka, 'wb') as plik:
obiekt = Czlowiek('James', 10)
pickle.dump(obiekt, plik)
# Deserializacja obiektu
with open(sciezka, 'rb') as plik:
obiekt = pickle.load(plik)
print(obiekt)
Po uruchomieniu tego kodu, otrzymamy wynik:
Imię: James, Numer: 10
Korzystając z modułu pickle, należy zachować ostrożność. Deserializacja danych z niezaufanych źródeł może być niebezpieczna, ponieważ może prowadzić do wykonania złośliwego kodu. Dlatego zaleca się używanie pickle tylko z danymi pochodzącymi z zaufanych źródeł. W sytuacjach wymagających większego bezpieczeństwa warto rozważyć użycie innych formatów, takich jak JSON czy XML.
jsonFormat JSON (JavaScript Object Notation) jest jednym z najpopularniejszych formatów do wymiany danych między aplikacjami, zwłaszcza w kontekście aplikacji webowych. Python oferuje moduł json, który pozwala na serializację i deserializację obiektów do formatu JSON.
import json
class Czlowiek:
def __init__(self, imie, numer):
self.imie = imie
self.numer = numer
def to_dict(self):
return {'imie': self.imie, 'numer': self.numer}
@classmethod
def from_dict(cls, dane):
return cls(dane['imie'], dane['numer'])
# Serializacja obiektu do JSON
obiekt = Czlowiek('James', 10)
json_str = json.dumps(obiekt.to_dict())
print(json_str)
Wynik:
{"imie": "James", "numer": 10}
Aby zdeserializować dane z formatu JSON:
# Deserializacja obiektu z JSON
dane = json.loads(json_str)
obiekt = Czlowiek.from_dict(dane)
print(obiekt)
Wynik:
Imię: James, Numer: 10
xml.etree.ElementTreeFormat XML (eXtensible Markup Language) jest kolejnym popularnym formatem do przechowywania i wymiany danych. W Pythonie możemy użyć modułu xml.etree.ElementTree do pracy z danymi XML.
import xml.etree.ElementTree as ET
class Czlowiek:
def __init__(self, imie, numer):
self.imie = imie
self.numer = numer
def to_xml(self):
czlowiek = ET.Element('Czlowiek')
imie_elem = ET.SubElement(czlowiek, 'Imie')
imie_elem.text = self.imie
numer_elem = ET.SubElement(czlowiek, 'Numer')
numer_elem.text = str(self.numer)
return ET.tostring(czlowiek, encoding='unicode')
@classmethod
def from_xml(cls, xml_data):
root = ET.fromstring(xml_data)
imie = root.find('Imie').text
numer = int(root.find('Numer').text)
return cls(imie, numer)
# Serializacja obiektu do XML
obiekt = Czlowiek('James', 10)
xml_str = obiekt.to_xml()
print(xml_str)
Wynik:
<Czlowiek><Imie>James</Imie><Numer>10</Numer></Czlowiek>
Deserializacja z XML:
# Deserializacja obiektu z XML
obiekt = Czlowiek.from_xml(xml_str)
print(obiekt)
Wynik:
Imię: James, Numer: 10
Aby lepiej zrozumieć proces serializacji i deserializacji, spójrzmy na poniższy diagram:
| Obiekt Pythona |
+-----------+-----------+
|
| Serializacja
v
+-----------------------+
| Format danych |
| (JSON, XML, bajty) |
+-----------+-----------+
|
| Deserializacja
v
+-----------------------+
| Obiekt Pythona |
+-----------------------+
Proces ten polega na przekształceniu obiektu Pythona w format danych, który można łatwo przechowywać lub przesyłać, a następnie przywróceniu go do pierwotnej postaci.
Wyobraźmy sobie aplikację, w której użytkownik tworzy złożone obiekty, takie jak profile użytkowników, konfiguracje czy stany gry. Chcemy umożliwić zapisanie tych obiektów do pliku, aby można było je później wczytać lub przesłać innym użytkownikom.
import json
class Postac:
def __init__(self, imie, poziom, ekwipunek):
self.imie = imie
self.poziom = poziom
self.ekwipunek = ekwipunek
def to_dict(self):
return {
'imie': self.imie,
'poziom': self.poziom,
'ekwipunek': self.ekwipunek
}
@classmethod
def from_dict(cls, dane):
return cls(dane['imie'], dane['poziom'], dane['ekwipunek'])
# Tworzenie obiektu postaci
postac = Postac('Aragorn', 20, ['Miecz', 'Tarcza', 'Pierścień'])
# Serializacja do JSON i zapis do pliku
with open('postac.json', 'w') as plik:
json.dump(postac.to_dict(), plik)
# Deserializacja z pliku JSON
with open('postac.json', 'r') as plik:
dane = json.load(plik)
postac_wczytana = Postac.from_dict(dane)
print(f"Imię: {postac_wczytana.imie}, Poziom: {postac_wczytana.poziom}, Ekwipunek: {postac_wczytana.ekwipunek}")
Wynik:
Imię: Aragorn, Poziom: 20, Ekwipunek: ['Miecz', 'Tarcza', 'Pierścień']
Jeśli chcemy przesłać dane między różnymi aplikacjami lub usługami sieciowymi, możemy użyć formatu JSON lub XML, który jest uniwersalny i obsługiwany przez wiele języków programowania.
Podczas korzystania z serializacji, szczególnie z modułem pickle, należy być świadomym potencjalnych zagrożeń. Deserializacja danych z nieznanych źródeł może prowadzić do wykonania złośliwego kodu. Zawsze upewnij się, że dane pochodzą z zaufanego źródła lub używaj bezpieczniejszych metod serializacji, takich jak JSON, które nie wykonują kodu podczas deserializacji.
| Format | Moduł | Czytelność | Szybkość | Bezpieczeństwo | Interoperacyjność | Obsługuje obiekty Pythona |
| pickle | pickle |
Nie | Bardzo szybki | Niskie | Tylko Python | Tak (prawie wszystkie) |
| JSON | json |
Tak | Szybki | Wysokie | Uniwersalny | Nie (wymaga konwersji) |
| XML | xml.etree |
Tak | Wolny | Średnie | Uniwersalny | Nie (wymaga konwersji) |
| YAML | pyyaml |
Tak | Średni | Średnie* | Uniwersalny | Częściowo |
| MessagePack | msgpack |
Nie | Bardzo szybki | Wysokie | Uniwersalny | Nie |
| Protocol Buffers | protobuf |
Nie | Najszybszy | Wysokie | Uniwersalny | Nie (wymaga schematu) |
* YAML z yaml.safe_load() jest bezpieczny; yaml.load() bez Loadera — nie.
| Scenariusz | Rekomendowany format |
| API webowe (REST) | JSON |
| Konfiguracja czytelna dla człowieka | YAML lub JSON |
| Wymiana danych między mikroserwisami | MessagePack / Protobuf |
| Zapis stanu aplikacji Python (zaufane źródło) | pickle |
| Wymiana z systemami enterprise (SOAP, RSS) | XML |
| Trwałe przechowywanie z wersjowaniem | JSON + schemat |
| Maksymalna wydajność i minimalny rozmiar | Protocol Buffers |
YAML (YAML Ain't Markup Language) jest popularnym formatem konfiguracyjnym dzięki swojej czytelności:
# pip install pyyaml
import yaml
dane = {
'serwer': {
'host': 'localhost',
'port': 8080,
'debug': True
},
'baza_danych': {
'url': 'sqlite:///app.db',
'pool_size': 5
}
}
# Serializacja do YAML
yaml_str = yaml.dump(dane, default_flow_style=False, allow_unicode=True)
print(yaml_str)
# Deserializacja z YAML (ZAWSZE używaj safe_load!)
odczytane = yaml.safe_load(yaml_str)
print(odczytane['serwer']['port']) # 8080
JSONEncoderimport json
from datetime import datetime, date
from decimal import Decimal
class RozszerzonyEncoder(json.JSONEncoder):
"""Encoder obsługujący datetime, date i Decimal."""
def default(self, obj):
if isinstance(obj, datetime):
return obj.isoformat()
if isinstance(obj, date):
return obj.isoformat()
if isinstance(obj, Decimal):
return float(obj)
return super().default(obj)
dane = {
'utworzono': datetime.now(),
'data': date.today(),
'cena': Decimal('19.99')
}
json_str = json.dumps(dane, cls=RozszerzonyEncoder, indent=2, ensure_ascii=False)
print(json_str)
jsonschema# pip install jsonschema
from jsonschema import validate, ValidationError
schemat = {
"type": "object",
"properties": {
"imie": {"type": "string", "minLength": 1},
"wiek": {"type": "integer", "minimum": 0},
"email": {"type": "string", "format": "email"}
},
"required": ["imie", "wiek"]
}
# Poprawne dane
validate({"imie": "Anna", "wiek": 30}, schemat)
# Niepoprawne dane — rzuci ValidationError
try:
validate({"imie": "", "wiek": -5}, schemat)
except ValidationError as e:
print(f"Błąd walidacji: {e.message}")
import json
import pickle
import sys
import time
dane = [{"id": i, "wartość": i * 3.14, "nazwa": f"element_{i}"} for i in range(10000)]
# Rozmiar serializowanych danych
json_bytes = json.dumps(dane).encode()
pickle_bytes = pickle.dumps(dane)
print(f"JSON: {len(json_bytes):>10,} bajtów")
print(f"Pickle: {len(pickle_bytes):>10,} bajtów")
# Szybkość serializacji
start = time.perf_counter()
for _ in range(100):
json.dumps(dane)
t_json = time.perf_counter() - start
start = time.perf_counter()
for _ in range(100):
pickle.dumps(dane)
t_pickle = time.perf_counter() - start
print(f"JSON: {t_json:.3f}s")
print(f"Pickle: {t_pickle:.3f}s")