在python中发现修饰类实例方法

在python中发现修饰类实例方法,python,reflection,decorator,python-decorators,Python,Reflection,Decorator,Python Decorators,我有一个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)

我有一个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)

编辑: 还请注意,所讨论的装饰师是定制/可修改的。

一般来说,您不能。decorator只是应用callable的语法糖。在您的情况下,decorator语法转换为:

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
返回的内容本身已经过修饰,并且您使用的是Python 3.2或更高版本,那么您可以查看新的
.pretty\u status
方法上是否有
;它是对原始包装函数的引用

在早期版本的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"
您可以做的最后一件事是测试包装器函数;它将有一个
\uuuu name\uuuu
属性,您可以对其进行测试。这个名字可能不是唯一的,但这是一个开始


在上面的示例decorator中,包装器函数被称为
wrapper
,因此
pretty\u status.\uu\u name\uu=='wrapper'
将为True。

您不能直接发现它们,但可以使用一些标志标记装饰方法

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

    wrapper._serializable = True
    return wrapper
然后,您可以使元类例如分析
\u serializable
属性的存在或不存在

或者你也可以在decorator中收集所有包装的方法

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

    DECORATED[func.__name__] = wrapper
    return wrapper

如果您无法控制装饰器的工作,那么一般来说,您无法识别装饰方法

但是,由于您可以修改可序列化的
,因此可以向包装函数添加一个属性,稍后可以使用该属性来标识序列化方法:

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>)
('pretty_status',)

您可以修改装饰器吗,
可序列化的
?当然可以,它是定制的