简体   繁体   English

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

[英]Discover decorated class instance methods in python

I have a python class, for example: 我有一个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]

The method pretty_status is decorated with @serializable . 方法pretty_status@serializable修饰

What is the simplest and most efficient way to discover the methods in a class that have a certain decoration ? 在具有特定装饰的类中发现方法的最简单,最有效的方法是什么? (in the above example giving: pretty_status). (在上面的示例中给出:pretty_status)。

Edit: Please also note that the decorator in question is custom/modifiable. 编辑:请注意有问题的装饰者是自定义/可修改的。

Generally speaking, you can't . 一般来说, 你不能 A decorator is just syntactic sugar for applying a callable. 装饰器只是用于应用可调用语法的语法糖。 In your case the decorator syntax translates to: 在您的情况下,装饰器语法转换为:

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

That is, pretty_status is replaced by whatever serializable() returns. 也就是说, pretty_statusserializable()返回替换。 What it returns could be anything. 它返回的可能是什么。

Now, if what serializable returns has itself been decorated with functools.wraps() and you are using Python 3.2 or newer, then you can see if there is a .__wrapped__ attribute on the new .pretty_status method; 现在,如果可.__wrapped__ serializable返回本身已使用functools.wraps()进行修饰,并且您使用的是Python 3.2或更高版本,则可以查看新的.pretty_status方法是否存在.__wrapped__属性; it's a reference to the original wrapped function. 它是对原始包装函数的引用。

On earlier versions of Python, you can easily do this yourself too: 在早期版本的Python上,您也可以轻松地自己完成:

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

    wrapper.__wrapped__ = func

    return wrapper

You can add any number of attributes to that wrapper function, including custom attributes of your own choosing: 您可以向该包装函数添加任意数量的属性,包括您自己选择的自定义属性:

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

    wrapper._serializable = True

    return wrapper

and then test for that attribute: 然后测试该属性:

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

One last thing you can do is test for that wrapper function; 你能做的最后一件事是测试那个包装函数; it'll have a .__name__ attribute that you can test against. 它将具有您可以测试的.__name__属性。 That name might not be unique, but it is a start. 该名称可能不是唯一的,但它是一个开始。

In the above sample decorator, the wrapper function is called wrapper , so pretty_status.__name__ == 'wrapper' will be True. 在上面的示例装饰器中,包装器函数称为wrapper ,因此pretty_status.__name__ == 'wrapper'将为True。

If you have no control over what the decorator does, then in general, you can not identify decorated methods. 如果你无法控制装饰器的作用,那么一般来说,你无法识别装饰的方法。

However, since you can modify serializable , then you could add an attribute to the wrapped function which you could later use to identify serialized methods: 但是,由于您可以修改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)

yields 产量

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

You can't discover them directly but You can mark decorated methods with some flag. 您无法直接发现它们,但您可以使用某些标记标记装饰方法。

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

    wrapper._serializable = True
    return wrapper

And then You can make metaclass for example analyse presence or absence of _serializable attribute. 然后你可以制作元类例如分析_serializable属性的存在与否。

Or You can collect all wrapped methodsin decorator 或者您可以收集装饰器中的所有包装方法

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

    DECORATED[func.__name__] = wrapper
    return wrapper

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM