12.3. Serialization Load

  • loads(str) -> object

  • load(file) -> object

12.3.1. Sequence

>>> DATA = 'Alice,Apricot,30'
>>>
>>> def loads(data, fieldseparator=','):
...     return tuple(data.split(fieldseparator))
>>>
>>>
>>> loads(DATA)
('Alice', 'Apricot', '30')

12.3.2. Mapping

>>> DATA = 'firstname,lastname,age;Alice,Apricot,30'
>>>
>>> def loads(data, fieldseparator=',', recordseparator=';'):
...     records = data.split(recordseparator)
...     header, row = [row.split(fieldseparator) for row in records]
...     return dict(zip(header,row))
>>>
>>>
>>> loads(DATA)
{'firstname': 'Alice', 'lastname': 'Apricot', 'age': '30'}

12.3.3. List of Sequence

>>> DATA = 'firstname,lastname,age;Alice,Apricot,30;Bob,Banana,31;Carol,Corn,32;Dave,Durian,33;Eve,Elderberry,34;Mallory,Melon,15'
>>>
>>> def loads(data, fieldseparator=',', recordseparator=';'):
...     rows = data.split(recordseparator)
...     return [tuple(row.split(fieldseparator)) for row in rows]
>>>
>>>
>>> loads(DATA)
[('firstname', 'lastname', 'age'),
 ('Alice', 'Apricot', '30'),
 ('Bob', 'Banana', '31'),
 ('Carol', 'Corn', '32'),
 ('Dave', 'Durian', '33'),
 ('Eve', 'Elderberry', '34'),
 ('Mallory', 'Melon', '15')]

12.3.4. List of Mappings

>>> DATA = 'age,firstname,lastname;30,Alice,Apricot;31,Bob,Banana;32,Carol,Corn;33,Dave,Durian;34,Eve,Elderberry;15,Mallory,Melon'
>>>
>>> def loads(data, fieldseparator=',', recordseparator=';'):
...     records = data.split(recordseparator)
...     header, *rows = [row.split(fieldseparator) for row in records]
...     return [dict(zip(header,row)) for row in rows]
>>>
>>>
>>> loads(DATA)
[{'age': '30', 'firstname': 'Alice', 'lastname': 'Apricot'},
 {'age': '31', 'firstname': 'Bob', 'lastname': 'Banana'},
 {'age': '32', 'firstname': 'Carol', 'lastname': 'Corn'},
 {'age': '33', 'firstname': 'Dave', 'lastname': 'Durian'},
 {'age': '34', 'firstname': 'Eve', 'lastname': 'Elderberry'},
 {'age': '15', 'firstname': 'Mallory', 'lastname': 'Melon'}]

12.3.5. List of Objects

>>> DATA = 'age,firstname,lastname;30,Alice,Apricot;31,Bob,Banana;32,Carol,Corn;33,Dave,Durian;34,Eve,Elderberry;15,Mallory,Melon'
>>>
>>> class User:
...     def __init__(self, firstname, lastname, age):
...         self.firstname = firstname
...         self.lastname = lastname
...         self.age = age
...
...     def __repr__(self):
...         clsname = self.__class__.__name__
...         firstname = self.firstname
...         lastname = self.lastname
...         age = self.age
...         return f'{clsname}({firstname=}, {lastname=}, {age=})'
>>>
>>>
>>> def loads(data, fieldseparator=',', recordseparator=';'):
...     records = data.split(recordseparator)
...     header, *rows = [row.split(fieldseparator) for row in records]
...     return [User(**dict(zip(header,row))) for row in rows]
>>>
>>>
>>> loads(DATA)
[User(firstname='Alice', lastname='Apricot', age='30'),
 User(firstname='Bob', lastname='Banana', age='31'),
 User(firstname='Carol', lastname='Corn', age='32'),
 User(firstname='Dave', lastname='Durian', age='33'),
 User(firstname='Eve', lastname='Elderberry', age='34'),
 User(firstname='Mallory', lastname='Melon', age='15')]

