2013-06-26 134 views
3

類的實例方法,我有一個Python類,例如:發現裝飾蟒蛇

class Book(models.Model): 
    enabled  = models.BooleanField(default=False) 
    full_title = models.CharField(max_length=256) 
    alias  = models.CharField(max_length=64) 
    author  = models.CharField(max_length=64) 
    status  = models.CharField(max_length=64) 
    @serializable 
    def pretty_status(self): 
     return [b for a, b in BOOK_STATUS_CHOICES if a == self.status][0] 

的方法pretty_status裝飾有@serializable

什麼是最簡單和最有效的方法來發現類中的方法有一定的裝飾? (在上面的例子中給出:pretty_status)。

編輯: 請注意,有問題的修飾器是自定義/可修改的。

+0

可以修改裝飾器,「可序列化」? – unutbu

+0

當然,這是自定義的 –

回答

2

如果你有在裝飾做什麼,那麼在一般情況下,你無法確定裝修方法無法控制的。

不過,既然你可以修改serializable,那麼你可以將屬性添加到包裝的功能,你可以在以後用它來識別序列化方法:

import inspect 
def serializable(func): 
    def wrapper(self): 
     pass 
    wrapper.serialized = True 
    return wrapper 

class Book: 
    @serializable 
    def pretty_status(self): 
     pass 
    def foo(self): 
     pass 


for name, member in inspect.getmembers(Book, inspect.ismethod): 
    if getattr(member, 'serialized', False): 
     print(name, member) 

產生

('pretty_status', <unbound method Book.wrapper>) 
2

一般來說,你不能。裝飾者只是應用可調用的語法糖。在你的情況下,裝飾語法翻譯爲:

def pretty_status(self): 
    return [b for a, b in BOOK_STATUS_CHOICES if a == self.status][0] 
pretty_status = serializable(pretty_status) 

也就是說,pretty_status由任何serializable()回報代替。它返回的可能是任何東西。現在

,如果有什麼serializable回報本身已經裝飾了functools.wraps(),並且您使用Python 3.2或更高版本,那麼你可以看到,如果沒有對新.pretty_status方法.__wrapped__屬性;它是對原始包裝函數的引用。

在早期版本的Python,你可以很容易地做到這一點自己太:

def serializable(func): 
    def wrapper(*args, **kw): 
     # ... 

    wrapper.__wrapped__ = func 

    return wrapper 

您可以將任意數量的屬性添加到該包裝的功能,包括你自己選擇的自定義屬性:

def serializable(func): 
    def wrapper(*args, **kw): 
     # ... 

    wrapper._serializable = True 

    return wrapper 

,然後測試該屬性:可以

if getattr(method, '_serializable', False): 
    print "Method decorated with the @serializable decorator" 

最後一件事do是爲那個包裝函數測試;它會有一個.__name__屬性,您可以測試。這個名字可能不是唯一的,但它是一個開始。

在上面的示例裝飾器中,包裝函數被稱爲wrapper,因此pretty_status.__name__ == 'wrapper'將爲True。

0

你不能直接發現它們,但你可以用一些標記標記裝飾的方法。

import functools 
def serializable(func): 
    functools.wraps(func) 
    def wrapper(*args, **kw): 
     # ... 

    wrapper._serializable = True 
    return wrapper 

,然後你可以讓元類,例如分析是否存在_serializable屬性。

或者你可以收集所有的包裹方法在庫裝飾

import functools 
DECORATED = {} 
def serializable(func): 
    functools.wraps(func) 
    def wrapper(*args, **kw): 
     # ... 

    DECORATED[func.__name__] = wrapper 
    return wrapper