# 7. Intrări și ieșiri

Există mai multe moduri de a prezenta rezultatul (sau ieșirea, de la englezescul output) execuției unui program; datele conținute în acest rezultat pot fi afișate într-o formă ușor de citit de către utilizatorii umani (în englezește, ca jargon, human-readable) sau pot fi scrise într-un fișier pentru o întrebuințare ulterioară. În capitolul de față vom discuta despre câteva din aceste feluri de prezentare.

## 7.1. Formatări elegante ale ieșirii

Până acum am întâlnit două modalități de scriere a valorilor: formulările de expresii și funcția `print()`. (O a treia modalitate este să folosim metoda `write()` a obiectelor fișier; fișierul standard de ieșire poate fi accesat ca `sys.stdout`. Vedeți Referința bibliotecii pentru mai multe informații în această privință.)

Adesea, veți dori să aveți mai mult control asupra formatului datelor de afișat decât simpla posibilitate de a le tipări cu câte un spațiu gol între ele. Dispunem de diferite procedee de a formata ieșirile.

- Pentru a folosi șiruri de caractere literale formatate, începeți șirul cu `f` sau cu `F`, poziționate înaintea ghilimelelor duble ori a celor triple de deschidere. În interiorul unui asemenea șir de caractere, puteți scrie o expresie Python încadrată de caracterele `{` și `}`, care să se refere la variabile ori la date literale.

      >>> anul = 2016
      >>> evenimentul = 'referendumul'
      >>> f'Rezultate la {evenimentul} din {anul}.'
      'Rezultate la referendumul din 2016.'

- Metoda `str.format()` a șirurilor de caractere necesită puțin mai multă muncă de redactare. Și aici veți utiliza `{` și `}` la încadrarea locului în care va fi substituită o anumită variabilă, respectiv veți avea posibilitatea de a da indicații detaliate în privința formatării, doar că va trebui să oferiți și informația de formatat. În blocul de cod care urmează se află două exemple despre cum se formatează variabilele:

      >>> voturi_pentru = 42_572_654
      >>> voturi_in_total = 85_705_149
      >>> procentaj = voturi_pentru / voturi_in_total
      >>> '{:-9} voturi PENTRU  {:2.2%}'.format(voturi_pentru, procentaj)
      ' 42572654 voturi PENTRU  49.67%'

  Să remarcăm că valoarea lui `voturi_pentru` este precedată de un spațiu gol la numerele pozitive și de un semn minus la cele negative. În același timp, codul din exemplu va afișa valoarea lui `procentaj` înmulțită cu 100 și urmată de două zecimale, respectiv de semnul procent (a se vedea Mini-limbajul specificației de format pentru detalii).

- În sfârșit, puteți să vă ocupați chiar dumneavoastră de întreaga manipulare a șirurilor de caractere folosind operațiile de tranșare și de concatenare a șirurilor pentru a crea orice machetă (de la englezescul layout) de afișare vă doriți. Tipul de date șir de caractere posedă diverse metode de spațiere a șirurilor la lățimi de caracter date.

Atunci când nu vă interesează nicio ieșire sofisticată ci, pur și simplu, vreți să afișați rapid valorile câtorva variabile în scopul depanării programului la care lucrați, ați putea converti orice valoare obținută într-un șir de caractere cu ajutorul funcțiilor `repr()` și `str()`.

Funcția `str()` a fost gândită să returneze reprezentări de valori care să fie ușor de citit de către utilizatorii umani, pe când funcția `repr()` a primit rolul de a genera reprezentări de date care să fie citite de către interpretorul de Python (sau să ridice o excepție `SyntaxError` atunci când reprezentările nu se potrivesc niciunui șablon sintactic). În cazul obiectelor care nu posedă nicio reprezentare distinctivă de oferit unui consumator uman, `str()` va întoarce aceeași valoare ca și `repr()`. Multe valori, cum ar fi numerele ori structurile de date de tipul listelor și al dicționarelor, primesc aceeași reprezentare de la amândouă funcțiile. Șirurile de caractere, pe de altă parte, posedă două reprezentări diferite.

