2012-11-01 55 views
8

我已經以下代碼:staticmethod和遞歸?

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()的,因爲它需要本身參考遞歸函數。但是,bar()在類中,調用return bar(n-1)將不起作用,調用NameError: global name 'bar' is not defined。我該如何處理這種情況?我是否應該將bar()更改爲類或實例方法,從而允許訪問selfcls

+1

在遞歸調用幫助中調用'Foo.bar(n-1)'嗎? – inspectorG4dget

回答

4

使用一個類方法或調用由名稱(如由其他人)類是使用一個封閉件來保存參照功能的替代:

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

的(次要)好處是這在名稱改變時不易受到破壞。例如,如果您在bar中參照Foo.bar,則這依賴於Foo繼續是定義bar的類的全局名稱。通常情況下是這種情況,但如果不是,則遞歸調用休息。

classmethod方法將爲該方法提供對該類的引用,但該方法在方法中並不需要,這看起來不夠優雅。使用閉包的速度也會稍微快一點,因爲它不會在每次調用時進行屬性查找。

16

您可以參考bar通過與類名前綴是:

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) 

靜態方法是什麼,但一類的命名空間內包含畢竟常規功能。

另外,定義bar作爲一個普通函數來代替:

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

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

這就完全避免了整個問題。

+0

@senderle:是的,只是我的一個C&P錯誤。你也需要Python 3。 –

+0

實際上,在Python 3中沒有它的代碼就可以正確運行 - 至少從'Foo'本身調用時。 (但是我發現從'Foo'實例調用時它不起作用。) – senderle

+3

@senderle它在Python 3中工作,因爲沒有更多的「未綁定方法」包裝器在調用時需要「isinstance(self,DefiningClass)''方法。有一件事情只能在'@ staticmethod'中起作用,就是調用一個實例的方法('Foo().bar(1)')。 – delnan

7

那該怎麼辦?

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

您可以在Foo之外定義bar(),然後將其作爲靜態方法引入,以便您可以獲得它作爲類的一個方法的所有好處,而不必關閉它或引用類本身。出於類繼承的原因,我需要這樣的東西。

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)