2013-11-26 40 views
2

任何人都可以解釋爲什麼下面的代碼不起作用?我試圖讓一個類裝飾器提供新的方法__repr____init__,如果我用它裝飾一個類,只有方法似乎被定義。我設法通過使裝飾者破壞性地修改原始類而不是創建新類(例如,它定義新方法,然後僅使用cl.__init__ = __init__來覆蓋它們)來修復原始問題。現在我只是好奇爲什麼基於子類的嘗試不起作用。Python中的高階類

def higherorderclass(cl): 
    @functools.wraps(cl) 
    class wrapped(cl): 
     def __init__(self, *args, **kwds): 
      print 'in wrapped init' 
      super(wrapped, self).__init__(*args, **kwds) 
     def __repr__(self): 
      return 'in wrapped repr' 
    return wrapped 
+1

對於初學者來說,'@ functools.wraps()'適用於*功能裝飾*只。 –

回答

4

第一個問題是您使用的是舊式類。 (也就是說,不從object繼承的類,另一種內置類型或另一種新式類。)特殊方法查找在舊式類中的工作方式不同。真的,你不想學習它是如何工作的;只是使用新式類。

但是,然後你遇到下一個問題:functools.wraps不起作用的類首先。隨着新式課程,你會得到某種AttributeError;用舊式的課程,事情會以各種方式默默地失敗。而且你不能明確使用update_wrapper。問題在於你試圖替換不可寫的類的屬性,並且沒有(直接的)方法。

如果您使用新式班級,並且不嘗試wraps他們,一切工作正常。

+0

你怎麼知道輸入是舊式的? – user2357112

+0

謝謝!有什麼我應該手動改變來提供像functools.wraps提供的類似的內省行爲,或者是否足夠子類化? –

+0

@ user2357112:我可以告訴,因爲我碰巧知道(而且我不知道爲什麼),否則OP會得到'AttributeError'異常並且不會問這個問題。 (如果他真的向我們展示了他的課程會更好,但他很幸運。) – abarnert

3

刪除@functools.wraps()修飾符,這僅適用於函數修飾符。隨着newstyle類的裝飾失敗:

>>> @higherorderclass 
... class Foo(object): 
...  def __init__(self): 
...   print 'in foo init' 
... 
Traceback (most recent call last): 
    File "<stdin>", line 2, in <module> 
    File "<stdin>", line 3, in higherorderclass 
    File "/Users/mj/Development/Library/buildout.python/parts/opt/lib/python2.7/functools.py", line 33, in update_wrapper 
    setattr(wrapper, attr, getattr(wrapped, attr)) 
AttributeError: attribute '__doc__' of 'type' objects is not writable 

沒有@functools.wraps()線你的裝飾工作得很好:

>>> def higherorderclass(cl): 
...  class wrapped(cl): 
...   def __init__(self, *args, **kwds): 
...    print 'in wrapped init' 
...    super(wrapped, self).__init__(*args, **kwds) 
...   def __repr__(self): 
...    return 'in wrapped repr' 
...  return wrapped 
... 
>>> @higherorderclass 
... class Foo(object): 
...  def __init__(self): 
...   print 'in foo init' 
... 
>>> Foo() 
in wrapped init 
in foo init 
in wrapped repr