2. Serializacja i deserializacja CSV

2.1. Odczytywanie danych z plików CSV

Code Listing 2.1. Zapis do plików csv używając csv.DictReader()
import csv

with open('filename.csv') as file:
    data = csv.DictReader(file, delimiter=',', quotechar='"')

    for row in data:
        print(row['first_name'], row['last_name'])

2.2. Zapis do plików CSV

Code Listing 2.2. Zapis do plików csv używając csv.DictWriter()
import csv

DATA = [
    {'first_name': 'José', 'last_name': 'Jiménez'},
    {'first_name': 'Max', 'last_name': 'Peck'},
    {'first_name': 'Ivan', 'last_name': 'Ivanovic'},
]

with open('filename.csv', 'w', encoding='utf-8') as file:
    fieldnames = DATA[0].keys()
    writer = csv.DictWriter(file, fieldnames=fieldnames, delimiter=',',
                            quotechar='"', quoting=csv.QUOTE_ALL, lineterminator='\n')
    writer.writeheader()

    for row in DATA:
        writer.writerow(row)

2.3. Parsowanie innych plików za pomocą csv.DictReader()

Code Listing 2.3. Parsing /etc/passwd file with csv.DictReader()
import csv

FILENAME = r'../../../data/file-etc-passwd.txt'


with open(FILENAME) as file:
    fieldnames = ['user', 'password', 'uid', 'gid', 'name', 'home', 'shell']
    data = csv.DictReader(file, fieldnames=fieldnames, delimiter=':')

    for row in data:
        print(row)

# OrderedDict([('user', '# User Database'), ('password', None), ('uid', None), ('gid', None), ('name', None), ('home', None), ('shell', None)])

# OrderedDict([('user', 'jimenez'), ('password', 'x'), ('uid', '1001'), ('gid', '1001'), ('name', 'Jose Jimenez'), ('home', '/home/jimenez'), ('shell', '/bin/bash')])

# OrderedDict([('user', 'ivanovic'), ('password', 'x'), ('uid', '1002'), ('gid', '1002'), ('name', 'Ivan Ivanovic'), ('home', '/home/ivanovic'), ('shell', '/bin/bash')])

2.4. Zadania Kontrolne

2.4.1. Wczytywanie pliku csv

  1. ściągnij plik z URL podanego powyżej i zapisz na dysku w miejscu gdzie masz skrypty
  2. Wczytaj dane z pliku csv
  3. Pierwsza linijka stanowi header

2.4.2. Serializacja csv

  • Za pomocą csv.DictWriter() zapisz do pliku dane o zmiennej strukturze.
  • fieldnames nie może być zahardkodowane w skrypcie.
DATA = [
    {'last_name': 'Jiménez'},
    {'first_name': 'Max', 'last_name': 'Peck'},
    {'first_name': 'Ivan'},
    {'first_name': 'Max', 'last_name': 'Peck', 'born': 1961},
    {'first_name': 'Jose', 'born': 1961, 'first_step': 1969},
]
Podpowiedź:
  • Kod powinien mieć około 5 linii
  • To jest bardzo często występujący i użyteczny przykład
Co zadanie sprawdza?:
 
  • Umiejętność korzystania z modułu csv
  • Umiejętność iteracji po złożonych strukturach danych
  • Dynamiczne generowanie struktur danych na podstawie innych

2.4.3. Serializacja obiektów do CSV

  1. Użyj obiektu książka_adresowa z listingu Code Listing 2.4.
  2. Za pomocą csv.DictWriter() zapisz kontakty z książki adresowej w pliku
  3. Wszystkie pola muszą być zawsze w cudzysłowiach i oddzielone średnikami, kodowanie UTF-8.
  4. Jak zapisać w CSV dane relacyjne (kontakt ma wiele adresów)?
  5. Stwórz obiekty książki adresowej na podstawie danych odczytanych z pliku
Podpowiedź:
  • powtarzanie rekordów (user pozostaje ten sam) z innymi danymi adresowymi
  • dodawanie kolumn (ulica_1, miasto_1, panstwo_1, ulica_2, miasto_2, panstwo_2) i automatyczne generowanie fieldnames
  • wrzucenie danych jako string do jednego pola adres_1, adres_2, adres_3 i ustalenie separatora (np: średnik - ‘;’)
  • jedno pole adres (w ramach niego wszystkie adresy rozdzielone “;” a dane przecinkami “,”)
Code Listing 2.4. Address book
class Kontakt:
    def __init__(self, imie, nazwisko, adresy=[]):
        self.imie = imie
        self.nazwisko = nazwisko
        self.adresy = adresy


class Adres:
    def __init__(self, **kwargs):
        for key, value in kwargs.items():
            setattr(self, key, value)


ksiazka_adresowa = [
    Kontakt(imie='Max', nazwisko='Peck', adresy=[
        Adres(ulica='2101 E NASA Pkwy', miasto='Houston', stan='Texas', kod='77058', panstwo='USA'),
        Adres(ulica=None, miasto='Kennedy Space Center', kod='32899', panstwo='USA'),
        Adres(ulica='4800 Oak Grove Dr', miasto='Pasadena', kod='91109', panstwo='USA'),
        Adres(ulica='2825 E Ave P', miasto='Palmdale', stan='California', kod='93550', panstwo='USA', data_urodzenia=None),
    ]),
    Kontakt(imie='José', nazwisko='Jiménez'),
    Kontakt(imie='Иван', nazwisko='Иванович', adresy=[]),
]