2011-03-17 88 views
5

我在裝飾Python中的靜態方法時遇到了一些問題。我想下面的代碼最能代表我的問題:Python:裝飾靜態方法recive不可調用方法

def decorator(func): 
    print callable(func) 
    return func 

class Foo(): 
    @decorator 
    @staticmethod 
    def bar(): 
     return 

# outputs False 

print callable(Foo.bar) 
# outputs True 

這似乎是一個錯誤。我想它的出現是因爲當方法Foo.bar被傳遞給裝飾器時,它是一個函數,而不是一個方法。這是我看到它不可調用的唯一原因,因爲如果我們裝飾一個標準函數,它不可調用,如下所示。

@staticmethod 
def function(): 
    return 

print callable(function) 
# outputs False 

因此,這是在執行靜態方法裝飾的一個真正的錯誤,和/或是否有任何簡單的解決方法?我確實想過寫一個裝飾器來設置一個__call__屬性,但我不知道callable是如何實現的,所以我無法評估這種方法的成功。

+0

請注意,您必須使用靜態方法的新樣式類才能在實例上調用,因爲它使用了描述符。 – 2011-03-17 21:33:37

+2

要使其工作,只需更改描述符的順序。 – 2011-03-17 21:36:23

回答

4

方法功能。但是staticmethod對象不是。它們是descriptors,所以當你以Cls.static_method的身份訪問它時會有額外的魔法,但是當你在Cls的主體內使用static_method時,這個魔法無法隱藏任何東西(即傳遞給裝飾器)。你無法解決這個問題,至少不夠乾淨。一個更簡單的解決方案是重新排序裝飾器,使staticmethod最後得到應用 - 即將它放置在頂部,高於所有其他裝飾器。

+0

啊,這是有道理的。謝謝。 – 2011-03-17 21:37:34

4

那麼,你是否認爲這是一個錯誤或不是,它是documented

靜態方法對象提供 函數對象的轉變擊敗至方法的對象的方式上述 。靜態方法 對象是圍繞任何其他對象的包裝,通常是用戶定義的方法 對象。當從一個類或一個類 實例中檢索到的靜態方法對象是 時,實際返回的對象 是被包裝的對象,它不受 的約束,可以進行任何進一步轉換。 靜態方法對象不是 本身可以調用,儘管它們通常包裝的對象是 。靜態 方法對象由 內置的staticmethod()構造函數創建。

0

我寫了我自己實現的staticmethod可調用,這似乎很好地解決了這個問題。

class staticmethod(object): 
    """Make @staticmethods play nice with @memoize.""" 

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

    def __call__(self, *args, **kwargs): 
     """Call the static method with no instance.""" 
     return self.func(*args, **kwargs) 

這不使用描述協議,這樣的行爲非常不同的比內部的內置staticmethod,但在實踐中,使可調用的函數爲類的屬性,實例屬性,甚至是功能屬性(即,如果你已經在裝飾函數中包裝了你的類,靜態方法的這個實現仍然允許你把你的靜態方法作爲包裝函數的屬性)。