2016-03-11 16:13 GMT+00:00 Marco Santamaria <marco.santama...@gmail.com>:
sto lavorando ad un piccolo framework nel quale mi sento autorizzato ad > usare il modulo abc per creare delle classi astratte/interfacce per > permetterne l'estensione. > Ok. Va bene. > > Mi sono trovato spesso a dover assicurare la presenza di un attributo > nelle classi derivate da una classe astratta, senza avere la possibilità di > fornire un valore di default ragionevole. > O a me non e' chiaro quale sia il tuo problema concreto, oppure tu non hai guardato la doc per abstractproperty. https://docs.python.org/2/library/abc.html#abc.abstractproperty E' una cosa sottilmente diversa da quello che vuoi fare tu... che vuole dire che potrebbe essere perfetto (o essere perfetto una volta che ti orienti nella sua direzione) oppure totalmente inadatto. Questo lo puoi sapere solo tu. Personalmente lo considererei perche' si muove nello stesso spazio di problemi che descrivi. Ovviamente non funziona *esattamente* come quello che descrivi. In pratica lui ti assicura la presenza di una *property* che fa quello che vuoi, mentre un attributo e' un concetto un pochetto piu' generale. In [1]: import abc In [2]: class B(object): ...: __metaclass__ = abc.ABCMeta ...: @abc.abstractproperty ...: def foo(self): pass ...: In [3]: class A(B): pass In [4]: A() --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-4-3cd318a12eea> in <module>() ----> 1 A() TypeError: Can't instantiate abstract class A with abstract methods foo In [5]: A(foo='bar') --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-5-99b4610496e4> in <module>() ----> 1 A(foo='bar') TypeError: object() takes no parameters In [6]: class AOK(B): ...: @property ...: def foo(self): return 42 ...: In [7]: AOK().foo Out[7]: 42 In [8]: class ABad(B): ...: def __init__(self, foo): ...: self.foo = foo ...: In [9]: ABad(foo=42).foo --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-9-d3c627ae930d> in <module>() ----> 1 ABad(foo=42).foo TypeError: Can't instantiate abstract class ABad with abstract methods foo > Data la natura dinamica di Python questo può essere fatto in vari modi, ma > mi chiedo quale sia quello più 'idiomatico' in Python 3.4, facendo in modo > che venga sollevata il prima possibile un'eccezione chiara se > quell'attributo non viene definito. > > Al momento mi sono venute in mente tre soluzioni: > > 1. controllare con hasattr la presenza dell'attributo nel metodo > __init__ della classe astratta > 2. definire nella classe astratta una proprietà (decorata con > @property) che solleva un'eccezione NotImplementedError > 3. definire nella classe astratta un metodo astratto (decorato con > @abstractmethod) con lo stesso nome dell'attributo > > Sto usando la 3. quando possibile perché solleva un'eccezione prima delle > altre, ma non mi piace molto l'idea di richiedere un metodo quando voglio > un attributo. > Ok. Se stai usando la 3, passare ad abstractproperty ti avvicina un po' a quello che vuoi. La 2 e' una versione fatta con lo scotch di abstractproperty (o meglio, sta ad abstractproperty come fare un metodo che ti tira not implemented sta ad abstractmethod: specificamente la differenza e' quando ottieni l'errore; abstract* ti da un errore se quando istanzi l'oggetto un determinato ente non e' nell'mro dell'oggetto, viceversa tirare sulla chiamata te lo segnala appunto se e solo se lo chiami... non entro nel merito del quando preferisco uno o l'altro perche' e' complicato). hasattr funzionicchia, ma hai un sacco di edge case fastidiosi. Per esempio ti rende molto vulnerabile all'ordine di risoluzione dei metodi (mro) e al fatto che qualche derivata *non* chiami l'__init__ che vorresti tu. Secondo me e'facile impiccarsi con una soluzione che apparentemente funziona, ma in pratica lascia fuori sufficienti casi da scoprire in produzione che effettivamente non funzionava. abstractproperty ha il vantaggio che a fronte di essere marginalmente piu' scomodo da scrivere e' molto chiaro nell'intento ed e' relativamente improbabile scavalcarlo "per errore". -- . ..: -enrico-
_______________________________________________ Python mailing list Python@lists.python.it http://lists.python.it/mailman/listinfo/python