2011-09-22 47 views
0

Python isinstance函數如何在內部工作?有什麼我可以做的改變它的結果,比如在一個類裏面定義一個特殊的函數?這是我的使用情況:使'isinstance'與裝飾器一起工作

class Decorator: 
    def __init__(self, decorated): 
     self._decorated = decorated 

    def __call__(self): 
     return self._decorated() 

@Decorator 
class Foo: 
    pass 

f = Foo() 

# How can I make this be true? 
isinstance(f, Foo) 

Decorator行爲幾乎像一個mixin,除了混合是不恰當的位置。有什麼辦法可以讓上面的代碼工作?我還要指出的是,isinstance線還提供了以下錯誤:

    isinstance(f, Foo)
TypeError: isinstance() arg 2 must be a type or tuple of types

+3

什麼是你真正想實現這個? –

+0

你還沒有告訴我們你的裝飾器做了什麼,所以很難知道什麼會起作用。考慮使用裝飾器更改類本身的屬性,然後返回類,或者用元類而不是裝飾器重寫該類。 – agf

回答

1

問題是您示例中的Foo不是類。

此代碼:

@Decorator 
class Foo: 
    pass 

相當於:

class Foo: 
    pass 
Foo = Decorator(Foo) 

這意味着FooDecorator類的一個實例。因爲Foo不是分類或類型,isinstance抱怨。

+1

這隻能解決他的「還應該注意」,它不會告訴他如何使isinstance正常工作。 – agf

4
如何

瞭解以下信息:

def Decorator(decorated): 
    class Dec(decorated): 
     def __call__(self): 
      print 'in decorated __call__' 
      return decorated.__call__(self) 
    return Dec 

@Decorator 
class Foo(object): 
    def __call__(self): 
     print 'in original __call__' 

f = Foo() 

# How can I make this be true? 
print isinstance(f, Foo) 

與上面的代碼:

  • isinstance(f, Foo)作品;
  • f()調用裝飾方法,然後轉發到原始方法。

的基本思路是,以確保裝飾Foo仍然是一個類,也確保裝飾Foo是原始Foo

P.S.這一切的目的並不完全清楚,元類可能是實現你想要做的更好的方法。

0

無法調用Foo而無法獲取Foo返回的對象的類型。

isinstance抱怨它的第二個參數,因爲它是一個實例 - 在你的情況下,實例爲Decorated。儘管你認爲Foo就像一個類,但實際上它只是一個可調用的對象,它不是一個類。

也許下一個會幫助你重新審視/解決您的問題:

>>> isinstance(f, Foo._decorated) 
True 
0

當裝飾類,它往往用於裝飾的返回值也是類型可用或需要的;實現這個最明顯的方法是讓裝飾器構造並直接返回一個新類。

該功能已經由元類處理;事實上,元類比裝飾器更強大一點,因爲在構造完裝飾類之前,你需要描述新類。

另一種選擇是返回傳入的同一個對象;但有一些變化。這對裝飾器來說更好用,因爲當你嵌套裝飾器時它效果很好。既然你正在修改的行爲當使用Foo(),那麼你可能要修改Foo的__init__,這可能是這樣的:

>>> def Decorator(cls): 
...  assert isinstance(cls, type) 
...  try: 
...   old_init = cls.__init__.im_func 
...  except AttributeError: 
...   def old_init(self): pass 
...  def new_init(self): 
...   # do some clever stuff: 
...   old_init(self) 
...  cls.__init__ = new_init 
...  return cls 
... 
>>> @Decorator 
... class Foo(object): 
...  def __init__(self): pass 
... 
>>> @Decorator 
... class Bar(object): 
...  pass 
... 
>>> f = Foo() 
>>> isinstance(f, Foo) 
True