12.3.6. From File

SetUp:

>>> with open('/tmp/myfile.txt', mode='wt') as file:
...     file.write('Alice,Apricot,25\n')
17

Solution:

>>> with open('/tmp/myfile.txt', mode='rt') as file:
...     content = file.read()
>>>
>>> firstname, lastname, age = content.strip().split(',')
>>> result = [firstname, lastname, int(age)]
>>> result
['Alice', 'Apricot', 25]

12.3.7. Use Case - 1

SetUp:

>>> from pprint import pprint
>>>
>>> DATA = """sepal_length,sepal_width,petal_length,petal_width,species
... 5.8,2.7,5.1,1.9,virginica
... 5.1,3.5,1.4,0.2,setosa
... 5.7,2.8,4.1,1.3,versicolor
... 6.3,2.9,5.6,1.8,virginica
... 6.4,3.2,4.5,1.5,versicolor
... 4.7,3.2,1.3,0.2,setosa
... 7.0,3.2,4.7,1.4,versicolor
... 7.6,3.0,6.6,2.1,virginica
... 4.6,3.1,1.5,0.2,setosa"""

Usage:

>>> def loads(data):
...     header, *lines = data.splitlines()
...     header = tuple(header.split(','))
...     rows = []
...     for line in lines:
...         *values, species = line.strip().split(',')
...         values = [float(x) for x in values]
...         row = tuple(values) + (species,)
...         rows.append(row)
...     return [header] + rows
>>>
>>> result = loads(DATA)
>>>
>>> pprint(result)
[('sepal_length', 'sepal_width', 'petal_length', 'petal_width', 'species'),
 (5.8, 2.7, 5.1, 1.9, 'virginica'),
 (5.1, 3.5, 1.4, 0.2, 'setosa'),
 (5.7, 2.8, 4.1, 1.3, 'versicolor'),
 (6.3, 2.9, 5.6, 1.8, 'virginica'),
 (6.4, 3.2, 4.5, 1.5, 'versicolor'),
 (4.7, 3.2, 1.3, 0.2, 'setosa'),
 (7.0, 3.2, 4.7, 1.4, 'versicolor'),
 (7.6, 3.0, 6.6, 2.1, 'virginica'),
 (4.6, 3.1, 1.5, 0.2, 'setosa')]

12.3.8. Use Case - 2

>>> from pprint import pprint
>>>
>>> class User:
...     def __init__(self, firstname, lastname):
...         self.firstname = firstname
...         self.lastname = lastname
...
...     def __repr__(self):
...         firstname = self.firstname
...         lastname = self.lastname
...         return f'User({firstname=}, {lastname=})'
>>>
>>>
>>> DATA = 'Alice,Apricot\n'

Usage:

>>> def loads(data):
...     values = data.strip().split(',')
...     result = User(*values)
...     return result
>>>
>>>
>>> result = loads(DATA)
>>> pprint(result)
User(firstname='Alice', lastname='Apricot')

12.3.9. Use Case - 3

SetUp:

>>> from pprint import pprint
>>>
>>> class User:
...     def __init__(self, firstname, lastname):
...         self.firstname = firstname
...         self.lastname = lastname
...
...     def __repr__(self):
...         firstname = self.firstname
...         lastname = self.lastname
...         return f'User({firstname=}, {lastname=})'
>>>
>>>
>>> DATA = 'Alice,Apricot\nBob,Banana\nCarol,Corn\n'

Usage:

>>> def loads(data):
...     records = data.splitlines()
...     result = []
...     for record in records:
...         values = record.strip().split(',')
...         user = User(*values)
...         result.append(user)
...     return result
>>>
>>>
>>> result = loads(DATA)
>>>
>>> pprint(result)
[User(firstname='Alice', lastname='Apricot'),
 User(firstname='Bob', lastname='Banana'),
 User(firstname='Carol', lastname='Corn')]

12.3.10. Use Case - 4

>>> from pprint import pprint
>>>
>>> DATA = """sepal_length,sepal_width,petal_length,petal_width,species
... 5.8,2.7,5.1,1.9,virginica
... 5.1,3.5,1.4,0.2,setosa
... 5.7,2.8,4.1,1.3,versicolor
... 6.3,2.9,5.6,1.8,virginica
... 6.4,3.2,4.5,1.5,versicolor
... 4.7,3.2,1.3,0.2,setosa
... 7.0,3.2,4.7,1.4,versicolor
... 7.6,3.0,6.6,2.1,virginica
... 4.6,3.1,1.5,0.2,setosa"""
>>>
>>> with open('/tmp/myfile.csv', mode='wt') as file:
...     file.write(DATA)
285

Solution:

>>> def load(filename):
...     with open(filename, mode='rt') as file:
...         data = file.read()
...     header, *lines = data.strip().splitlines()
...     header = tuple(header.split(','))
...     rows = []
...     for line in lines:
...         *values, species = line.split(',')
...         values = map(float, values)
...         row = tuple(values) + (species,)
...         rows.append(row)
...     return [header] + rows

Result:

>>> result = load('/tmp/myfile.csv')
>>> pprint(result)
[('sepal_length', 'sepal_width', 'petal_length', 'petal_width', 'species'),
 (5.8, 2.7, 5.1, 1.9, 'virginica'),
 (5.1, 3.5, 1.4, 0.2, 'setosa'),
 (5.7, 2.8, 4.1, 1.3, 'versicolor'),
 (6.3, 2.9, 5.6, 1.8, 'virginica'),
 (6.4, 3.2, 4.5, 1.5, 'versicolor'),
 (4.7, 3.2, 1.3, 0.2, 'setosa'),
 (7.0, 3.2, 4.7, 1.4, 'versicolor'),
 (7.6, 3.0, 6.6, 2.1, 'virginica'),
 (4.6, 3.1, 1.5, 0.2, 'setosa')]

12.3.11. Assignments

# %% About
# - Name: Serialization Loads Sequence
# - Difficulty: easy
# - Lines: 3
# - Minutes: 5

# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author

# %% English
# 1. Define function `loads()`, which deserialize Sequence:
#    - Argument: `data: str`
#    - Returns: `tuple`
# 2. Define `result: tuple` with result of `dumps()` function for `DATA`
# 3. Non-functional requirements:
#    - Do not use `import` and any module
#    - Do not convert numbers to `int` or `float`, leave them as `str`
#    - Quoting: none
#    - Delimiter: `,`
#    - Lineseparator: `;`
# 4. Run doctests - all must succeed

# %% Polish
# 1. Zdefiniuj funkcję `loads()`, która deserializuje Sequence:
#    - Argument: `data: str`
#    - Zwraca: `tuple`
# 2. Zdefiniuj `result: tuple` z wynikiem funkcji `dumps()` dla `DATA`
# 3. Wymagania niefunkcjonalne:
#    - Nie używaj `import` ani żadnych modułów
#    - Nie konwertuj liczb do `int` lub `float`, pozostaw je jako `str`
#    - Quoting: żadne
#    - Delimiter: `,`
#    - Lineseparator: `;`
# 4. Uruchom doctesty - wszystkie muszą się powieść

# %% Example
# >>> result
# ('Alice', 'Apricot', '30')

# %% Hints
# - `tuple()`
# - `str.split()`

# %% Doctests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 12), \
'Python 3.12+ required'

>>> assert result is not Ellipsis, \
'Assign result to variable: `result`'
>>> assert type(result) is tuple, \
'Variable `result` has invalid type, should be tuple'

