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

前端 未结 26 2774
天命终不由人
天命终不由人 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:31

    A static variable inside a Python method

    class Count:
        def foo(self):
            try: 
                self.foo.__func__.counter += 1
            except AttributeError: 
                self.foo.__func__.counter = 1
    
            print self.foo.__func__.counter
    
    m = Count()
    m.foo()       # 1
    m.foo()       # 2
    m.foo()       # 3
    
    0 讨论(0)
  • 2020-11-22 01:33

    A little bit more readable, but more verbose (Zen of Python: explicit is better than implicit):

    >>> def func(_static={'counter': 0}):
    ...     _static['counter'] += 1
    ...     print _static['counter']
    ...
    >>> func()
    1
    >>> func()
    2
    >>>
    

    See here for an explanation of how this works.

    0 讨论(0)
  • 2020-11-22 01:33
    _counter = 0
    def foo():
       global _counter
       _counter += 1
       print 'counter is', _counter
    

    Python customarily uses underscores to indicate private variables. The only reason in C to declare the static variable inside the function is to hide it outside the function, which is not really idiomatic Python.

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

    Use a generator function to generate an iterator.

    def foo_gen():
        n = 0
        while True:
            n+=1
            yield n
    

    Then use it like

    foo = foo_gen().next
    for i in range(0,10):
        print foo()
    

    If you want an upper limit:

    def foo_gen(limit=100000):
        n = 0
        while n < limit:
           n+=1
           yield n
    

    If the iterator terminates (like the example above), you can also loop over it directly, like

    for i in foo_gen(20):
        print i
    

    Of course, in these simple cases it's better to use xrange :)

    Here is the documentation on the yield statement.

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

    Using an attribute of a function as static variable has some potential drawbacks:

    • Every time you want to access the variable, you have to write out the full name of the function.
    • Outside code can access the variable easily and mess with the value.

    Idiomatic python for the second issue would probably be naming the variable with a leading underscore to signal that it is not meant to be accessed, while keeping it accessible after the fact.

    An alternative would be a pattern using lexical closures, which are supported with the nonlocal keyword in python 3.

    def make_counter():
        i = 0
        def counter():
            nonlocal i
            i = i + 1
            return i
        return counter
    counter = make_counter()
    

    Sadly I know no way to encapsulate this solution into a decorator.

    0 讨论(0)
  • 2020-11-22 01:34
    def staticvariables(**variables):
        def decorate(function):
            for variable in variables:
                setattr(function, variable, variables[variable])
            return function
        return decorate
    
    @staticvariables(counter=0, bar=1)
    def foo():
        print(foo.counter)
        print(foo.bar)
    

    Much like vincent's code above, this would be used as a function decorator and static variables must be accessed with the function name as a prefix. The advantage of this code (although admittedly anyone might be smart enough to figure it out) is that you can have multiple static variables and initialise them in a more conventional manner.

    0 讨论(0)
提交回复
热议问题