Câteva exemple:

    >>> s = 'Salutare, lume.'
    >>> str(s)
    'Salutare, lume.'
    >>> repr(s)
    "'Salutare, lume.'"
    >>> str(1/7)
    '0.14285714285714285'
    >>> x = 10 * 3.25
    >>> y = 200 * 200
    >>> s = 'Valoarea lui x este ' + repr(x) + ', iar a lui y este ' + repr(y) + '...'
    >>> print(s)
    Valoarea lui x is 32.5, iar a lui y este 40000...
    >>> # Aplicarea lui repr() unui șir îi adaugă acestuia ghilimele simple
    >>> # și linii oblice inverse:
    >>> salut = 'salutare, lume\n'
    >>> salutări = repr(salut)
    >>> print(salutări)
    'salutare, lume\n'
    >>> # Argumentul lui repr() poate fi orice obiect Python:
    >>> repr((x, y, ('carne presată', 'ouă')))
    "(32.5, 40000, ('carne presată', 'ouă'))"

Modulul `string` conține o clasă `Template` care oferă încă o metodă de substituire a valorilor în șirurile de caractere, pe baza unor substitute de forma `$x` ce vor fi înlocuite cu valori preluate dintr-un dicționar, însă care furnizează mult mai puțin control asupra formatării.

### 7.1.1. Șiruri de caractere literale formatate

Șirurile de caractere literale formatate (supranumite, pe scurt, f-șiruri) ne permit să introducem valoarea unei expresii Python în interiorul unui șir de caractere prefixând șirul cu `f` sau `F` și scriind expresia în cauză drept `{expresia}`.

Un specificator de format opțional îi poate urma expresiei. Prezența lui oferă un control sporit asupra modulului în care valoarea expresiei este formatată. Exemplul dat în continuare prezintă rotunjirea lui pi la trei cifre după virgulă (punct):

    >>> import math
    >>> print(f'Valoarea lui pi este de aproximativ {math.pi:.3f}.')
    Valoarea lui pi este de aproximativ 3.142.

Inserarea unui număr întreg imediat după semnul `':'` va avea ca efect printarea unui câmp lat de minim tot atâta caractere cât este valoarea inserată. O atare proprietate se dovedește utilă la alinierea coloanelor într-o afișare.

    >>> tabel = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 7678}
    >>> for nume, telefon in tabel.items():
    ...     print(f'{nume:10} ==> {telefon:10d}')
    ...
    Sjoerd     ==>       4127
    Jack       ==>       4098
    Dcab       ==>       7678

Alți modificatori pot fi întrebuințați la conversia unei valori înainte de formatare. Astfel, `'!a'` îi aplică valorii funcția `ascii()`, `'!s'` o aplică pe `str()` iar `'!r'` pe `repr()`:

    >>> animale = 'țipari'
    >>> print(f'Barca mea pe pernă de aer e plină de {animale}.')
    Barca mea pe pernă de aer e plină de țipari.
    >>> print(f'Barca mea pe pernă de aer e plină de {animale!r}.')
    Barca mea pe pernă de aer e plină de 'țipari'.

The `=` specifier can be used to expand an expression to the text of the expression, an equal sign, then the representation of the evaluated expression:

    >>> bugs = 'roaches'
    >>> count = 13
    >>> area = 'living room'
    >>> print(f'Debugging {bugs=} {count=} {area=}')
    Debugging bugs='roaches' count=13 area='living room'

A se vedea expresii auto-documentate pentru mai multe informații privind specificatorul `=`. Pentru o descriere cuprinzătoare a tuturor acestor specificații de format, consultați ghidul de referință despre Mini-limbajul specificației de format.

### 7.1.2. Metoda format() a tipului șir de caractere

Utilizarea de bază a metodei `str.format()` se face astfel – apelând, ca de obicei, la o scenetă Monty Python:

    >>> print('Noi suntem {} care strigă "{}!"'.format('bravii', 'Bau'))
    Noi suntem bravii care strigă "Bau!"

Acoladele și caracterele încadrate de ele (care se numesc câmpuri de format) vor fi înlocuite de obiectele transmise metodei `str.format()`. Un număr trecut între acolade poate fi utilizat ca referire la poziția obiectului ce trebuie transmis metodei `str.format()`.

    >>> print('{0} și {1}'.format('șuncă presată', 'ouă'))
    șuncă presată și ouă
    >>> print('{1} și {0}'.format('șuncă presată', 'ouă'))
    ouă și șuncă presată

Dacă vom întrebuința argumente cuvânt-cheie la apelul metodei `str.format()`, atunci ne vom referi la valorile acestora prin intermediul numelor argumentelor respective.

    >>> print('Această {aliment} este {nume_predicativ}.'.format(
    ...       aliment='șuncă presată', nume_predicativ='absolut îngrozitoare'))
    Această șuncă presată este absolut îngrozitoare.

