Python:静态变量装饰器 [英] Python: static variable decorator

查看:187
本文介绍了Python:静态变量装饰器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想创建一个如下的装饰器,但是我似乎无法想到一个可行的实现.我开始认为这是不可能的,但我想我先问你们.

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 you guys first.

我意识到还有其他各种方法可以在Python中创建静态变量,但是我发现这些方法很难看.如果可能的话,我真的很想使用以下语法.

I realize there's various other ways to create static variables in Python, but I find those ways ugly. I'd really like to use the below syntax, if possible.

@static(x=0)
def f():
    x += 1
    print x

f() #prints 1
f() #prints 2

我不在乎static的实现是长的还是可破解的,只要它能像上面那样工作即可.

I don't care if the implementation of static is long or hackity, as long as it works like above.

我创建了这个版本,但是它只允许使用<function>.<varname>语法,而使用较长的函数和变量名会很快变得麻烦.

I created this version, but it only allows a <function>.<varname> syntax, which gets cumbersome pretty quickly with longer function and variable names.

def static(**assignments):
    def decorate(func):
        for var, val in assignments.items():
            setattr(func, var, val)
        return func
    return decorate

我想到但无法上班的各种事情是:

Various things I thought of, but couldn't get to work were:

  1. 将f(修饰的函数)更改为可调用的类,并以某种方式透明地将静态vars存储在self中.
  2. 在装饰器内部修改f()的全局变量,并以某种方式将"global x"语句插入f的代码中.
  3. 将f更改为生成器,我们在其中手动绑定变量,然后直接执行f的代码.
  1. Changing f (the decorated function) into a callable class, and somehow storing the static vars in self transparently.
  2. Modifying the globals of f() inside the decorator, and somehow inserting 'global x' statements into the code for f.
  3. Changing f into a generator where we bind the variables by hand and then execute f's code directly.

推荐答案

这是一个看起来有效的装饰器. 请注意,由于无法从外部设置本地语言,这需要在函数末尾返回locals()(我没有太多的编程经验,所以如果有办法,我也不知道).

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()

输出为:

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

我在 http://code.activestate.com/recipes/410698/,并决定尝试将其添加到此.现在可以正常使用了.

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

再次更改为使其更快几秒钟. 编辑3;改为功能而不是类

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

已测试:

@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)

输出:

Timeit static function: 5.10412869535
Timeit global variable: 0.242917510783

使用settrace会大大降低它的速度.

Using settrace slows it down quite drastically.

这篇关于Python:静态变量装饰器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