Python: static variable decorator

前端 未结 8 678

I\'d like to create a decorator like below, but I can\'t seem to think of an implementation that works. I\'m starting to think it\'s not possible, but thought I would ask yo

8条回答
  •  北海茫月
    2021-01-06 16:12

    Here is a decorator that seems to work. Note that this requires return locals() at the end of the function due to being unable to set locals from the outside (I don't have much experience programming so if there is a way, I don't know it).

    class Static(object):
        def __init__(self, **kwargs):
            self.kwargs = kwargs
    
        def __call__(self, f):
            def wrapped_f():
                try:
                    new_kwargs = {}
                    for key in self.kwargs:
                        i = getattr(f, key)
                        new_kwargs[key] = i
                    self.kwargs = new_kwargs
                except:
                    pass
                for key, value in f(**self.kwargs).items():
                    setattr(f, key, value)
            return wrapped_f
    
    @Static(x=0, y=5, z='...')
    def f(x, y, z):
        x += 1
        y += 5
        print x, y, z
        return locals()
    

    The output would be:

    >>> f()
    1 10 ...
    >>> f()
    2 15 ...
    >>> f()
    3 20 ...
    

    EDIT:

    I found something at http://code.activestate.com/recipes/410698/ and decided to try adding it to this. It works without the return now.

    EDIT again: Changed to to make it a few seconds faster. Edit 3; changed to function instead of class

    def static(**kwargs):
        def wrap_f(function):
            def probeFunc(frame, event, arg):
                if event == 'call':
                    frame.f_locals.update(kwargs)
                    frame.f_globals.update(kwargs)
                elif event == 'return':
                    for key in kwargs:
                        kwargs[key] = frame.f_locals[key]
                    sys.settrace(None)
                return probeFunc
            def traced():
                sys.settrace(probeFunc)
                function()
            return traced
        return wrap_f
    

    tested:

    @static(x=1)
    def f():
        x += 1
    
    global_x = 1
    def test_non_static():
        global global_x
        global_x += 1
    
    
    print 'Timeit static function: %s' % timeit.timeit(f)
    print 'Timeit global variable: %s' % timeit.timeit(test_non_static)
    

    output:

    Timeit static function: 5.10412869535
    Timeit global variable: 0.242917510783
    

    Using settrace slows it down quite drastically.

提交回复
热议问题