What is the Python equivalent of static variables

2019-09-10 07:16发布

What is the idiomatic Python equivalent of this C/C++ code?

void foo()
{
    static int counter = 0;
    counter++;
    printf("counter is %d\n", counter);
}

specifically, how does one implement the static member at the function level, as opposed to the class level? And does placing the function into a class change anything?

标签: python
27条回答
家丑人穷心不美
2楼-- · 2019-09-10 07:45

One could also consider:

def foo():
    try:
        foo.counter += 1
    except AttributeError:
        foo.counter = 1

Reasoning:

  • much pythonic (ask for forgiveness not permission)
  • use exception (thrown only once) instead of if branch (think StopIteration exception)
查看更多
可以哭但决不认输i
3楼-- · 2019-09-10 07:45

This answer builds on @claudiu 's answer.

I found that my code was getting less clear when I always had to prepend the function name, whenever I intend to access a static variable.

Namely, in my function code I would prefer to write:

print(statics.foo)

instead of

print(my_function_name.foo)

So, my solution is to :

  1. add a statics attribute to the function
  2. in the function scope, add a local variable statics as an alias to my_function.statics
from bunch import *

def static_vars(**kwargs):
    def decorate(func):
        statics = Bunch(**kwargs)
        setattr(func, "statics", statics)
        return func
    return decorate

@static_vars(name = "Martin")
def my_function():
    statics = my_function.statics
    print("Hello, {0}".format(statics.name))

Remark

My method uses a class named Bunch, which is a dictionary that supports attribute-style access, a la JavaScript (see the original article about it, around 2000)

It can be installed via pip install bunch

It can also be hand-written like so:

class Bunch(dict):
    def __init__(self, **kw):
        dict.__init__(self,kw)
        self.__dict__ = self
查看更多
你好瞎i
4楼-- · 2019-09-10 07:48

However, this is a quiet old post, as I have got a different idiomatic objective, I put the following:

In a function, I want to initialize a variable only once by a calculated value which may be a bit costly.

As I love nice-writing, and being an old C-style programmer. I tried to define a macro-like writing:

def  Foo () :
    StaticVar( Foo, ‘Var’, CalculateStatic())
    StaticVar( Foo, ‘Step’, CalculateStep())
    Foo.Var += Foo.Step
    print(‘Value of Var : ‘, Foo.Var)

Then, I wrote ‘StaticVar’ like this:

def StaticVar(Cls, Var, StaticVal) :
    if not hasattr(Cls, Var) :
        setattr(Cls, Var, StaticVal)

Even nicer in Python :

def StaticVars(Cls, **Vars) :
    for Var, StaticVal in Vars.items() :
        if not hasattr(Cls, Var) :
            setattr(Cls, Var, StaticVal)

def  Foo () :
    StaticVars( Foo, Var = CalculateStatic(),Step= CalculateStep()))
    Foo.Var += Foo. Step
    print(‘Value of Var : ‘, Foo.Var)

This is a nice way to write, but my objective (only one call of initialization functions) is not met (just add a print in the initialization function) ! The fact is that, in a function call, the parameter value is evaluated before the function is called.

def CalculateStatic() :
    print("Costly Initialization")
    return 0

To meet my objective, I’d rather write:

def  Foo () :
    if not hasattr(Foo, ‘Var’) :
        setattr ( Foo, ‘Var’, CalculateStatic())
        setattr ( Foo, ‘Step’, CalculateStep())

    Foo.Var += Foo. Step
    print(‘Value of Var : ‘, Foo.Var)

If Python had had 'Marcro preprocessing', it would be nicer..

查看更多
登录 后发表回答