Clear list inside decorator from global scope

Question:

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.

Asked By: Yurii

||

Answers:

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']
Answered By: Fractalism

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.

Answered By: chepner

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']
Answered By: Ed Brook
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.