简体   繁体   中英

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 (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?

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

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.

From the Zen of Python (ie 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).

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

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM