2013-08-06 20 views
7

volte devo bisogno di scrivere classe con metodi statici, ma con possibilità di inizializzazione e mantenere lo stato (oggetto)pitone: ibrido tra il metodo regolare e classmethod

STH come:

class A: 
    @classmethod 
    def method(cls_or_self): 
    # get reference to object when A().method() or to class when A.method() 
    code 

quello Ho ora è:

class A: 
    def method(self = None, *params): code 
    # or 
    def method2(self = None, **params): code 
    # but what I need is rather normal parameters, not optional and named args: 
    def method3(self_or_cls, a, b=1, c=2, *p, **kw): code 

per favore non scrivere sulle differenze tra staticmethod e classmethod. Mi interessa se tale decoratore esiste (in libs più o meno standard) e inoltre se sopra è adatto per PEP.

+2

Vuoi dire un ibrido tra un classmethod e un metodo * * regolare. –

risposta

17

Le funzioni e gli oggetti classmethod funzionano come descriptors; entrambi restituiscono un wrapper che, quando chiamato, a sua volta chiama la funzione sottostante con un parametro extra. L'unica differenza tra il modo in cui le funzioni e gli oggetti classmethod si comportano è in quale parametro aggiuntivo è.

Per creare un ibrido tra i due approcci, costruire il proprio descrittore decoratore:

from functools import wraps 

class hybridmethod(object): 
    def __init__(self, func): 
     self.func = func 

    def __get__(self, obj, cls): 
     context = obj if obj is not None else cls 

     @wraps(self.func) 
     def hybrid(*args, **kw): 
      return self.func(context, *args, **kw) 

     # optional, mimic methods some more 
     hybrid.__func__ = hybrid.im_func = self.func 
     hybrid.__self__ = hybrid.im_self = context 

     return hybrid 

Qui, torniamo un wrapper che verrà utilizzato sia la classe o l'istanza come primo parametro, a seconda di ciò è disponibile quando viene chiamato il metodo del descrittore __get__.

Demo:

>>> class Foo(object): 
...  @hybridmethod 
...  def bar(cls_or_self): 
...   print 'Called with cls_or_self={!r}'.format(cls_or_self) 
... 
>>> Foo.bar() 
Called with cls_or_self=<class '__main__.Foo'> 
>>> Foo().bar() 
Called with cls_or_self=<__main__.Foo object at 0x1043a4390> 
+0

... così veloce e sorprendente che devo aspettare per accettare la risposta (req stackoverflow), ma per quanto riguarda classmethod? - per me sopra decoratore sembra molto funzionale, anche per suggerire di sovrascrivere il clasmethod o aggiungere terzo decoratore standard per i metodi. So che richiede forti critiche. –

+0

Il decoratore 'classmethod' ha un obiettivo diverso; metodi ambigui sul loro comportamento (che agiscono in un modo o nell'altro in base al contesto) non sono troppo pitonici. –

Problemi correlati