1

I have a situation as follows, I have a relative path that I want to get for a directory. The directory structure is as follows,

Windows Folder Structure

C:\FileFolder\LowerLevel\ThirdLevel\script.py

C:\FileFolder\FolderOfInterest\filesStuff.txt

Linux Structure

PathAbove/LowerLevel/ThirdLevel/script.py

PathAbove/FileFolder/FolderOfInterest/filesStuff.txt


Top Level

args = parse_args(sys.argv[1:])
main(args.filepath, args.repository)

Function Definitions

main(filepath,repopath)
{
//do stuff with filepath, repopath
    do_stuff()
    
}

do_stuff()
   path_to_repo = rel_path()  
   #use path_to_repo 




def rel_path():
    """
    Gets the relative path two directory levels up where FileFolder folder lives
    """
    return os.path.abspath(os.path.join(os.path.dirname( __file__), '../../', 'FileFolder/FolderOfInterest'))

I have been asked to make this more general so I don't have to rely on the FileFolder name being 'FileFolder' in case somebody has it named differently.

I pass in the path directly to repopath at the start, so I could use that since it's validated before use. My usual solution is this

My Usual Solution

Pass repository_path from the top level.

main(args.filepath,args.repository)
    repository_path = args.repository

    do_stuff(repository_path)
        rel_path(repository_path)
    def rel_path(repository_path):
        """
        Gets the relative path two directory levels up where galaxy folder lives
        """
        return os.path.abspath(os.path.join(os.path.dirname( repository_path ), '/FileOfInterest'))

It comes up often that I need to pass in information from a higher level function to a lower level function, usually after I realize that info is needed and I want to refactor something to use it for whatever reason. This requires adding an extra argument to multiple functions and changing functionality slightly. There is actually a third function in-between this in my real code, but this illustrates the issue.

Here is my question

My question is this, is there a best practice for passing in information to a lower level function used only inside another function that isn't called by the main function? Or am I way off base here? Is there any easier way to get the relative path of FolderOfInterest that I'm interested in getting? Typically I have historically programmed in procedural languages and this has come up plenty of times before in the past. But, it also comes up in OOP programming I've done before.

This comes up often enough that I thought it was worth asking here. How do I pass information around without requiring rework of multiple parts of my code when that information is embedded at a higher level than where it needs to be used? I'm trying to make this as agnostic as possible with relative paths, function arguments so it's easier for others to use/modify later, and so people using it don't have to make changes depending on whether they run it on Linux or Windows.

I hope I've written this somewhat clear and this is a useful enough question to be here. I originally had this on stackoverflow, but since it's more about best practices in software engineering, I put it here.

I've marked this as python because that's what I'm writing in, but this comes up just as much in c, matlab, c++, and other languages I've written in that I'm not necessarily tied to the answer being specific to python syntax

2 Answers 2

3

What you present as cumbersome is actually a good thing. If you find some function needs some input after all, the preferred way to provide it would be as an argument. This will both keep your scope tight and document the function: it will be clear what it needs/uses.

Any other way would blow up scope or obscure the dependency or both. It would needlessly require knowledge to understand what the function does.

Candied_orange is saying the same thing in the last paragraph of his answer. I think this is the core issue and thus elaborated on it.

0

When do you know this path?

If we’re talking about a value that doesn’t change during the life of the program and it is known early then an alternative to passing it down as an argument through multiple functions is to wrap it up in a persistent object. Make that persistent object known to other objects and they can tell it to do work for them.

Done this way the path doesn’t get passed around. References do.

This used to just be called reference passing but the kids today are calling it pure dependency injection for some reason.

Another alternative is to go find this info yourself without telling anything that you need it. Such code hides its dependencies and is hard to work with because it knows about the world around it. Which means it breaks when the world changes.

2
  • The path is passed in as an argument at the command line, the parse function, which I didn't show, validates that it's a real path before doing anything else in the program. Commented Jan 15, 2021 at 18:55
  • @HereForTheAnswers Sounds like it qualifies. Commented Jan 15, 2021 at 19:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.