What is the Python equivalent of static variables inside a function?

前端 未结 26 2739
天命终不由人
天命终不由人 2020-11-22 00:45

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

void foo()
{
    static int counter = 0;
    counter++;
          


        
相关标签:
26条回答
  • 2020-11-22 01:27

    I write a simple function to use static variables:

    def Static():
        ### get the func object by which Static() is called.
        from inspect import currentframe, getframeinfo
        caller = currentframe().f_back
        func_name = getframeinfo(caller)[2]
        # print(func_name)
        caller = caller.f_back
        func = caller.f_locals.get(
            func_name, caller.f_globals.get(
                func_name
            )
        )
        
        class StaticVars:
            def has(self, varName):
                return hasattr(self, varName)
            def declare(self, varName, value):
                if not self.has(varName):
                    setattr(self, varName, value)
    
        if hasattr(func, "staticVars"):
            return func.staticVars
        else:
            # add an attribute to func
            func.staticVars = StaticVars()
            return func.staticVars
    

    How to use:

    def myfunc(arg):
        if Static().has('test1'):
            Static().test += 1
        else:
            Static().test = 1
        print(Static().test)
    
        # declare() only takes effect in the first time for each static variable.
        Static().declare('test2', 1)
        print(Static().test2)
        Static().test2 += 1
    
    0 讨论(0)
  • 2020-11-22 01:28

    Another (not recommended!) twist on the callable object like https://stackoverflow.com/a/279598/916373, if you don't mind using a funky call signature, would be to do

    class foo(object):
        counter = 0;
        @staticmethod
        def __call__():
            foo.counter += 1
            print "counter is %i" % foo.counter
    

    >>> foo()()
    counter is 1
    >>> foo()()
    counter is 2
    
    0 讨论(0)
  • 2020-11-22 01:30

    Python doesn't have static variables but you can fake it by defining a callable class object and then using it as a function. Also see this answer.

    class Foo(object):
      # Class variable, shared by all instances of this class
      counter = 0
    
      def __call__(self):
        Foo.counter += 1
        print Foo.counter
    
    # Create an object instance of class "Foo," called "foo"
    foo = Foo()
    
    # Make calls to the "__call__" method, via the object's name itself
    foo() #prints 1
    foo() #prints 2
    foo() #prints 3
    

    Note that __call__ makes an instance of a class (object) callable by its own name. That's why calling foo() above calls the class' __call__ method. From the documentation:

    Instances of arbitrary classes can be made callable by defining a __call__() method in their class.

    0 讨论(0)
  • 2020-11-22 01:30

    The idiomatic way is to use a class, which can have attributes. If you need instances to not be separate, use a singleton.

    There are a number of ways you could fake or munge "static" variables into Python (one not mentioned so far is to have a mutable default argument), but this is not the Pythonic, idiomatic way to do it. Just use a class.

    Or possibly a generator, if your usage pattern fits.

    0 讨论(0)
  • 2020-11-22 01:31

    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)
    0 讨论(0)
  • 2020-11-22 01:31

    After trying several approaches I end up using an improved version of @warvariuc's answer:

    import types
    
    def func(_static=types.SimpleNamespace(counter=0)):
        _static.counter += 1
        print(_static.counter)
    
    0 讨论(0)
提交回复
热议问题