Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pythonic way to maintain variable assignment

I was writing a small file utility earlier, and ran into an issue with passing by reference. After reading How do I pass a variable by reference?, I set the variable I wanted to pass through as an argument and also as the return value. Within the code below, it is the line:

diff = compareDir(path0, path0List, path1, path1List, diff)

where diff is the variable I wished to pass by reference.

While this works, it feels rather awkward. I think there must be a better way. In many other languages, I could just set compareLists() to have no return value, and use the side-effect of modifying the pass-by-reference argument. Python's pass-by-assignment seems to disallow this.

I am relatively new to python, and would like to know if there is a more pythonic way to resolve my issue. Would it require rethinking the functions entirely? Or is there a nice statement I am unaware of? I'd like to stay away from global variables.

I welcome any and all constructive criticisms and comments. Thanks!

Relevant Code:

def comparePaths(path0, path1):
    path0List = os.listdir(path0)
    path1List = os.listdir(path1)

    diff = False
    diff = compareDir(path0, path0List, path1, path1List, diff)
    print()
    diff = compareDir(path1, path1List, path0, path0List, diff)
    return diff

def compareDir(basePath, baseList, comparePath, compareDir, diffVar):
    for entry in baseList:
        #compare to the other folder
        if (not (entry in compareDir)):
            if (not (diffVar)):
                diffVar = True
                print ("Discreptancies found. The following files are different:")
                print (str(entry) + " doesn\'t exist in " + str(comparePath))
            else:
                print (str(entry) + " doesn\'t exist in " + str(comparePath))
    return diffVar
like image 611
Grey_Ham Avatar asked Dec 18 '15 05:12

Grey_Ham


2 Answers

Since in Python, the bool type is by definition immutable, the only way to modify a bool variable inside a function without reassigning it (and without defining it as a global variable) is to store it in a mutable type instance. ie:

  • Storing it in a mutable data structure (list, dict, ...) and pass this data structure to the function.
  • Having it as an attribute of a mutable object, and pass this object to the function.
like image 104
Dim' Avatar answered Oct 06 '22 01:10

Dim'


Your problem has multiple possible solutions.

You can add nonlocal modifier (global prior to python3) for your diff variable to modify from inside function and have changes visible from outside.

    diff = False

    def compareDir(basePath, baseList, comparePath, compareDir):
        nonlocal diff
        for entry in baseList:
                    ...
                    diff = True

    compareDir(path0, path0List, path1, path1List)
    print()
    compareDir(path1, path1List, path0, path0List)
    return diff

Or you can have OOP solution with differ object and self.diff as explicit state of that object.

class differ(object):
    def __init__(self):
        self.diff = False
    def compareDir(self, basePath, baseList, comparePath, compareDir):
        ...
              self.diff = True
        ...

    def comparePaths(self, path0, path1):

Latter solution is super helpful if you need to do a lot of work in some 'context' and frequently need to change shared state.

like image 36
hamilyon Avatar answered Oct 06 '22 01:10

hamilyon