我有 2 个现有的装饰器可以在 python 中运行,@property 和 @safe_property。这些装饰器无法更改,并且它们是我无权访问的代码的一部分。
def safe_property(original_property):
def wrap(self):
try:
return original_property(self)
except AttributeError as e:
pass
return wrap
class MyClass(object):
def __init__(self):
pass
@property
@safe_property
def do_func(self):
print("inside do_func!")
return [2,3,4]
通过调用函数:
a = MyClass()
print(a.do_func)
输出对我有好处!:
inside do_func!
[2, 3, 4]
现在,另一个功能出现了,我正在尝试根据(可选)附加参数过滤掉do_func的一些返回值。这意味着某些用户可以像往常一样继续工作并调用:
print(a.do_func)
虽然其他人可以使用过滤器进行调用:
print(a.do_func(True))
为了尝试这个,我创建了另一个名为 my_decorator 的装饰器,例如:
def my_decorator(*args, **kwargs):
print(args)
print(kwargs)
def wrapper(*args):
print(args)
if args[1] == True:
return
# how do I return filter?
else:
return #without the filter?
return wrapper
class MyClass(object):
def __init__(self):
pass
@my_decorator
@property
@safe_property
def do_func(self):
print("inside do_func!")
return [2,3,4]
此功能的当前输出是:
(<property object at 0x02AF0090>,)
{}
(<__main__.MyClass object at 0x00BCDBB0>, True)
None
如何仅过滤返回列表中的奇数 ** 例如,**: do_func?
谢谢
最佳答案
您正在将装饰器应用到 @property
装饰器的输出。该装饰器生成 property()
object ,不是函数。这是因为装饰器是从函数定义向外应用的;看我的answer on decorator execution order ;因此首先应用 @safe_property
,然后应用 @property
,然后应用 @my_decorator
。
如果你想装饰 getter 函数,请将装饰器放在 def
语句的正上方,它将首先执行,并且装饰器返回的任何内容都将传递给 safe_property( )
装饰器(添加自己的包装函数):
@property
@safe_property
@my_decorator
def do_func(self):
print("inside do_func!")
return [2,3,4]
或者,由于 @safe_property
也会生成一个适合作为 getter 函数的包装函数,您可以将装饰器放在 @safe_property
和 @ 之间property
行来包装包装函数返回的前者:
@property
@my_decorator
@safe_property
def do_func(self):
print("inside do_func!")
return [2,3,4]
无论哪种方式,你的装饰器包装器都会传递可调用对象来装饰,并且应该返回一个替换。属性 getter 只接受 self
,您的替换也将使用 self
调用,并且没有其他参数:
def my_decorator(func):
def wrapper(self): # a replacement getter function, so only self is passed in
result = func(self) # call the original getter
if self.some_flag: # you can access the instance in the wrapper
# return only odd values from the getter
return [i for i in result if i % 2]
else:
# otherwise return the values unchanged
return result
return wrapper
将 @my_decorator
放在顶部是装饰 property()
对象,而不是函数,因此您需要专门处理传递这样的对象(您可以在 an answer I wrote before 中了解 @property
装饰器的工作原理)。
例如您可以从 property().fget
属性提取 getter,然后返回适当的替换对象(这将是另一个 property()
对象):
def my_decorator(prop):
getter = prop.fget
def wrapper(self): # a replacement getter function, so only self is passed in
result = getter(self) # call the original getter, taken from the property
if self.some_flag: # you can access the instance in the wrapper
# return only odd values from the getter
return [i for i in result if i % 2]
else:
# otherwise return the values unchanged
return result
# return a new property object, with the wrapper as the getter function
# and copying across all other property attributes
return property(wrapper, prop.fset, prop.fdel, prop.doc)
请注意,属性 getter
函数只能传递 self
,属性 getter 没有其他参数。
但是,直接处理 property
对象并不比将装饰器放置在低一行上有任何优势,它只会使事情变得复杂,因为必须添加 prop.fget
引用和 property(...)
返回值。
关于Python,如何添加另一个装饰器来过滤具有Python属性的现有多重装饰器的输出?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55951832/