V dalším díle našeho seriálu o chybách v návrhu se podíváme na nešvar, kterého se mnohdy nevědomky dopouštíme: místo doménových typů k reprezentaci složených dat používáme řetězce.
-- Alan Perlis
Pojďme si ukázat typický příklad kódu, který využívá řetězce k reprezentaci složených dat. Kód bude v Pythonu, ale princip je na jazyce nezávislý. Mějme aplikaci, která potřebuje reprezentovat osoby. Tak si jich pár vytvoříme:
authors = ['Betty Elms', 'Diane Selwyn', 'Adam Kesher']
Dále mějme modul, který nám zajišťuje vytváření emailů. Jelikož chceme, aby emaily působily přívětivě, budeme autory oslovovat křestním jménem. Kód pro vytvoření oslovení pak může vypadat takto:
for author in authors: name = author.split(' ')[0] greetings = 'Dear ' + name + ',' # Dear Betty, ...
Jinde bychom zase potřebovali autory seřadit podle jejich příjmení. To lze při současné reprezentaci autorů udělat takto.
sorted_authors = sorted(authors, key=lambda author: author.split(' ')[1]) # ['Betty Elms', 'Adam Kesher', 'Diane Selwyn']
Možná už sami tušíte, že toto není ideální přístup. Schválně, zkuste se zamyslet, co za problémy nám současná reprezentace autorů přináší.
Použití řetězců k reprezentaci složených dat nám přináší následující problémy.
split()
.Místo řetězce si vytvoříme doménový typ - osobu:
class Person: def __init__(self, name, surname): self.name = name self.surname = surname @property def full_name(self): # Dekorátor property nám umožní psát author.full_name bez nutnosti # použít závorky. Pro uživatele naší třídy je to přirozenější, než # psát author.full_name(). return self.name + ' ' + self.surname def __str__(self): # print(author) vytiskne celé jméno return self.full_name
Náš původní kód pak bude vypadat následovně:
authors = [ Person('Betty', 'Elms'), Person('Diane', 'Selwyn'), Person('Adam', 'Kesher') ] for author in authors: greetings = 'Dear ' + author.name + ',' sorted_authors = sorted(authors, key=lambda author: author.surname)
Práce s osobou je tak soustředěna do třídy, zmíněné implicitní předpoklady mizí, nedochází k porušování "Tell, don't ask" a řešení je rozšiřitelné.
Vždy, když budete chtít použít řetězec, tak se nejdříve zamyslete, zda vaše data nejsou složená a zda se někde nepřistupuje k jednotlivým částem. Pokud ano, nepoužívejte raději řetězec, ale vytvořte si na jejich reprezentaci třídu. Později, až zjistíte, že řetězec nedostačuje, může být již pozdě na to dělat větší změny, protože by si vyžadovaly rozsáhlé úpravy na mnoha místech.
Pokud jste četli můj předchozí příspěvek o řazení v Pythonu, tak pro řazení objektů dle zvoleného atributu (či zvolených atributů) lze použít i následující konstrukci:
from operator import attrgetter sorted_authors = sorted(authors, key=attrgetter('surname'))
Dále, místo skládání řetězců
greetings = 'Dear ' + author.name + ','
lze využít formátování:
greetings = 'Dear {},'.format(author.name)
Komentáře
Ďakujem
Ďakujem za článok. Bolo to krátke, výstižné a užitočné. Dobrá práca!
Přidat komentář