2012-11-01 19 views
8

Ho seguente codice:metodo statico e ricorsione?

class Foo(object): 
    def __init__(self): 
     baz=self.bar(10) 

    @staticmethod 
    def bar(n): 
     if n==0: 
      return 'bar' 
     else: 
      return bar(n-1) 

bar() in funzione ricorsiva ha bisogno riferimento a se stessa. Tuttavia, bar() si trova all'interno di una classe e la chiamata a return bar(n-1) non funzionerà, invocando NameError: global name 'bar' is not defined. Come posso affrontare questo tipo di situazione? Devo cambiare barra() in un metodo di classe o istanza, consentendo l'accesso a self o cls?

+1

Il richiamo di 'Foo.bar (n-1)' nella guida di chiamata ricorsiva? – inspectorG4dget

risposta

4

Un'alternativa all'uso di un metodo di classe o chiamando classe per nome (come mostrato da altri) è quello di utilizzare una chiusura per contenere il riferimento alla funzione:

class Foo(object): 
    def bar(): 
     def bar(n): 
      if n == 0: 
       return "bar" 
      return bar(n-1) 
     return bar 
    bar = staticmethod(bar()) 

Il (minore) il vantaggio è che questo è un po 'meno suscettibile di rottura quando i nomi cambiano. Ad esempio, se si dispone di un riferimento a Foo.barall'internobar, questa si basa su Foo continuando ad essere un nome globale per la classe che bar è definito in. Di solito questo è il caso, ma se non lo è, allora la chiamata ricorsiva pause.

L'approccio classmethod fornirà il metodo con un riferimento alla classe, ma la classe non è altrimenti necessaria nel metodo, che sembra poco elegante. L'utilizzo della chiusura sarà anche leggermente più veloce perché non sta eseguendo una ricerca di attributi per ogni chiamata.

16

è possibile fare riferimento a bar dal prefisso con il nome della classe:

class Foo(object): 
    def __init__(self): 
     baz=self.bar(10) 

    @staticmethod 
    def bar(n): 
     if n==0: 
      return 'bar' 
     else: 
      return Foo.bar(n-1) 

I metodi statici non sono altro che normali funzioni contenute all'interno del namespace di una classe, dopo tutto.

alternativa, definire bar come funzione regolare invece:

def bar(n): 
    if n==0: 
     return 'bar' 
    else: 
     return bar(n-1) 

class Foo(object): 
    def __init__(self): 
     baz=bar(10) 

che evita l'intera questione del tutto.

+0

@senderle: sì, solo un errore c & p da parte mia. Ne hai bisogno anche in Python 3. –

+0

In realtà il codice funziona correttamente senza di esso in Python 3 - almeno quando chiamato da 'Foo' stesso. (Ma vedo che non funziona quando viene chiamato da un'istanza 'Foo'.) – senderle

+3

@senderle Funziona in Python 3 perché non ci sono più wrapper" metodo non associato "che richiedono' isinstance (self, DefiningClass) 'durante la chiamata metodi. Una cosa che funziona solo con '@ staticmethod' sta chiamando il metodo su un'istanza (' Foo(). Bar (1) '). – delnan

7

Che dire?

class Foo(object): 
    def __init__(self): 
     baz = self.bar(10) 

    @classmethod 
    def bar(cls, n): 
     if n == 0: 
      return 'bar' 
     else: 
      return cls.bar(n-1) 
2

È possibile definire bar() al di fuori di Foo e quindi portarlo come metodo statico in modo da ottenere tutti i vantaggi di essere un metodo della classe senza doverlo chiudere o fare riferimento alla classe stessa. Ho avuto bisogno di qualcosa del genere per motivi di ereditarietà di classe.

def bar(n): 
    if n==0: 
     return 'bar' 
    else: 
     return bar(n-1) 

class Foo(object): 
    bar = staticmethod(bar) 
    def __init__(self): 
     baz=self.bar(10) 
Problemi correlati