Argumentele poziționale și cele cuvânt-cheie pot fi combinate în mod arbitrar:

    >>> print('Povestea lui {0}, {1} și {altul}.'.format('Bill', 'Manfred',
    ...                                                    altul='Georg'))
    Povestea lui Bill, Manfred și Georg.

În caz că aveți de manevrat un șir de format realmente lung și țineți neapărat să nu-l partiționați, ar fi util dacă v-ați putea referi la variabilele care trebuie formatate nu cu numărul – indicele poziției – ci cu numele. O atare rezolvare se obține transmițând, pur și simplu, un dicționar de date și folosind parantezele pătrate `'[]'` pentru a-i accesa cheile.

    >>> tabel = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 8637678}
    >>> print('Jack: {0[Jack]:d}; Sjoerd: {0[Sjoerd]:d}; '
    ...       'Dcab: {0[Dcab]:d}'.format(tabel))
    Jack: 4098; Sjoerd: 4127; Dcab: 8637678

Același rezultat poate fi obținut transmițând dicționarul de date `tabel` ca pe un argument cuvânt-cheie dat în notația `**`.

    >>> tabel = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 8637678}
    >>> print('Jack: {Jack:d}; Sjoerd: {Sjoerd:d}; Dcab: {Dcab:d}'.format(**tabel))
    Jack: 4098; Sjoerd: 4127; Dcab: 8637678

Procedeul este extrem de folositor în combinație cu funcția predefinită `vars()`, care returnează un dicționar de date cu toate variabilele locale:

    >>> tabel = {k: str(v) for k, v in vars().items()}
    >>> mesaj = " ".join([f'{k}: ' + '{' + k +'};' for k in tabel.keys()])
    >>> print(mesaj.format(**tabel))
    __name__: __main__; __doc__: None; __package__: None; __loader__: ...

Ca exemplu, liniile de cod următoare produc un set de coloane aliniate compact care afișează numere întregi împreună cu pătratele și cuburile lor:

    >>> for x in range(1, 11):
    ...     print('{0:2d} {1:3d} {2:4d}'.format(x, x*x, x*x*x))
    ...
     1   1    1
     2   4    8
     3   9   27
     4  16   64
     5  25  125
     6  36  216
     7  49  343
     8  64  512
     9  81  729
    10 100 1000

Pentru o dare de seamă elaborată asupra formatării șirurilor de caractere folosind `str.format()`, a se vedea Sintaxa șirurilor de format.

### 7.1.3. Formatare manuală a șirurilor de caractere

Iată același tabel de pătrate și cuburi de numere întregi, însă formatat manual:

    >>> for x in range(1, 11):
    ...     print(repr(x).rjust(2), repr(x*x).rjust(3), end=' ')
    ...     # Remarcați folosirea lui 'end' pe linia anterioară
    ...     print(repr(x*x*x).rjust(4))
    ...
     1   1    1
     2   4    8
     3   9   27
     4  16   64
     5  25  125
     6  36  216
     7  49  343
     8  64  512
     9  81  729
    10 100 1000

(Luați în considerare faptul că un spațiu gol, între două coloane consecutive, i se datorează modului de funcționare al funcției `print()`: aceasta adaugă întotdeauna spații goale între argumentele sale.)

Metoda `str.rjust()` a obiectelor șir de caractere aliniază la dreapta un șir într-un câmp de lățime dată inserând spații goale în stânga șirului. Python-ul dispune de încă două metode similare, și anume `str.ljust()`, respectiv `str.center()`. Ele nu inserează nimic (în vechiul șir), doar întorc un șir nou. Dacă șirul ce trebuie manipulat este prea lung, aceste metode nu-l vor trunchia, ci îl vor returna nemodificat; deși un asemenea comportament vă va afecta dpdv. estetic macheta coloanelor, alternativa ar fi mult mai rea, ea presupunând modificări de valori. (Dacă doriți, cu adevărat, o trunchiere a șirului manipulat, atunci puteți apela la operațiile de tranșare, cum ar fi `x.ljust(n)[:n]`.)

Mai există o metodă, `str.zfill()`, care completează la stânga, cu zerouri, șirurile de numere. Are capacitatea de a distinge cifrele de semnele plus și minus:

    >>> '12'.zfill(5)
    '00012'
    >>> '-3.14'.zfill(7)
    '-003.14'
    >>> '3.14159265359'.zfill(5)
    '3.14159265359'

