5

Elegant way to increment a global variable in Python:

This is what I have so far:

my_i = -1
def get_next_i():
    global my_i
    my_i += 1
    return my_i

with generator:

my_iter = iter(range(100000000)) 
def get_next_i():
    return next(my_iter)

with class:

class MyI:
    MyI.my_i = -1
    @staticmethod
    def next():
        MyI.my_i += 1
        return MyI.my_i
  • The first one is long and I don't consider it as a better way to code .
  • The second one is a bit more elegant, but have an upper limit.
  • The third one is long, but at least have no global variable to work with.

What would be the best alternative to those?

The purpose of these functions is to assign a unique number to a specific event in my code. The code is not just a single loop, so using for i in range(...): is not suitable here. A later version might use multiple indices assigned to different events. The first code would require duplication to solve such an issue. (get_next_i(), get_next_j(), ...)

Thank You.

Sandeep
  • 155
  • 1
  • 14
Szabolcs Dombi
  • 5,493
  • 3
  • 39
  • 71
  • 4
    Just use `itertools.count`? – jonrsharpe Sep 10 '16 at 08:41
  • "The third one is long, but at least have no global variable to work with" -- it does still have a global variable, it's just that it's spelled `my_module.MyI.my_i` instead of `my_module.my_i`. For the purpose of worrying about globals being dangerous, a global is something that can be accessed willy-nilly by anyone. None of the potential issues with globals go away just because you move it from the module namespace into a class namespace. You need to address the potential issues instead (or as well). – Steve Jessop Sep 10 '16 at 08:48
  • yes but you won't name your variable as `MyI.my_i` and ruin the functionality of the `next()` method. The first example is bad because writing a `for my_i in range(123):` will ruin the `get_next_i()` function. – Szabolcs Dombi Sep 10 '16 at 08:54
  • @Dombi: Yes, "obviously" `for my_i in range(123:)` at module level re-assigns the global. But point taken: I don't write code like that at module level, but those who do will hit this problem. Those who write `for my_i in xrange(123):` at class level will hit the same problem with `MyI.my_i`, but I grant you that's even rarer. – Steve Jessop Sep 10 '16 at 09:34

2 Answers2

6

As others suggested, itertools.count() is the best option, e.g.

import itertools

global_counter1 = itertools.count()
global_counter2 = itertools.count()
# etc.

And then, when you need it, simply call next:

def some_func():
    next_id = next(global_counter1)

EDIT: Changed global_counter1.next() (which worked only in Python 2) to next(global_counter1), which works also in Python 3.

zvone
  • 18,045
  • 3
  • 49
  • 77
4

You can create a generator that has an infinite loop. Each call of next(generator) will return a next value, without limit. See What does the "yield" keyword do in Python?

def create_generator()
    i=0
    while True:
        i+=1
        yield i

generator = create_generator()
print(next(generator))
print(next(generator))
Community
  • 1
  • 1
James K
  • 3,692
  • 1
  • 28
  • 36