2011-05-05 7 views
10

Posso definire un metodo Python sia statico che istanza allo stesso tempo? Qualcosa di simile:Metodi statici e di istanza in Python

class C(object): 
    @staticmethod 
    def a(self, arg1): 
     if self: 
      blah 
     blah 

In modo che posso chiamare con entrambi:

C.a(arg1) 
C().a(arg1) 

L'intento è quello di essere in grado di eseguire due serie di logiche. Se si accede come un metodo di istanza, farebbe uso di variabili di istanza e fare cose. Se l'accesso è un metodo statico, ne farà a meno.

+2

Hai provato? –

+0

http://stackoverflow.com/questions/5812537/can-i-have-a-method-of-a-class-which-can-be-used-as-a-staticmethod-or-instance-me è decisamente interessante. Mi stavo chiedendo se c'è un modo meno semplice di farlo – xster

risposta

17
import functools 

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

    def __get__(self, instance, owner): 
    return functools.partial(self.func, instance) 

class C(object): 
    @static_or_instance 
    def a(self, arg): 
    if self is None: 
     print "called without self:", arg 
    else: 
     print "called with self:", arg 

C.a(42) 
C().a(3) 
+4

Molto interessante. Ma io lo odio: D –

+0

L'hai fatto. Non posso credere che tu l'abbia fatto! – jathanism

+0

molto molto bello. – Haranadh

2

No. Cosa significherebbe self all'interno del metodo, se fosse possibile farlo?

1

Il codice funzionerà se si rimuove il parametro self su a(). Quando lo chiami con C().a(arg1) l'istanza viene ignorata.

Ma si desidera che questo metodo funzioni sia come metodo statico sia come metodo che riceve un'istanza. Non puoi averlo in entrambe le direzioni.

+0

Ma poi diventerebbe un normale metodo statico. Mi piacerebbe essere in grado di eseguire un diverso set di logica e accedere a self se utilizzato come metodo di istanza – xster

+1

È meglio passare le variabili che si desidera utilizzare all'interno del metodo. Quindi non ti importa se sono variabili di istanza o meno. – jathanism

4

formencode ha un decoratore classinstancemethod, che fa quello che vuoi. Richiede il metodo di avere 2 argomenti (self e cls, uno di loro potrebbe ottenere passati None a seconda del contesto chiamare)

sollevato da formencode/declarative.py

class classinstancemethod(object): 
    """ 
    Acts like a class method when called from a class, like an 
    instance method when called by an instance. The method should 
    take two arguments, 'self' and 'cls'; one of these will be None 
    depending on how the method was called. 
    """ 

    def __init__(self, func): 
     self.func = func 

    def __get__(self, obj, type=None): 
     return _methodwrapper(self.func, obj=obj, type=type) 

class _methodwrapper(object): 

    def __init__(self, func, obj, type): 
     self.func = func 
     self.obj = obj 
     self.type = type 

    def __call__(self, *args, **kw): 
     assert not kw.has_key('self') and not kw.has_key('cls'), (
      "You cannot use 'self' or 'cls' arguments to a " 
      "classinstancemethod") 
     return self.func(*((self.obj, self.type) + args), **kw) 

    def __repr__(self): 
     if self.obj is None: 
      return ('<bound class method %s.%s>' 
        % (self.type.__name__, self.func.func_name)) 
     else: 
      return ('<bound method %s.%s of %r>' 
        % (self.type.__name__, self.func.func_name, self.obj)) 

utilizzo Esempio

class A(object): 
    data = 5 

    @classinstancemethod 
    def print_(self=None, cls=None): 
     ctx = self or cls 
     print ctx.data 


>>> A.print_() 
5 
>>> a = A() 
>>> a.data = 4 
>>> a.print_() 
4