### 7.1.4. Vechiul stil de formatare al șirurilor de caractere

Operatorul % (modulo) poate fi întrebuințat și la formatarea șirurilor de caractere. Fiind dată expresia `formatul % valorile` (unde formatul desemnează un șir de caractere), specificațiile conversiei `%` care sunt scrise în formatul vor fi înlocuite cu zero sau mai multe elemente din valorile. Această operație este cunoscută sub numele de interpolarea șirurilor (de caractere). De exemplu:

    >>> import math
    >>> print('Valoarea lui pi este aproximativ %5.3f.' % math.pi)
    Valoarea lui pi este aproximativ 3.142.

Mai multe informații se găsesc în secțiunea Formatarea șirurilor de caractere în vechiul stil printf.

## 7.2. Citirea și scrierea fișierelor

`open()` returnează un obiect fișier și este utilizată de obicei cu două argumente poziționale și un argument cuvânt-cheie: `open(nume_de_fișier, mod_de_deschidere, encoding=None)`

    >>> f = open('fișier_șantier', 'w', encoding="utf-8")

Primul argument este un șir de caractere desemnând numele fișierului pe care dorim să-l deschidem. Cel de-al doilea argument este tot un șir de caractere, foarte scurt, ce descrie felul în care vom folosi fișierul. mod_de_deschidere va fi `'r'` dacă dorim doar să citim fișierul, `'w'` dacă ne interesează numai să scriem în el (în caz că există fișierul omonim, acesta va fi șters), respectiv `'a'` pentru adăugare la sfârșitul fișierului. `'r+'` va deschide fișierul atât pentru citit cât și pentru scris. Argumentul mod_de_deschidere este opțional; dacă nu-l precizăm, atunci el va fi considerat `'r'`.

De obicei, fișierele se deschid în modul text, ceea ce înseamnă că puteți citi șiruri de caractere din ele, respectiv scrie șiruri de caractere în ele, șiruri care sunt codificate (de la englezescul encoding) conform unei codificări anumite. Atunci când codificarea nu este precizată, codificarea implicită va depinde de platforma de calcul (vedeți `open()`). Dat fiind că UTF-8 constituie, în zilele noastre, standardul de facto în domeniu, este recomandat să folosiți `encoding="utf-8"` dacă nu aveți, realmente, nevoie de vreo codificare specială. Adăugând sufixul `'b'` la modul de deschidere, fișierul în cauză va fi deschis în modul binar. Datele accesate în modul binar sunt citite și scrise sub formă de obiecte `octeți`. Nu vi se permite să specificați care este codificarea dacă deschideți fișierul în modul binar.

Atunci când manevrăm fișierul în modul text, la citire din el, caracterele care marchează sfârșitul de rând se vor transforma implicit din caractere sfârșit de rând specifice platformei de calcul (adică, din `\n` în Unix, respectiv din `\r\n` în Windows) în caracterul `\n`. Invers, la scrierea în fișier, toate aparițiile lui `\n` vor deveni implicit caracterele de sfârșit de rând specifice platformei pe care lucrăm. Deși o astfel de modificare sub capotă (de la englezescul behind-the-scenes) este convenabilă atunci când avem de a face cu fișiere text, ea va corupe datele binare precum cele dintr-un fișier `JPEG` ori `EXE`. Aveți mare grijă să folosiți modul binar atunci când fie citiți din asemenea fișiere fie scrieți în ele.

O bună practică ne este la îndemână prin intermediul cuvântului-cheie `with`, de întrebuințat dacă manevrăm obiecte fișier. Avantajul său constă în aceea că fișierul va fi întotdeauna închis corect la finalul execuției expresiei acestui construct, și aceasta chiar dacă a fost ridicată vreo excepție pe parcurs. În plus, folosirea lui `with` scurtează semnificativ codul care ar trebui scris dacă folosim constructul echivalent dat de blocurile `try`-`finally`:

    >>> with open('fișier_șantier', encoding="utf-8") as f:
    ...     citește_datele = f.read()

    >>> # Putem verifica dacă fișierul a fost închis automat.
    >>> f.closed
    True

În caz că nu utilizați cuvântul cheie `with`, atunci va trebui să apelați metoda `f.close()` pentru a închide fișierul și a elibera de îndată eventualele resurse ale sistemului pe care manevrarea fișierului le-a blocat.

Atenționare

