简体   繁体   中英

What is best: Global Variable or Parameter in this python function?

I have a question about the following code, but i guess applies to different functions. This function computes the maximum path and its length for a DAG, given the Graph, source node, and end node.

To keep track of already computed distances across recursions I use "max_distances_and_paths" variable, and update it on each recursion.

Is it better to keep it as a function parameter (inputed and outputed across recursions) or use a global variable and initialize it outside the function?

How can avoid to have this parameter returned when calling the function externally (ie it has to be outputed across recursions but I dont care about its value, externally)?

a better way than doing: LongestPath(G, source, end)[0:2]??

Thanks

# for a DAG computes maximum distance and maximum path nodes sequence (ordered in reverse).
# Recursively computes the paths and distances to edges which are adjacent to the end node
# and selects the maximum one
# It will return a single maximum path (and its distance) even if there are different paths
# with same max distance
# Input {Node 1: adj nodes directed to Node 1 ... Node N: adj nodes directed to Node N}
# Example: {'g': ['r'], 'k': ['g', 'r']})
def LongestPath(G, source, end, max_distances_and_paths=None):
    if max_distances_and_paths is None:
        max_distances_and_paths = {}
    max_path = [end]
    distances_list = []
    paths_list = []
    # return max_distance and max_path from source to current "end" if already computed (i.e.
    # present in the dictionary tracking maximum distances and correspondent distances)
    if end in max_distances_and_paths:
        return max_distances_and_paths[end][0], max_distances_and_paths[end][1], max_distances_and_paths
    # base case, when end node equals source node
    if source == end:
        max_distance = 0
        return max_distance, max_path, max_distances_and_paths
    # if there are no adjacent nodes directed to end node (and is not the source node, previous case)
    # means path is disconnected
    if len(G[end]) == 0:
        return 0, [0], {"": []}
    # for each adjacent node pointing to end node compute recursively its max distance to source node
    # and add one to get the distance to end node. Recursively add nodes included in the path
    for t in G[end]:
        sub_distance, sub_path, max_distances_and_paths = LongestPath(G, source, t, max_distances_and_paths)
        paths_list += [[end] + sub_path]
        distances_list += [1 + sub_distance]
    # compute max distance
    max_distance = max(distances_list)
    # access the same index where max_distance is, in the list of paths, to retrieve the path
    # correspondent to the max distance
    index = [i for i, x in enumerate(distances_list) if x == max_distance][0]
    max_path = paths_list[index]
    # update the dictionary tracking maximum distances and correspondent paths from source
    # node to current end node.
    max_distances_and_paths.update({end: [max_distance, max_path]})
    # return computed max distance, correspondent path, and tracker
    return max_distance, max_path, max_distances_and_paths

Global variables are generally avoided due to several reasons (see Why are global variables evil? ). I would recommend sending the parameter in this case. However, you could define a larger function housing your recursive function. Here's a quick example I wrote for a factorial code:

def a(m):
    def b(m):
        if m<1:return 1
        return m*b(m-1)
    n = b(m)
    m=m+2
    return n,m
print(a(6))

This will give: (720, 8) . This proves that even if you used the same variable name in your recursive function, the one you passed in to the larger function will not change. In your case, you want to just return n as per my example. I only returned an edited m value to show that even though both a and b functions have m as their input, Python separates them.

In general I would say avoid the usage of global variables. This is because is makes you code harder to read and often more difficult to debug if you codebase gets a bit more complex. So it is good practice.

I would use a helper function to initialise your recursion.

def longest_path_helper(G, source, end, max_distances_and_paths=None):
    max_distance, max_path, max_distances_and_paths = LongestPath(
        G, source, end, max_distances_and_paths
    )
    return max_distance, max_path, max_distances_and_paths

On a side note, in Python it is convention to write functions without capital letters and separated with underscores and Capicalized without underscores are used for classes. So it would be more Pythonic to use def longest_path():

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