3

Approach 1 (global var):

id_constant = 1000
id_cnt = 1
def give_id():
    global id_cnt
    id_cnt += 1
    return id_constant * id_cnt
id = give_id()

Approach 2 (fuc var instead of global var):

id_cnt = 1
def give_id():
    id_constant = 1000
    global id_cnt
    id_cnt += 1
    return id_constant * id_cnt
id = give_id()

Approach 3 (pass in global vars):

id_cnt = 1
id_constant = 1000
def give_id(constant, cnt):
    return constant * cnt
global id_cnt
id_cnt +=1
id = give_id(id_constant, id_cnt)

im not sure if there are any general rule of thumb but is is widely accepted for a function to access a global variable inside a function? or if the variable is only used for a function, then should it be part of a function variable instead?

3
  • 2
    Sometimes it is necessary but in general, in all languages, accessing global variables is bad practice Commented May 29, 2015 at 13:44
  • 1
    Usually less global variables means better code, so try using parameters and return values instead of global variables. What comes to your question, context would help to choose the best method for you. What are you using the ids for? Commented May 29, 2015 at 13:45
  • Don't forget you can use default values in function parameters, as in: def foo(bar=4): \ print bar, which would print 4 if invoked as foo(). Usually that's better for seldom-changing configuration variables because it avoids global (well, module-level actually) variables, and keeps the constant near its use in the code. Commented May 29, 2015 at 13:47

6 Answers 6

4

The method often depends a little on the situation.

You seem to need unique ids, why not use a generator:

def create_id_generator():
    """Returns an id generator."""
    i = 0
    while True:
        yield i
        i += 1

Used with the next() function:

>>> ID_GENERATOR = create_id_generator()  # Global variable
>>> my_id = next(ID_GENERATOR)
>>> my_id2 = next(ID_GENERATOR)
>>> my_id3 = next(ID_GENERATOR)
>>> print(my_id, my_id2, my_id3, next(ID_GENERATOR))
0 1 2 3

If you want the ids to be multiples of 1000, you can pass the constant to the generator via parameters:

def create_id_generator(multiplier=1000):
    """Returns an id generator."""
    i = 0
    while True:
        yield i * multiplier
        i += 1

You can even add a starting value if you don't want to start from index 0:

def create_id_generator(multiplier=1000, start_index=0):
    """Returns an id generator."""
    while True:
        yield start_index * multiplier
        start_index += 1
Sign up to request clarification or add additional context in comments.

Comments

3

If id_constant is actually constant, I would have done:

ID_CONSTANT = 1000

def give_id(id_count):
    return ID_CONSTANT * id_count

id_count = 1

id = give_id(id_count)

But it looks like you also have some state (id_count) that needs to be kept up-to-date with the issuing of id, suggesting a generator function:

def give_id(id_count):
    while True:
        yield ID_CONSTANT * id_count
        id_count += 1

or even a class:

class IdCreator(object):

    ID_CONSTANT = 1000

    def __init__(self, start_count=1):
        self.id_count = start_count

    def give_id(self):
        new_id = self.ID_CONSTANT * self.id_count
        self.id_count += 1
        return new_id

You could go further and implement iteration for the class.

Comments

2

Global variable is generally something you should avoid.

If you want to have constants, for let's say, configuration purposes I would take more a module approach like:

conf.py

 MYCONST = 1000

app.py

import conf

print conf.MYCONST

Or take an OO approach such as:

class Test(object):

    def __init__(self):
        self._constant = 1000

    def give_id(self, cnt):
        return self._constant * cnt

Comments

2

From the Zen of Python (i.e. import this)

Namespaces are one honking great idea -- let's do more of those!

In general, if you don't need to put something in the global namespace, it is better to encapsulate it in the local namespace of the function, so I would consider option 2 to be more "pythonic" unless id_constant is going to be used by multiple functions.

You might also try the following using a keyword argument with a default value:

id_cnt = 1
def give_id(id_constant=1000):
    global id_cnt
    id_cnt += 1
    return id_constant * id_cnt
id = give_id()

Then if you ever needed id_constant to be something different, you could call the function as id = give_id(id_constant=500).

2 Comments

In your current version the function parameter is ignored.
oops! Thanks for the catch
1

A little bit of tricky stuff:

def get_id_func(constant):
    class c(object):
        def __init__(self, constant):
            self.constant = constant
            self.id = 0
        def func(self):
            self.id += 1
            return self.id * self.constant
    o = c(constant)
    return o.func

# create function
f = get_id_func(1000)

# call and test it
assert f() == 1000
assert f() == 2000
assert f() == 3000

Comments

1

Probably you need generator function?

def give_id(id_constant):
    delta = 0
    while True:
        delta += 1
        yield id_constant + delta

for i in range(100):
    print(give_id(1000))  # prints numbers from 1001 to 1100

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.