我有一个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 :(得分: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或更高版本,则可以查看新.__wrapped__
属性是否存在.pretty_status
属性{1}}方法;它是对原始包装函数的引用。
在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"
您可以做的最后一件事是测试该包装函数;它将具有您可以测试的.__name__
属性。该名称可能不是唯一的,但它是一个开始。
在上面的示例装饰器中,包装函数被称为wrapper
,因此pretty_status.__name__ == 'wrapper'
将为True。
答案 1 :(得分: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 :(得分: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