Apelul lui `f.write()` fie fără să folosim cuvântul cheie `with` fie fără să-l însoțim de apelul lui `f.close()` poate avea drept consecință o scriere incompletă a argumentelor lui `f.write()` pe disc, și aceasta chiar dacă programul se va încheia corect.

După ce un obiect fișier a fost închis, fie printr-o instrucție `with` fie prin apelul metodei `f.close()`, orice încercare de a-l întrebuința va fi sortită eșecului.

    >>> f.close()
    >>> f.read()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    ValueError: I/O operation on closed file.

### 7.2.1. Metodele obiectelor fișier

Restul exemplelor din această secțiune presupune că un obiect fișier pe nume `f` a fost deja creat.

Ca să citiți conținutul unui fișier, apelați `f.read(cantitate)`, instrucțiune care citește o anumită cantitate de date și o returnează sub formă de șir de caractere (în modul text) sau sub forma unui obiect bytes (în modul binar). cantitate este un argument numeric opțional. Atunci când cantitate fie este omis fie este număr negativ, întregul conținut al fișierului va fi citit și apoi returnat; treaba dumneavoastră dacă fișierul în cauză se dovedește a fi de două ori mai mare ca memoria mașinii de calcul. Altfel, cel mult un număr de cantitate de caractere (în modul text) vor fi citite și returnate, respectiv un număr de cantitate de biți (în modul binar) vor fi citiți și returnați. Atunci când se va ajunge la finalul fișierului, `f.read()` va întoarce un șir gol (`''`).

    >>> f.read()
    'Acesta este întregul fișier.\n'
    >>> f.read()
    ''

`f.readline()` citește un singur rând din fișier; caracterul linie-nouă (`\n`) este păstrat la sfârșitul șirului de caractere citit, el fiind omis numai la ultimul rând al fișierului, atunci când fișierul nu se încheie cu o linie nouă (în englezește, ca jargon, newline). Procedeul în cauză face ca valoarea returnată să fie lipsită de ambiguitate; căci, dacă `f.readline()` returnează un șir gol înseamnă că am ajuns la finalul fișierului, în timp ce o linie goală (dintre paragrafe) va fi reprezentată de un `'\n'`, adică de un șir conținând numai un singur caracter, cel de linie nouă.

    >>> f.readline()
    'Acesta este primul rând al fișierului.\n'
    >>> f.readline()
    'Al doilea rând al fișierului\n'
    >>> f.readline()
    ''

Pentru a citi mai multe linii din fișier, puteți itera de-a lungul obiectului fișier. O atare procedură este eficientă dpdv. al consumului de memorie, este rapidă și se bazează pe un cod Python simplu:

    >>> for rând in f:
    ...     print(rând, end='')
    ...
    Acesta este primul rând al fișierului.
    Al doilea rând al fișierului

Dacă vă interesează să plasați toate rândurile unui fișier într-o listă, atunci ați putea folosi `list(f)` sau `f.readlines()`.

`f.write(șir_de_caractere)` scrie conținutul lui șir_de_caractere în fișier, returnând numărul de caractere scrise.

    >>> f.write('Acesta e un test\n')
    17

Obiectele de alt tip trebuie convertite mai întâi – fie la șiruri de caractere (în modul text) fie la obiecte bytes (în modul binar) – înainte de scrierea în fișier:

    >>> valoarea = ('răspunsul', 42)
    >>> s = str(valoarea)  # convertește tuplul în șir de caractere
    >>> f.write(s)
    17

`f.tell()` returnează un număr întreg care fie indică poziția curentă în obiectul fișier precizând la câți octeți ne găsim față de începutul fișierului, atunci când fișierul a fost deschis în modul binar, fie este o valoare opacă, atunci când fișierul a fost deschis în modul text.

Pentru a schimba poziția (cursorului) în obiectul fișier, întrebuințați metoda `f.seek(deplasament, sursă)`. Poziția se calculează adunând acest deplasament la punctul de referință; punctul de referință este precizat prin argumentul sursă. Valoarea 0 a lui sursă înseamnă că ne vom raporta la începutul fișierului, valoarea 1 se referă la poziția curentă în fișier, iar valoarea 2 implică folosirea finalului de fișier pe post de punct de referință.

    >>> f = open('fișier_șantier', 'rb+')
    >>> f.write(b'0123456789abcdef')
    16
    >>> f.seek(5)      # Mergi la cel de-al 6-lea octet din fișier
    5
    >>> f.read(1)
    b'5'
    >>>                # Mergi la octetul situat cu 3 poziții (octeți)
    >>>                # înaintea finalului
    >>> f.seek(-3, 2)
    13
    >>> f.read(1)
    b'd'

