6.9. Relations¶
6.9.1. Relations¶
class Astronaut:
def __init__(self, firstname, lastname, missions=()):
self.firstname = firstname
self.lastname = lastname
self.missions = list(missions)
class Mission:
def __init__(self, year, name):
self.year = year
self.name = name
DATA = [
Astronaut('Jan', 'Twardowski', missions=[
Mission('1967', 'Apollo 1'),
Mission('1970', 'Apollo 13'),
Mission('1973', 'Apollo 18')]),
Astronaut('Ivan', 'Ivanovic', missions=[
Mission('2023', 'Artemis 2'),
Mission('2024', 'Artemis 3')]),
Astronaut('Mark', 'Watney', missions=[
Mission('2035', 'Ares 3')]),
Astronaut('Melissa', 'Lewis'),
]
6.9.3. Assignments¶
"""
* Assignment: OOP Relations Syntax
* Complexity: easy
* Lines of code: 7 lines
* Time: 5 min
English:
1. Use Dataclass to define class `Point` with attributes:
a. `x: int` with default value `0`
b. `y: int` with default value `0`
2. Use Dataclass to define class `Path` with attributes:
a. `points: list[Point]` with default empty list
3. Compare result with "Tests" section (see below)
Polish:
1. Użyj Dataclass do zdefiniowania klasy `Point` z atrybutami:
a. `x: int` z domyślną wartością `0`
b. `y: int` z domyślną wartością `0`
2. Użyj Dataclass do zdefiniowania klasy `Path` z atrybutami:
a. `points: list[Point]` z domyślną pustą listą
3. Porównaj wyniki z sekcją "Tests" (patrz poniżej)
Tests:
>>> from inspect import isclass
>>> assert isclass(Point)
>>> assert isclass(Path)
>>> assert hasattr(Point, 'x')
>>> assert hasattr(Point, 'y')
>>> Point()
Point(x=0, y=0)
>>> Point(x=0, y=0)
Point(x=0, y=0)
>>> Point(x=1, y=2)
Point(x=1, y=2)
>>> Path([Point(x=0, y=0),
... Point(x=0, y=1),
... Point(x=1, y=0)])
Path(points=[Point(x=0, y=0), Point(x=0, y=1), Point(x=1, y=0)])
"""
# Given
from dataclasses import dataclass, field
"""
* Assignment: OOP Relations Model
* Complexity: easy
* Lines of code: 10 lines
* Time: 13 min
English:
1. Use data from "Given" section (see below)
2. In `DATA` we have two classes
3. Model data using classes and relations
4. Create instances dynamically based on `DATA`
5. Compare result with "Tests" section (see below)
Polish:
1. Użyj danych z sekcji "Given" (patrz poniżej)
2. W `DATA` mamy dwie klasy
3. Zamodeluj problem wykorzystując klasy i relacje między nimi
4. Twórz instancje dynamicznie na podstawie `DATA`
5. Porównaj wyniki z sekcją "Tests" (patrz poniżej)
Tests:
>>> assert type(result) is list
>>> assert all(type(astro) is Astronaut
... for astro in result)
>>> assert all(type(addr) is Address
... for astro in result
... for addr in astro.addresses)
>>> result # doctest: +NORMALIZE_WHITESPACE
[Astronaut(firstname='Jan',
lastname='Twardowski',
addresses=[Address(street='Kamienica Pod św. Janem Kapistranem', city='Kraków', postcode='31-008', region='Małopolskie', country='Poland')]),
Astronaut(firstname='José',
lastname='Jiménez',
addresses=[Address(street='2101 E NASA Pkwy', city='Houston', postcode=77058, region='Texas', country='USA'),
Address(street='', city='Kennedy Space Center', postcode=32899, region='Florida', country='USA')]),
Astronaut(firstname='Mark',
lastname='Watney',
addresses=[Address(street='4800 Oak Grove Dr', city='Pasadena', postcode=91109, region='California', country='USA'),
Address(street='2825 E Ave P', city='Palmdale', postcode=93550, region='California', country='USA')]),
Astronaut(firstname='Иван',
lastname='Иванович',
addresses=[Address(street='', city='Космодро́м Байкону́р', postcode='', region='Кызылординская область', country='Қазақстан'),
Address(street='', city='Звёздный городо́к', postcode=141160, region='Московская область', country='Россия')]),
Astronaut(firstname='Melissa',
lastname='Lewis',
addresses=[]),
Astronaut(firstname='Alex',
lastname='Vogel',
addresses=[Address(street='Linder Hoehe', city='Köln', postcode=51147, region='North Rhine-Westphalia', country='Germany')])]
"""
# Given
from dataclasses import dataclass
from typing import Optional, Union
DATA = [
{"firstname": "Jan", "lastname": "Twardowski", "addresses": [
{"street": "Kamienica Pod św. Janem Kapistranem", "city": "Kraków", "postcode": "31-008", "region": "Małopolskie", "country": "Poland"}]},
{"firstname": "José", "lastname": "Jiménez", "addresses": [
{"street": "2101 E NASA Pkwy", "city": "Houston", "postcode": 77058, "region": "Texas", "country": "USA"},
{"street": "", "city": "Kennedy Space Center", "postcode": 32899, "region": "Florida", "country": "USA"}]},
{"firstname": "Mark", "lastname": "Watney", "addresses": [
{"street": "4800 Oak Grove Dr", "city": "Pasadena", "postcode": 91109, "region": "California", "country": "USA"},
{"street": "2825 E Ave P", "city": "Palmdale", "postcode": 93550, "region": "California", "country": "USA"}]},
{"firstname": "Иван", "lastname": "Иванович", "addresses": [
{"street": "", "city": "Космодро́м Байкону́р", "postcode": "", "region": "Кызылординская область", "country": "Қазақстан"},
{"street": "", "city": "Звёздный городо́к", "postcode": 141160, "region": "Московская область", "country": "Россия"}]},
{"firstname": "Melissa", "lastname": "Lewis", "addresses": []},
{"firstname": "Alex", "lastname": "Vogel", "addresses": [
{"street": "Linder Hoehe", "city": "Köln", "postcode": 51147, "region": "North Rhine-Westphalia", "country": "Germany"}]}
]
result: list
"""
* Assignment: OOP Relations Movable
* Complexity: medium
* Lines of code: 18 lines
* Time: 21 min
English:
1. Define class `Point`
2. Class `Point` has attributes `x: int = 0` and `y: int = 0`
3. Define class `Movable`
4. In `Movable` define method `get_position(self) -> Point`
5. In `Movable` define method `set_position(self, x: int, y: int) -> None`
6. In `Movable` define method `change_position(self, left: int = 0, right: int = 0, up: int = 0, down: int = 0) -> None`
7. Assume left-top screen corner as a initial coordinates position:
a. going right add to `x`
b. going left subtract from `x`
c. going up subtract from `y`
d. going down add to `y`
8. Compare result with "Tests" section (see below)
Polish:
1. Zdefiniuj klasę `Point`
2. Klasa `Point` ma atrybuty `x: int = 0` oraz `y: int = 0`
3. Zdefiniuj klasę `Movable`
4. W `Movable` zdefiniuj metodę `get_position(self) -> Point`
5. W `Movable` zdefiniuj metodę `set_position(self, x: int, y: int) -> None`
6. W `Movable` zdefiniuj metodę `change_position(self, left: int = 0, right: int = 0, up: int = 0, down: int = 0) -> None`
7. Przyjmij górny lewy róg ekranu za punkt początkowy:
a. idąc w prawo dodajesz `x`
b. idąc w lewo odejmujesz `x`
c. idąc w górę odejmujesz `y`
d. idąc w dół dodajesz `y`
8. Porównaj wyniki z sekcją "Tests" (patrz poniżej)
Tests:
>>> from inspect import isclass, ismethod
>>> assert isclass(Point)
>>> assert isclass(Movable)
>>> assert hasattr(Point, 'x')
>>> assert hasattr(Point, 'y')
>>> assert hasattr(Movable, 'get_position')
>>> assert hasattr(Movable, 'set_position')
>>> assert hasattr(Movable, 'change_position')
>>> assert ismethod(Movable().get_position)
>>> assert ismethod(Movable().set_position)
>>> assert ismethod(Movable().change_position)
>>> class Astronaut(Movable):
... pass
>>> astro = Astronaut()
>>> astro.set_position(x=1, y=2)
>>> astro.get_position()
Point(x=1, y=2)
>>> astro.set_position(x=1, y=1)
>>> astro.change_position(right=1)
>>> astro.get_position()
Point(x=2, y=1)
>>> astro.set_position(x=1, y=1)
>>> astro.change_position(left=1)
>>> astro.get_position()
Point(x=0, y=1)
>>> astro.set_position(x=1, y=1)
>>> astro.change_position(down=1)
>>> astro.get_position()
Point(x=1, y=2)
>>> astro.set_position(x=1, y=1)
>>> astro.change_position(up=1)
>>> astro.get_position()
Point(x=1, y=0)
"""
from dataclasses import dataclass
"""
* Assignment: OOP Relations Flatten
* Complexity: hard
* Lines of code: 5 lines
* Time: 21 min
English:
1. Use code from "Given" section (see below)
2. How to write relations to CSV file (contact has many addresses)?
3. Convert `DATA` to `resul: list[dict[str,str]]`
4. Non-functional requirements:
a. Use `,` to separate fields
b. Use `;` to separate columns
5. Compare result with "Tests" section (see below)
Polish:
1. Użyj kodu z sekcji "Given" (patrz poniżej)
2. Jak zapisać w CSV dane relacyjne (kontakt ma wiele adresów)?
3. Przekonwertuj `DATA` do `resul: list[dict[str,str]]`
4. Wymagania niefunkcjonalne:
b. Użyj `,` do oddzielenia pól
b. Użyj `;` do oddzielenia kolumn
5. Porównaj wyniki z sekcją "Tests" (patrz poniżej)
Tests:
>>> result # doctest: +NORMALIZE_WHITESPACE
[{'firstname': 'Jan', 'lastname': 'Twardowski', 'missions': '1967,Apollo 1;1970,Apollo 13;1973,Apollo 18'},
{'firstname': 'Ivan', 'lastname': 'Ivanovic', 'missions': '2023,Artemis 2;2024,Artemis 3'},
{'firstname': 'Mark', 'lastname': 'Watney', 'missions': '2035,Ares 3'},
{'firstname': 'Melissa', 'lastname': 'Lewis', 'missions': ''}]
"""
# Given
class Astronaut:
def __init__(self, firstname, lastname, missions=()):
self.firstname = firstname
self.lastname = lastname
self.missions = list(missions)
class Mission:
def __init__(self, year, name):
self.year = year
self.name = name
DATA = [
Astronaut('Jan', 'Twardowski', missions=[
Mission('1967', 'Apollo 1'),
Mission('1970', 'Apollo 13'),
Mission('1973', 'Apollo 18')]),
Astronaut('Ivan', 'Ivanovic', missions=[
Mission('2023', 'Artemis 2'),
Mission('2024', 'Artemis 3')]),
Astronaut('Mark', 'Watney', missions=[
Mission('2035', 'Ares 3')]),
Astronaut('Melissa', 'Lewis')]
result: list
"""
* Assignment: OOP Relations Nested
* Complexity: medium
* Lines of code: 7 lines
* Time: 21 min
English:
1. Use data from "Given" section (see below)
2. Convert `DATA` to format with one column per each attrbute
for example: `street1`, `street2`, `city1`, `city2`, etc.
3. Compare result with "Tests" section (see below)
Polish:
1. Użyj danych z sekcji "Given" (patrz poniżej)
2. Przekonweruj `DATA` do formatu z jedną kolumną dla każdego atrybutu,
np. `street1`, `street2`, `city1`, `city2`, itd.
3. Porównaj wyniki z sekcją "Tests" (patrz poniżej)
Tests:
>>> type(result)
<class 'list'>
>>> result # doctest: +NORMALIZE_WHITESPACE
[{'firstname': 'Jan', 'lastname': 'Twardowski', 'street1': 'Kamienica Pod św. Janem Kapistranem', 'city1': 'Kraków', 'post_code1': '31-008', 'region1': 'Małopolskie', 'country1': 'Poland'},
{'firstname': 'José', 'lastname': 'Jiménez', 'street1': '2101 E NASA Pkwy', 'city1': 'Houston', 'post_code1': 77058, 'region1': 'Texas', 'country1': 'USA', 'street2': '', 'city2': 'Kennedy Space Center', 'post_code2': 32899, 'region2': 'Florida', 'country2': 'USA'},
{'firstname': 'Mark', 'lastname': 'Watney', 'street1': '4800 Oak Grove Dr', 'city1': 'Pasadena', 'post_code1': 91109, 'region1': 'California', 'country1': 'USA', 'street2': '2825 E Ave P', 'city2': 'Palmdale', 'post_code2': 93550, 'region2': 'California', 'country2': 'USA'},
{'firstname': 'Иван', 'lastname': 'Иванович', 'street1': '', 'city1': 'Космодро́м Байкону́р', 'post_code1': '', 'region1': 'Кызылординская область', 'country1': 'Қазақстан', 'street2': '', 'city2': 'Звёздный городо́к', 'post_code2': 141160, 'region2': 'Московская область', 'country2': 'Россия'},
{'firstname': 'Melissa', 'lastname': 'Lewis'},
{'firstname': 'Alex', 'lastname': 'Vogel', 'street1': 'Linder Hoehe', 'city1': 'Köln', 'post_code1': 51147, 'region1': 'North Rhine-Westphalia', 'country1': 'Germany'}]
"""
# Given
import json
DATA = """[
{"firstname": "Jan", "lastname": "Twardowski", "addresses": [
{"street": "Kamienica Pod św. Janem Kapistranem", "city": "Kraków", "post_code": "31-008", "region": "Małopolskie", "country": "Poland"}]},
{"firstname": "José", "lastname": "Jiménez", "addresses": [
{"street": "2101 E NASA Pkwy", "city": "Houston", "post_code": 77058, "region": "Texas", "country": "USA"},
{"street": "", "city": "Kennedy Space Center", "post_code": 32899, "region": "Florida", "country": "USA"}]},
{"firstname": "Mark", "lastname": "Watney", "addresses": [
{"street": "4800 Oak Grove Dr", "city": "Pasadena", "post_code": 91109, "region": "California", "country": "USA"},
{"street": "2825 E Ave P", "city": "Palmdale", "post_code": 93550, "region": "California", "country": "USA"}]},
{"firstname": "Иван", "lastname": "Иванович", "addresses": [
{"street": "", "city": "Космодро́м Байкону́р", "post_code": "", "region": "Кызылординская область", "country": "Қазақстан"},
{"street": "", "city": "Звёздный городо́к", "post_code": 141160, "region": "Московская область", "country": "Россия"}]},
{"firstname": "Melissa", "lastname": "Lewis", "addresses": []},
{"firstname": "Alex", "lastname": "Vogel", "addresses": [
{"street": "Linder Hoehe", "city": "Köln", "post_code": 51147, "region": "North Rhine-Westphalia", "country": "Germany"}]}
]"""
result: list