def outer(func):
a = []
def inner():
func()
a.append('work')
print(a)
return inner
@outer
def test():
print('TEST')
test()
test()
# *1
test() # *2
*1 here I want clear list a inside a decorator *2 so here must be a new list a inside outer
Is it posible to clear list a, in global scope? If yes, how do it correct.
CodePudding user response:
It is possible if you define the decorator as a class:
(tested using Python 3.11)
class Outer:
def __init__(self):
self.a = []
def reset(self):
self.a = []
def __call__(self, fn):
def inner():
fn()
self.a.append('work')
print(self.a)
return inner
outer = Outer()
@outer
def test():
print('TEST')
test()
# TEST
# ['work']
test()
# TEST
# ['work', 'work']
print(f'before-reset {outer.a}')
# before-reset ['work', 'work']
outer.reset()
print(f'after-reset {outer.a}')
# after-reset []
test()
# TEST
# ['work']
print(f'after-next test() {outer.a}')
# after-next test() ['work']
CodePudding user response:
a
does not exist at the global scope, rather as the cell_contents
attribute of the first element of test.__closure__
. You can reset it to an empty list, but I don't recommend modifying closures like this.
>>> test()
TEST
['work']
>>> test()
TEST
['work', 'work']
>>> test.__closure__[0].cell_contents = []
>>> test()
TEST
['work']
You should probably instead define a class with a list
-valued instance attribute instead of using a closure.
CodePudding user response:
You can add a parameter to the wrapper function specifying whether to clear a
before/after the original function executes.
def outer(func):
a = []
def inner(clear=False):
func()
a.clear() if clear else a.append('work')
print(a)
return inner
@outer
def test():
print('TEST')
test()
test(clear=True)
# *1
test() # *2
Result:
TEST
['work']
TEST
[]
TEST
['work']