În fișierele text (adică, fișierele deschise fără să se utilizeze niciun `b` în șirul de caractere al modului de deschidere) sunt permise doar poziționările raportate la începutul fișierului (singura excepție fiind cea dată de poziționarea, folosind `seek(0, 2)`, chiar la finalul fișierului), iar valorile corecte pentru deplasament sunt numerele returnate de `f.tell()`, respectiv zero. Orice alt deplasament va cauza comportamente impredictibile.

Fișierele obiect posedă diverse alte metode, precum `isatty()` și `truncate()` care sunt mai rar întâlnite; consultați Referința bibliotecii pentru ghidul cuprinzător al obiectelor fișier.

### 7.2.2. Salvarea structurilor de date cu `json`

Șirurile de caractere se scriu ușor într-un fișier și se citesc (la fel de) ușor dintr-un fișier. Numerele presupun un efort suplimentar, dat fiind că metoda `read()` returnează doar șiruri de caractere, iar acestea din urmă trebuie transmise unei funcții precum `int()`, care funcție preia un șir ca `'123'` și întoarce valoarea sa numerică, adică pe 123. Atunci când vă interesează să salvați date de diverse tipuri mai sofisticate decât șirurile ori numerele, cum ar fi listele imbricate ori dicționarele de date, parsarea manuală și serializarea de mână devin niște sarcini complicate.

Ca să nu-i silească pe utilizatori să-și consume timpul scriind și corectând cod specializat în salvarea în fișiere a tipurilor complicate de date, Python-ul le permite acestora să întrebuințeze popularul format de (inter)schimb de date numit JSON (Notația obiectelor JavaScript). Modulul predefinit `json` preia date Python ierarhizate și le convertește în reprezentări sub formă de șiruri de caractere; un atare proces este numit serializare. Invers, reconstrucția datelor din reprezentările lor ca șiruri de caractere poartă numele de deserializare. Între o serializare și deserializarea subsecventă, șirul de caractere care reprezintă un obiect Python poate fi stocat într-un fișier sau într-un flux de date, ori transmis printr-o conexiune la rețeaua Internet către o mașină de calcul aflată la distanță.

Notă

Formatul JSON este utilizat frecvent de aplicațiile moderne care permit schimburi de date. Mulți programatori sunt deja familiarizați cu el, ceea ce îl face o alegere potrivită atunci când ne interesează interoperabilitatea.

Dacă aveți la îndemână un obiect Python `x`, atunci vă ajunge o singură linie de cod ca să-i vedeți reprezentarea JSON sub formă de șir de caractere:

    >>> import json
    >>> x = [1, 'banală', 'listă']
    >>> json.dumps(x)
    '[1, "banală", "listă"]'

O variantă a funcției `dumps()`, intitulată `dump()`, serializează de-a dreptul obiectul Python într-un fișier text. Așadar, dacă `f` este un obiect fișier text deschis pentru scriere, putem proceda astfel:

    json.dump(x, f)

Ca redecodificăm obiectul, presupunând că `f` este fie un obiect fișier binar fie un obiect fișier text care a fost deja deschis pentru citire, executăm:

    x = json.load(f)

Notă

Fișierele JSON trebuie să fie codificate UTF-8. Folosiți `encoding="utf-8"` atunci când deschideți un fișier JSON ca fișier text atât pentru citire cât și pentru scriere.

O asemenea tehnică simpl(ist)ă de serializare se descurcă la manevrarea listelor și a dicționarelor de date, însă serializarea în JSON a unor instanțe de clase oarecare necesită un anume efort. Referința la modulul `json` din documentație explică de ce.

Vezi și

`pickle` - modulul pickle

Spre deosebire de JSON, pickle (adică, muratul sau punerea la murat) desemnează un protocol capabil să serializeze obiecte Python oricât de complicate. Din care motiv, îi este tipic (doar) Python-ului și nu poate fi utilizat la comunicarea cu aplicații scrise în alte limbaje de programare. De asemeni, este nesigur în mod prestabilit: deserializarea unor date puse la murat pe care le-ați obținut de la o sursă dubioasă poate provoca execuții de cod despre care (să) nu știți nimic, în caz că datele au fost preparate de un atacator îndemânatic.