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?
source to share
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
source to share
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.
source to share
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).
source to share
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
source to share
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
source to share