>>> from pprint import pprint
>>> pprint(result, sort_dicts=False, width=79)
('Alice', 'Apricot', '30')
"""

# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`

# %% Imports

# %% Types
from typing import Callable
type data = tuple[str,...]
loads: Callable[[str,...], data]
result: data

# %% Data
DATA = 'Alice,Apricot,30'

# %% Result
result = ...

# %% About
# - Name: Serialization Loads Mapping
# - Difficulty: easy
# - Lines: 5
# - Minutes: 5

# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author

# %% English
# 1. Define function `loads()`, which deserialize Mapping:
#    - Argument: `data: str`
#    - Returns: `dict[str,str]`
# 2. Define `result: dict` with result of `dumps()` function for `DATA`
# 3. Non-functional requirements:
#    - Do not use `import` and any module
#    - Do not convert numbers to `int` or `float`, leave them as `str`
#    - Quoting: none
#    - Delimiter: `,`
#    - Lineseparator: `;`
# 4. Run doctests - all must succeed

# %% Polish
# 1. Zdefiniuj funkcję `loads()`, która deserializuje Mapping:
#    - Argument: `data: str`
#    - Zwraca: `dict[str,str]`
# 2. Zdefiniuj `result: dict` z wynikiem funkcji `dumps()` dla `DATA`
# 3. Wymagania niefunkcjonalne:
#    - Nie używaj `import` ani żadnych modułów
#    - Nie konwertuj liczb do `int` lub `float`, pozostaw je jako `str`
#    - Quoting: żadne
#    - Delimiter: `,`
#    - Lineseparator: `;`
# 4. Uruchom doctesty - wszystkie muszą się powieść

# %% Example
# >>> result
# {'firstname': 'Alice', 'lastname': 'Apricot', 'age': '30'}

# %% Hints
# - `str.split()`
# - `[x for x in data]`
# - `dict()`
# - `zip()`
# - `first, second = 1, 2`

# %% Doctests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 12), \
'Python 3.12+ required'

>>> assert result is not Ellipsis, \
'Assign result to variable: `result`'
>>> assert type(result) is dict, \
'Variable `result` has invalid type, should be dict'

>>> from pprint import pprint
>>> pprint(result, sort_dicts=False, width=79)
{'firstname': 'Alice', 'lastname': 'Apricot', 'age': '30'}
"""

# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`

# %% Imports

# %% Types
from typing import Callable
type data = dict[str,str]
loads: Callable[[str,...], data]
result: data

# %% Data
DATA = 'firstname,lastname,age;Alice,Apricot,30'

# %% Result
result = ...

# %% About
# - Name: Serialization Loads ListSequence
# - Difficulty: easy
# - Lines: 4
# - Minutes: 5

# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author

# %% English
# 1. Define function `loads()`, which deserialize list[Sequence]:
#    - Argument: `data: str`
#    - Returns: `list[tuple]`
# 2. Define `result: list[tuple]` with result of `dumps()` function for `DATA`
# 3. Non-functional requirements:
#    - Do not use `import` and any module
#    - Do not convert numbers to `int` or `float`, leave them as `str`
#    - Quoting: none
#    - Delimiter: `,`
#    - Lineseparator: `;`
# 4. Run doctests - all must succeed

# %% Polish
# 1. Zdefiniuj funkcję `loads()`, która deserializuje list[Sequence]:
#    - Argument: `data: str`
#    - Zwraca: `list[tuple]`
# 2. Zdefiniuj `result: list[tuple]` z wynikiem funkcji `dumps()` dla `DATA`
# 3. Wymagania niefunkcjonalne:
#    - Nie używaj `import` ani żadnych modułów
#    - Nie konwertuj liczb do `int` lub `float`, pozostaw je jako `str`
#    - Quoting: żadne
#    - Delimiter: `,`
#    - Lineseparator: `;`
# 4. Uruchom doctesty - wszystkie muszą się powieść

