gpt4 book ai didi

python - 如何使装饰器有选择地打开或关闭

转载 作者:行者123 更新时间:2023-11-28 21:09:55 29 4
gpt4 key购买 nike

我想问,给定一个带有装饰器的函数,是否可以在不调用装饰器调用的情况下运行该函数?

给定一个函数 foo,是否可以选择打开或关闭它的装饰器?

给定

@decorator
def foo():
//do_somthing

是否可以在关闭 decorator 的情况下运行 foo

可能存在一些函数,您可能希望在有或没有装饰器的情况下运行它。例如(不是一个好的,因为它涉及有效的缓存)在 factorial(n) 函数中关闭基于装饰器的缓存。

我的问题与这个问题类似Optionally use decorators on class methods .它讨论了装饰器打开/关闭(作为 api 公开)的一个很好的应用;

如果我必须使用一个函数,比如 goo 并提供使用或不使用装饰器运行 goo 的选项,我尝试了一种原始的、hackish 的方式来实现这个可选的装饰器开/关切换功能如下:

# this is the decorator class that executes the function `goo`
class deco(object):
def __init__(self, attr):
print "I am initialized"
self.fn = None
# some args you may wana pass
self.attr = attr
# lets say you want these attributes to persist
self.cid = self.attr['cid']
self.vid = 0

def __call__(self, f):
# the call executes and returns another inner wrapper
def wrap(*args):
# this executes main function - see closure
self.fn = f
self.vid = args[0]
self.closure(*args)
return wrap

def closure(self, *args):
n = args[0]
self.cid[n] = self.vid
#goo = deco(fn, attr)
print 'n',n
# executes function `goo`
self.fn(*args)


class gooClass(object):
class that instantias and wraps `goo`around
def __init__(self, attr, deco):
'''
@param:
- attr: some mutable data structure
- deco: True or False. Whether to run decorator or not
'''
self.attr = attr
self.deco = deco

def __call__(self, *args):
if self.deco:
# initiate deco class with passed args
foo = deco(self.attr)
# now pass the `goo` function to the wrapper inside foo.__class__.__call__
foo = foo(self.goo)
return foo(*args)
else:
# execute w/o decorator
return self.goo(*args)

def goo(self, n):
# recursive goo
if n>0:
print 'in goo',n
#print n
# to recurse, I recreate the whole scene starting with the class
# because of this the args in `deco` Class init never persist
too = gooClass(self.attr, self.deco)
return too(n-1)
else: return n


def Fn(n, decoBool):
# this function is where to start running from
attr = {}
cid = [0]*(n+1)
attr['cid'] = cid

#following wud work too but defeat the purpose - have to define again! foo is goo actually
#@deco(attr)
#def foo(n):
# if n>0:
# print 'in foo',n
# #print n
# return foo(n-1)
# else: return n
#return foo(n), attr
# create the gooClass and execute `goo` method instance
foo = gooClass(attr, decoBool)
print foo(n)
return foo



res = Fn(5, True)
print res.attr
print "="*10
res = Fn(5, False)
print res.attr

哪些输出:

I am initialized
n 5
in goo 5
I am initialized
n 4
in goo 4
I am initialized
n 3
in goo 3
I am initialized
n 2
in goo 2
I am initialized
n 1
in goo 1
I am initialized
n 0
None
{'cid': [0, 1, 2, 3, 4, 5]}
==========
in goo 5
in goo 4
in goo 3
in goo 2
in goo 1
0
{'cid': [0, 0, 0, 0, 0, 0]}

这在技术上是可行的,但我认为这是一个自举的 hack。不是 python 。每次都会递归创建一个新类。

问题来了,我在这里找不到一个相关的答案,所以我创建了这个,有没有一种方法可以选择性地打开/关闭装饰器?

最佳答案

在从装饰器返回之前,将未装饰的函数附加到装饰的函数上,如 unwrapped 所说。

例如

def add42(fn):
def wrap(i):
return fn(i) + 42
wrap.unwrapped = fn
return wrap

@add42
def mult3(i):
return i * 3

mult3(1) # 45
mult3.unwrapped(1) # 3

您可以通过将 add42 更改为如下内容,使这种方法适用于类方法(如评论中所要求的):

class add42: 
def __init__(self, clsmethod):
self.classmethod = clsmethod
def __get__(self, instance, cls):
self.unwrapped = self.classmethod.__get__(cls)
return self
def __call__(self, *args):
return self.unwrapped(*args) + 42

并使用它:

class Foo:
@add42
@classmethod
def mult3(cls, i):
return i * 3

Foo.mult3(1) # 45
Foo.mult3.unwrapped(1) # 3

关于python - 如何使装饰器有选择地打开或关闭,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37393287/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com