2009-04-15 102 views
4

我正在爲必須檢查父方法(在裝飾類的父類中同名的方法)編寫方法的裝飾器。從裝飾器訪問擁有裝飾方法的類

例(從PEP 318第四例):

def returns(rtype): 
    def check_returns(f): 
     def new_f(*args, **kwds): 
      result = f(*args, **kwds) 
      assert isinstance(result, rtype), \ 
        "return value %r does not match %s" % (result,rtype) 
      return result 
     new_f.func_name = f.func_name 
     # here I want to reach the class owning the decorated method f, 
     # it should give me the class A 
     return new_f 
    return check_returns 

class A(object): 
    @returns(int) 
    def compute(self, value): 
     return value * 3 

所以我在尋找的代碼代替#我在這裏要輸入...

感謝。

回答

6

由於bobince said it,你不能訪問周圍的類,因爲在調用裝飾器時,該類還不存在。如果您需要訪問類和基地的全部字典,你應該考慮metaclass

__metaclass__

這個變量可以是名,鹼和字典的任何調用接受參數。在創建類時,將使用可調用對象而不是內置類型()。

基本上,我們轉換returns裝飾到的東西,只是告訴元類上做一流的施工某種魔力:

class CheckedReturnType(object): 
    def __init__(self, meth, rtype): 
     self.meth = meth 
     self.rtype = rtype 

def returns(rtype): 
    def _inner(f): 
     return CheckedReturnType(f, rtype) 
    return _inner 

class BaseInspector(type): 
    def __new__(mcs, name, bases, dct): 
     for obj_name, obj in dct.iteritems(): 
      if isinstance(obj, CheckedReturnType): 
       # do your wrapping & checking here, base classes are in bases 
       # reassign to dct 
     return type.__new__(mcs, name, bases, dct) 

class A(object): 
    __metaclass__ = BaseInspector 
    @returns(int) 
    def compute(self, value): 
     return value * 3 

記住,我沒有測試此代碼,請我是否應該發表評論更新這個。

有一些articles on metaclasses由強烈推薦的大衛Mertz,你可能會發現在這方面的有趣。

+0

我沒有直接使用你的代碼,因爲我的問題比我告訴你的更具體。但是,在遍歷* dct *時使用* name *有點奇怪,因爲* name *通常用於* type *構造。謝謝,我認爲無論如何接受你的答案都可以,因爲它對我有很大的幫助。 – Gra 2009-04-16 13:08:27

6

這裏我想達到的類擁有裝飾方法F

你不能因爲在裝修的點,沒有類擁有的方法F.

class A(object): 
    @returns(int) 
    def compute(self, value): 
     return value * 3 

是一樣的話說:

class A(object): 
    pass 

@returns(int) 
def compute(self, value): 
    return value*3 

A.compute= compute 

顯然,之前的功能被分配給所有者類returns()裝飾建成。

現在,當你爲一個類寫入一個函數(內聯或者像這樣顯式)時,它就成爲一個未綁定的方法對象。 現在它有它的主人類,你可以這樣得到一個參考:

>>> A.compute.im_class 
<class '__main__.A'> 

所以,你可以閱讀f.im_class內「new_f」,這是在轉讓之後執行的,而不是在裝飾本身。如果你不需要依靠CPython的實現細節,那麼它有點難看,我不太清楚你想做什麼,但涉及「獲得所有者類」的東西是通常可以使用元類來實現。)