2009-05-02 50 views
2

比方說,我們已經有了一個元類CallableWrappingMeta該走了一類新的身體,包裹它的方法與一類,InstanceMethodWrapper作爲實例方法調用?

import types 

class CallableWrappingMeta(type): 
    def __new__(mcls, name, bases, cls_dict): 
     for k, v in cls_dict.iteritems(): 
      if isinstance(v, types.FunctionType): 
       cls_dict[k] = InstanceMethodWrapper(v) 
     return type.__new__(mcls, name, bases, cls_dict) 

class InstanceMethodWrapper(object): 
    def __init__(self, method): 
     self.method = method 
    def __call__(self, *args, **kw): 
     print "InstanceMethodWrapper.__call__(%s, *%r, **%r)" % (self, args, kw) 
     return self.method(*args, **kw) 

class Bar(object): 
    __metaclass__ = CallableWrappingMeta 
    def __init__(self): 
     print 'bar!' 

我們的虛擬包裝只是打印參數,因爲他們進來,但你會注意到一些明顯的問題:該方法沒有通過實例對象接收器,因爲儘管InstanceMethodWrapper是可調用的,但它不會被視爲用於在創建類時轉換爲實例方法的函數(在我們的元類爲用它完成)。

一個潛在的解決方案是使用裝飾器而不是類來包裝方法 - 該函數將成爲一個實例方法。但在現實世界中,InstanceMethodWrapper要複雜得多:它提供了一個API併發布了方法調用事件。一個類更方便(並且性能更高,並不是這很重要)。

我也嘗試了一些死衚衕。子類types.MethodTypetypes.UnboundMethodType沒有去任何地方。有點內省,看起來他們從type減少。所以我嘗試使用這兩個作爲元類,但也沒有運氣。這可能是他們作爲一個元類有特殊需求的情況,但是現在看來我們現在處於無證的領域。

任何想法?

+0

你能解釋一下嗎?我無法理解你想要做什麼。 – Unknown 2009-05-03 01:24:46

回答

3

只是豐富你InstanceMethodWrapper類與__get__(可完美也只是return self) - 也就是說,使該類成描述類型,因此它的實例是描述對象。有關背景和細節,請參閱http://users.rcn.com/python/download/Descriptor.htm

順便說一句,如果你使用的是Python 2.6或更高版本,請考慮使用類裝飾器而不是該元類 - 我們添加類裝飾器正是因爲如此多的元類僅用於裝飾目的,而裝飾器是真的使用起來更簡單。

0

編輯:我再說謊。功能上的__?attr__屬性是隻讀的,但在分配時顯然不會總是拋出異常AttributeException。我不知道。回到原點!

編輯:這實際上沒有解決問題,因爲包裝功能不會將屬性請求代理到InstanceMethodWrapper。當然,我可以在裝飾器中打上__?attr__屬性 - 這就是我現在正在做的 - 但這很醜陋。更好的創意非常受歡迎。


當然,我馬上意識到,結合我們班一個簡單的裝飾就可以了:

def methodize(method, callable): 
    "Circumvents the fact that callables are not converted to instance methods." 
    @wraps(method) 
    def wrapper(*args, **kw): 
     return wrapper._callable(*args, **kw) 
    wrapper._callable = callable 
    return wrapper 

然後你在元類的裝飾添加到調用InstanceMethodWrapper

cls_dict[k] = methodize(v, InstanceMethodWrapper(v)) 

Poof。有點斜,但它的作品。

0

我猜你正在嘗試使用自定義函數來包裝類中的每個方法的元類。

這是我的版本,我認爲它有點偏斜。

import types 

class CallableWrappingMeta(type): 
    def __new__(mcls, name, bases, cls_dict): 
     instance = type.__new__(mcls, name, bases, cls_dict) 
     for k in dir(instance): 
      v = getattr(instance, k) 
      if isinstance(v, types.MethodType): 
       setattr(instance, k, instanceMethodWrapper(v)) 

     return instance 

def instanceMethodWrapper(function): 
    def customfunc(*args, **kw): 
     print "instanceMethodWrapper(*%r, **%r)" % (args, kw) 
     return function(*args, **kw) 
    return customfunc 

class Bar(object): 
    __metaclass__ = CallableWrappingMeta 

    def method(self, a, b): 
     print a,b 

a = Bar() 
a.method("foo","bar") 
0

我認爲你需要對你的問題更加具體。原來的問題是關於包裝一個功能,但是你後來的回答似乎是談論保留功能屬性,這似乎是一個新的因素。如果你更清楚地闡明瞭你的設計目標,那麼回答你的問題可能會更容易。