Minule jsem zmínil, že můžeme chtít také v modelu spravovat vybranou položku. Tady už nastává oboustraná komunikace mezi view (neboli tím vlastním oknem nebo ovládacím prvkem) a modelem. View musí modelu sdělit, že se změnila vybraná položka, naopak model musí „odpálit“ zprávu když se změní vybraná položka. Jenže tady nám vzniká potenciální problém. View řekne modelu: nastav výběr na pátou položku. Na základě toho model odpálí změnu výběru, což odchytne view, a sdělí modelu, ať nastaví výběr na pátou položku, a tak pořád až do nekonečné rekurze. Samozřejmě ta náprava tkví v tom, že v modelu odpalujeme změnu výběru pouze, pokud se výběr opravdu změnil, a stejně tak ve view v handleru změny výběru nastavujeme výběr pouze, pokud se změnil. Tak, jak je v github/modellerkit step02, a vypadá to asi takto:
# model: def select(self, index): if self.selection == index: return self.selection = index self._fire("select", index) # view: def handle_select(self, event_source, event_name, data): selected = self.GetFirstSelected() if data == selected: return if data > -1: self.Select(data) elif -1 == selected: pass else: self.Select(selected, False)To je ovšem jen takový implementační detail.
Teď udělám malou odbočku. collections.namedtuple je geniální nápad jak dát nám programátorům k dispozici snadnou možnost nadefinovat si vlastní třídu, která je potomek tuple, a k jejíž prvkům se dá přistupovat jak přes index, tak přes jméno. Zároveň je to tuple, takže prvkům nelze přiřadit jinou hodnotu. Např.:
from collections import namedtuple SampleStruct = namedtuple("SampleStruct", ["id", "name", "mktm",]) item = SampleStruct(1, "passwd", "2013-12-4 5:32:11") item.id item.name item.mktm = "2013-12-4 12:43" # tohle nelze
Jako by to na mě křičelo: Použij mě pro modelářskou sadu! Tak dobře. Ve github/modellerkit step03/hotlist.py máme novou třídu TypedHotList, která je potomkem HotList, a která jen kontroluje, že přiřazované hodnoty jsou toho typu, který jsme si na začátku určili:
class TypedHotList(HotList): def __init__(self, type_constraint, init_iterable=None): super(TypedHotList, self).__init__(init_iterable) self.type_constraint = type_constraint def _validate_value(self, val): if not isinstance(val, self.type_constraint): raise TypeError("Only %s allowed here." % self.type_constraint) if isinstance(val, tuple) or isinstance(val, frozenset): for i in val: self._validate_sub_value(i) return val def _validate_sub_value(self, val): if type(val) in (int, long, float, str, unicode, ): return val if isinstance(val, tuple) or isinstance(val, frozenset): for i in val: self._validate_sub_value(i) return val raise TypeError("Only number/strings and tuples/frozensets allowed here.")
TypedHotList není typově omezen jen na namedtuple, ikdyž by to asi bylo přijatelné omezení.
Edit: Jestliže moje původní myšlenka byla, že HotList (nebo TypedHotList) nesmí obsahovat mutable hodnoty, tak tady mi to nefunguje. Berte to, jako takovou pracovní verzi.
Co je vlastně model? Máme pro jedno složitější view, které má třeba 2 seznamy a ještě něco k tomu zvlášť dva modely pro seznamy a ještě model pro to něco k tomu, nebo chceme raději jeden větší model, ve kterém budou všechna data pohromadě? Zároveň s tím se budeme muset podívat na pořádný dispatch.
Ahoj, prijde mi, ze kvuli testu isinstance() na konkretni typ jsi prisel o duck-typing. Podle mne to neni nutne a slo by dosahnout pres abstraktni bazove tridy (se zachovanim duck-typingu). Tedy test na typ by overolva abstraktniho predka pomoci if not isinstance(val, virtual_ancestor).
Virtualni predek by se zadefinoval takhle:
import abc
class virtual_ancestor(metaclass=abc.ABCMeta):
pass
A kazdy kdo by chtel mit tridu ktera dedi od toho virtualniho predka (tedy ekvivalent k registrovani constraintu) by se zaregistroval pomoci virtual_ancestor.register(my_type).
Ahoj, díky za komentář. Jestli to chápu správně, tak píšeš, že takto můžu použít jako případný prvek pole vpodstatě jakýkoliv typ, jen tím, že mu zaregistruju virtual_ancestor. Jenže můj cíl je hlavně to, aby ty prvky pole byly immutable. Kdybych nechal tu volnost vrazit tam cokoliv, tak tam brzo někdo (třeba já) vrazí objekt, který jde modifikovat, to nezdetekuju, a o změnách se nedozvím.
Uznávám, že to mi ten TypedHotList momentálně nesplňuje, je to taková pracovní verze.
Jmenuju se Petr Blahoš. Programuju něco přes 20 let. Tady se snažím psát hlavně o Pythonu, webovém frameworku Pyramid, a občas i o něčem úplně jiném.
Přečteno 19 398×
Přečteno 11 921×
Přečteno 9 489×
Přečteno 8 944×
Přečteno 8 729×