# %% Example
# >>> result
# [('firstname', 'lastname', 'age'),
#  ('Alice', 'Apricot', '30'),
#  ('Bob', 'Banana', '31'),
#  ('Carol', 'Corn', '32'),
#  ('Dave', 'Durian', '33'),
#  ('Eve', 'Elderberry', '34'),
#  ('Mallory', 'Melon', '15')]

# %% Hints
# - `tuple()`
# - `str.split()`
# - `[x for x in data]`

# %% Doctests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 12), \
'Python 3.12+ required'

>>> assert result is not Ellipsis, \
'Assign result to variable: `result`'
>>> assert type(result) is list, \
'Variable `result` has invalid type, should be list'
>>> assert all(type(x) is tuple for x in result), \
'All rows in `result` should be tuple'

>>> from pprint import pprint
>>> pprint(result, sort_dicts=False, width=79)
[('firstname', 'lastname', 'age'),
 ('Alice', 'Apricot', '30'),
 ('Bob', 'Banana', '31'),
 ('Carol', 'Corn', '32'),
 ('Dave', 'Durian', '33'),
 ('Eve', 'Elderberry', '34'),
 ('Mallory', 'Melon', '15')]
"""

# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`

# %% Imports

# %% Types
from typing import Callable
type data = list[tuple[str,...]]
loads: Callable[[str,...], data]
result: data

# %% Data
DATA = 'firstname,lastname,age;Alice,Apricot,30;Bob,Banana,31;Carol,Corn,32;Dave,Durian,33;Eve,Elderberry,34;Mallory,Melon,15'

# %% Result
result = ...

# %% About
# - Name: Serialization Loads ListMapping
# - Difficulty: easy
# - Lines: 5
# - Minutes: 5

# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author

# %% English
# 1. Define function `loads()`, which deserialize list[Mapping]:
#    - Argument: `data: str`
#    - Returns: `list[dict]`
# 2. Define `result: list[dict]` with result of `dumps()` function for `DATA`
# 3. Non-functional requirements:
#    - Do not use `import` and any module
#    - Do not convert numbers to `int` or `float`, leave them as `str`
#    - Quoting: none
#    - Delimiter: `,`
#    - Lineseparator: `;`
# 4. Run doctests - all must succeed

# %% Polish
# 1. Zdefiniuj funkcję `loads()`, która deserializuje list[Mapping]:
#    - Argument: `data: str`
#    - Zwraca: `list[dict]`
# 2. Zdefiniuj `result: list[dict]` z wynikiem funkcji `dumps()` dla `DATA`
# 3. Wymagania niefunkcjonalne:
#    - Nie używaj `import` ani żadnych modułów
#    - Nie konwertuj liczb do `int` lub `float`, pozostaw je jako `str`
#    - Quoting: żadne
#    - Delimiter: `,`
#    - Lineseparator: `;`
# 4. Uruchom doctesty - wszystkie muszą się powieść

# %% Example
# >>> result
# [{'age': '30', 'firstname': 'Alice', 'lastname': 'Apricot'},
#  {'age': '31', 'firstname': 'Bob', 'lastname': 'Banana'},
#  {'age': '32', 'firstname': 'Carol', 'lastname': 'Corn'},
#  {'age': '33', 'firstname': 'Dave', 'lastname': 'Durian'},
#  {'age': '34', 'firstname': 'Eve', 'lastname': 'Elderberry'},
#  {'age': '15', 'firstname': 'Mallory', 'lastname': 'Melon'}]

# %% Hints
# - `str.split()`
# - `[x for x in data]`
# - `dict()`
# - `zip()`
# - `first, *others = 1, 2, 3, 4, 5`

# %% Doctests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 12), \
'Python 3.12+ required'

>>> assert result is not Ellipsis, \
'Assign result to variable: `result`'
>>> assert type(result) is list, \
'Variable `result` has invalid type, should be list'
>>> assert all(type(x) is dict for x in result), \
'All rows in `result` should be dict'

>>> from pprint import pprint
>>> pprint(result, sort_dicts=False, width=79)
[{'age': '30', 'firstname': 'Alice', 'lastname': 'Apricot'},
 {'age': '31', 'firstname': 'Bob', 'lastname': 'Banana'},
 {'age': '32', 'firstname': 'Carol', 'lastname': 'Corn'},
 {'age': '33', 'firstname': 'Dave', 'lastname': 'Durian'},
 {'age': '34', 'firstname': 'Eve', 'lastname': 'Elderberry'},
 {'age': '15', 'firstname': 'Mallory', 'lastname': 'Melon'}]
"""

# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`

# %% Imports

# %% Types
from typing import Callable
type data = list[dict[str,str]]
loads: Callable[[str,...], data]
result: data

# %% Data
DATA = 'age,firstname,lastname;30,Alice,Apricot;31,Bob,Banana;32,Carol,Corn;33,Dave,Durian;34,Eve,Elderberry;15,Mallory,Melon'

# %% Result
result = ...

# %% About
# - Name: Serialization Loads ListObject
# - Difficulty: easy
# - Lines: 5
# - Minutes: 5

# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author

# %% English
# 1. Define function `loads()`, which deserialize list[object]:
#    - Argument: `data: str`
#    - Returns: `list[object]`
# 2. Define `result: list[object]` with result of `dumps()` function for `DATA`
# 3. Non-functional requirements:
#    - Do not use `import` and any module
#    - Do not convert numbers to `int` or `float`, leave them as `str`
#    - Quoting: none
#    - Delimiter: `,`
#    - Lineseparator: `;`
# 4. Run doctests - all must succeed

# %% Polish
# 1. Zdefiniuj funkcję `loads()`, która deserializuje list[object]:
#    - Argument: `data: str`
#    - Zwraca: `list[object]`
# 2. Zdefiniuj `result: list[object]` z wynikiem funkcji `dumps()` dla `DATA`
# 3. Wymagania niefunkcjonalne:
#    - Nie używaj `import` ani żadnych modułów
#    - Nie konwertuj liczb do `int` lub `float`, pozostaw je jako `str`
#    - Quoting: żadne
#    - Delimiter: `,`
#    - Lineseparator: `;`
# 4. Uruchom doctesty - wszystkie muszą się powieść

# %% Example
# >>> result
# [User(firstname='Alice', lastname='Apricot', age='30'),
#  User(firstname='Bob', lastname='Banana', age='31'),
#  User(firstname='Carol', lastname='Corn', age='32'),
#  User(firstname='Dave', lastname='Durian', age='33'),
#  User(firstname='Eve', lastname='Elderberry', age='34'),
#  User(firstname='Mallory', lastname='Melon', age='15')]

# %% Hints
# - `[x for x in data]`
# - `tuple()`
# - `str.split()`
# - `dict()`
# - `zip()`

# %% Doctests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 12), \
'Python 3.12+ required'

>>> assert result is not Ellipsis, \
'Assign result to variable: `result`'
>>> assert type(result) is list, \
'Variable `result` has invalid type, should be list'
>>> assert all(type(x) is User for x in result), \
'All rows in `result` should be User'

>>> from pprint import pprint
>>> pprint(result, sort_dicts=False, width=79)
[User(firstname='Alice', lastname='Apricot', age='30'),
 User(firstname='Bob', lastname='Banana', age='31'),
 User(firstname='Carol', lastname='Corn', age='32'),
 User(firstname='Dave', lastname='Durian', age='33'),
 User(firstname='Eve', lastname='Elderberry', age='34'),
 User(firstname='Mallory', lastname='Melon', age='15')]
