Python best practices for functions

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 (WAN pass):

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 any general rule exists, but is it widely accepted for a function to access a global variable within a function? or if a variable is only used for a function, then should it be part of a function variable?

+3


source to share


6 answers


The method is often slightly dependent 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 function next()

:

>>> 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 identifiers to be multiples 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 an initial value if you don't want to start at index 0:

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

      

+4


source


If id_constant

indeed persistent, I would do:

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 updated with output 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 can go ahead and implement iteration for the class.

+3


source


From Zen Python (i.e. import this

)

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

      

In general, if you don’t need to put something in the global namespace, it’s better to encapsulate it in the local namespace of the function, so I would consider option 2 as more "pythonic" if it id_constant

will be used by multiple functions.

You can also try the following using the default keyword argument:

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 anything else, you could call the function like id = give_id (id_constant = 500).

+2


source


A global variable is generally what you should avoid.

If you want to have constants, for example for configuration purposes, I would use a more modular approach, like:

conf.py

 MYCONST = 1000

      

app.py

import conf

print conf.MYCONST

      

Or take an OO approach like:

class Test(object):

    def __init__(self):
        self._constant = 1000

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

      

+2


source


Perhaps you need a 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

      

+1


source


A little 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

      

+1


source







All Articles