<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">2016-03-11 16:13 GMT+00:00 Marco Santamaria <span dir="ltr"><<a href="mailto:marco.santamaria@gmail.com" target="_blank">marco.santamaria@gmail.com</a>></span>:</div><div class="gmail_quote"><br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div dir="ltr"><div><div>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.<br></div></div></div></blockquote><div><br></div><div>Ok. Va bene.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div dir="ltr"><div><div><br></div>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.<br></div></div></blockquote><div><br></div><div>O a me non e' chiaro quale sia il tuo problema concreto, oppure tu non hai guardato la doc per abstractproperty.</div><div><br></div><div><a href="https://docs.python.org/2/library/abc.html#abc.abstractproperty">https://docs.python.org/2/library/abc.html#abc.abstractproperty</a><br></div><div><br></div><div>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.</div><div><br></div><div>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.</div><div><br></div><div><div>In [1]: import abc</div><div><br></div><div>In [2]: class B(object):</div><div>   ...:     __metaclass__ = abc.ABCMeta</div><div>   ...:     @abc.abstractproperty<br></div><div>   ...:     def foo(self): pass</div><div>   ...:</div><div><br></div><div>In [3]: class A(B): pass</div><div><br></div><div>In [4]: A()</div><div>---------------------------------------------------------------------------</div><div>TypeError                                 Traceback (most recent call last)</div><div><ipython-input-4-3cd318a12eea> in <module>()</div><div>----> 1 A()</div><div><br></div><div>TypeError: Can't instantiate abstract class A with abstract methods foo</div><div><br></div><div>In [5]: A(foo='bar')</div><div>---------------------------------------------------------------------------</div><div>TypeError                                 Traceback (most recent call last)</div><div><ipython-input-5-99b4610496e4> in <module>()</div><div>----> 1 A(foo='bar')</div><div><br></div><div>TypeError: object() takes no parameters</div><div><br></div><div>In [6]: class AOK(B):</div><div>   ...:     @property</div><div>   ...:     def foo(self): return 42</div><div>   ...:</div><div><br></div><div>In [7]: AOK().foo</div><div>Out[7]: 42</div><div><br></div><div>In [8]: class ABad(B):</div><div>   ...:     def __init__(self, foo):</div><div>   ...:         self.foo = foo</div><div>   ...:</div><div><br></div><div>In [9]: ABad(foo=42).foo</div><div>---------------------------------------------------------------------------</div><div>TypeError                                 Traceback (most recent call last)</div><div><ipython-input-9-d3c627ae930d> in <module>()</div><div>----> 1 ABad(foo=42).foo</div><div><br></div><div>TypeError: Can't instantiate abstract class ABad with abstract methods foo</div></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div dir="ltr"><div>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.<br><br></div>Al momento mi sono venute in mente tre soluzioni:<br><ol><li>controllare con hasattr la presenza dell'attributo nel metodo __init__ della classe astratta</li><li>definire nella classe astratta una proprietà (decorata con @property) che solleva un'eccezione NotImplementedError</li><li>definire nella classe astratta un metodo astratto (decorato con @abstractmethod) con lo stesso nome dell'attributo<br></li></ol><div><div><div><div><div><div>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.<br></div></div></div></div></div></div></div></blockquote><div><br></div><div>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).</div><div><br></div><div>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.</div><div><br></div><div>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".</div></div><br><br clear="all"><div><br></div>-- <br><div class="gmail_signature"> .<br>..: -enrico-</div>
</div></div>