"""

# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`

# %% Imports

# %% Types
from typing import Callable
type data = list[object]
loads: Callable[[str,...], data]
result: data

# %% Data
DATA = 'age,firstname,lastname;30,Alice,Apricot;31,Bob,Banana;32,Carol,Corn;33,Dave,Durian;34,Eve,Elderberry;15,Mallory,Melon'

class User:
    def __init__(self, firstname, lastname, age):
        self.firstname = firstname
        self.lastname = lastname
        self.age = age
    def __repr__(self):
        clsname = self.__class__.__name__
        firstname = self.firstname
        lastname = self.lastname
        age = self.age
        return f'{clsname}({firstname=}, {lastname=}, {age=})'

# %% Result
result = ...

# %% About
# - Name: Serialization Loads ListObject
# - Difficulty: easy
# - Lines: 5
# - Minutes: 5

# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author

# %% English
# 1. Define function `load()`, which deserialize list[object] from file:
#    - Argument: `file: str`
#    - Returns: `data: list[dict]`
# 2. Define `result: data: list[dict]` with result of `dumps()` function for `DATA`
# 3. Non-functional requirements:
#    - Do not use `import` and any module
#    - Do not convert numbers to `int` or `float`, leave them as `str`
#    - Quoting: none
#    - Delimiter: `,`
#    - Lineseparator: `;`
#    - File ends with an empty line
# 4. Run doctests - all must succeed

# %% Polish
# 1. Zdefiniuj funkcję `load()`, która deserializuje list[object] z pliku:
#    - Argument: `data: str`
#    - Zwraca: `list[object]`
# 2. Zdefiniuj `result: list[object]` z wynikiem funkcji `dumps()` dla `DATA`
# 3. Wymagania niefunkcjonalne:
#    - Nie używaj `import` ani żadnych modułów
#    - Nie konwertuj liczb do `int` lub `float`, pozostaw je jako `str`
#    - Quoting: żadne
#    - Delimiter: `,`
#    - Lineseparator: `;`
#    - Plik kończy się pustą linią
# 4. Uruchom doctesty - wszystkie muszą się powieść

# %% Example
# >>> result
# [{'age': '30', 'firstname': 'Alice', 'lastname': 'Apricot'},
#  {'age': '31', 'firstname': 'Bob', 'lastname': 'Banana'},
#  {'age': '32', 'firstname': 'Carol', 'lastname': 'Corn'},
#  {'age': '33', 'firstname': 'Dave', 'lastname': 'Durian'},
#  {'age': '34', 'firstname': 'Eve', 'lastname': 'Elderberry'},
#  {'age': '15', 'firstname': 'Mallory', 'lastname': 'Melon'}]

# %% Hints
# - `[x for x in data]`
# - `tuple()`
# - `str.split()`
# - `dict()`
# - `zip()`

# %% Doctests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 12), \
'Python 3.12+ required'

>>> assert result is not Ellipsis, \
'Assign result to variable: `result`'
>>> assert type(result) is list, \
'Variable `result` has invalid type, should be list'
>>> assert all(type(x) is dict for x in result), \
'All rows in `result` should be dict'

>>> from pprint import pprint
>>> pprint(result, sort_dicts=False, width=79)
[{'age': '30', 'firstname': 'Alice', 'lastname': 'Apricot'},
 {'age': '31', 'firstname': 'Bob', 'lastname': 'Banana'},
 {'age': '32', 'firstname': 'Carol', 'lastname': 'Corn'},
 {'age': '33', 'firstname': 'Dave', 'lastname': 'Durian'},
 {'age': '34', 'firstname': 'Eve', 'lastname': 'Elderberry'},
 {'age': '15', 'firstname': 'Mallory', 'lastname': 'Melon'}]

>>> from os import remove
>>> remove(FILE)
"""

# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`

# %% Imports

# %% Types
from typing import Callable
type data = list[object]
loads: Callable[[str,...], data]
result: data

# %% Data
DATA = 'age,firstname,lastname;30,Alice,Apricot;31,Bob,Banana;32,Carol,Corn;33,Dave,Durian;34,Eve,Elderberry;15,Mallory,Melon'
FILE = '_temporary.dat'

with open(FILE, mode='wt', encoding='utf-8') as file:
    file.write(DATA)

# %% Result
result = ...