Vrácení jako dict
def load_aff_rules(...) -> dict:
rules = {'normal': [...], 'reversed': [...]}
return rules
- Výhody
- Čitelná pojmenovaná data:
rules['normal'],rules['reversed']. - Snadno se rozšiřuje o další klíče.
- Čitelná pojmenovaná data:
- Nevýhody
- Nutnost pamatovat si přesné názvy klíčů – hrozí
KeyError. - Horší podpora statické kontroly typů (mypy, IDE).
- O něco pomalejší přístup kvůli hash‑lookup v dictu.
- Nutnost pamatovat si přesné názvy klíčů – hrozí
Vrácení jako Tuple[List[AffRule], List[AffRule]]
from typing import Tuple, List
def load_aff_rules(self, ...) -> Tuple[List[AffRule], List[AffRule]]:
normal, reversed = [...], [...]
return normal, reversed
a skutečně:
return rules['normal'], rules['reversed']
- Výhody
- Jasně daná struktura: vždy dva seznamy ve stanoveném pořadí.
- Snadné rozbalení do proměnných:
normal_rules, reversed_rules = self.load_aff_rules(...) - Lepší podpora statické kontroly typů díky
Tuple[...]. - Rychlejší přístup (není potřeba dict‑lookup).
- Nevýhody
- Méně samo‑dokumentující – musíte znát pořadí výstupů.
- Obtížnější rozšíření – přidání dalšího výstupu změní definici tuple i všech volání.
Použití čárek
V definici typu:
-> Tuple[List[AffRule], List[AffRule]]
čárka odděluje první a druhý seznam.
V návratové hodnotě:
return rules['normal'], rules['reversed']
čárka tu znamená, že Python vrátí 2‑prvkový tuple.
Dodatek: Chyba AttributeError při rozbalování dict
Chyba:
AttributeError: 'str' object has no attribute 'matches'
Tato chyba vzniká při nesprávném rozbalení návratové hodnoty z funkce, která vrací
dict. Pokud máš následující kód:
aff_rules["normal"], aff_rules["reversed"] = self.load_aff_rules(...)
a funkce load_aff_rules vrací dict, dochází k tomu, že Python
se snaží rozbalit klíče slovníku, ne jeho hodnoty. Výsledkem je:
aff_rules["normal"] == "normal"aff_rules["reversed"] == "reversed"
což následně vede k chybě:
AttributeError: 'str' object has no attribute 'matches'
Řešení
Varianta A – Nechat návratový typ jako dict
Vrácený dict zachováš beze změny, ale rozbalíš ho ručně:
aff_rules = self.load_aff_rules(...)
normal_rules = aff_rules["normal"]
reversed_rules = aff_rules["reversed"]
for w in dic_entries["normal"]:
for r in normal_rules:
if r.matches(w):
dics_out["normal"].append(r.apply(w))
Varianta B – Vrátit Tuple místo dict
Pokud změníš návratovou hodnotu funkce na:
def load_aff_rules(...) -> Tuple[List[AffRule], List[AffRule]]:
return rules["normal"], rules["reversed"]
pak volání funkce bude:
normal_rules, reversed_rules = self.load_aff_rules(...)
a zbytek kódu funguje stejně, ale s jistotou, že máš dva seznamy objektů typu AffRule.
Výhodou této varianty je lepší podpora typové kontroly (mypy, IDE),
rychlejší přístup (není potřeba hash-lookup jako u dict)
a menší riziko chyb typu KeyError.
* * *
def parse_aff_input(self, aff_path: str) -> list[dict]:
Vysvětlení deklarace výstupního typu
Funkce skutečně vrací seznam slovníků, kde každý slovník má přesně tyto klíče a hodnoty:
'regex':str'substring':str'replacement':str'ext':str'tags':List[str]
Původní podpis
def parse_aff_input(self, aff_path: str) -> list[dict]: Toto je sice validní, ale statický typ dict neříká nic o tom, jaké klíče či hodnoty slovníky obsahují.
Konkrétní typová anotace
Můžeme si nejprve vytvořit TypedDict, aby bylo jasné, co v dictu očekáváme:
from typing import TypedDict, List
class AffRecord(TypedDict):
regex: str
substring: str
replacement: str
ext: str
tags: List[str]
A pak upravit deklaraci:
def parse_aff_input(self, aff_path: str) -> List[AffRecord]: ... Alternativa bez TypedDict
Pokud nechcete zavádět TypedDict, můžete alespoň upřesnit hodnoty pomocí Union:
from typing import List, Dict, Union
def parse_aff_input(self, aff_path: str) -> List[Dict[str, Union[str, List[str]]]]:
...
Tím dáváte najevo, že každá položka seznamu je slovník s řetězcovými klíči a hodnotami buď str nebo List[str].
Žádné komentáře:
Okomentovat