Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How do i import functions from multiple files that can change in numbers and names in a folder

i want to make a loop that imports every function in every file in a function and use input to run that function i wanted to put the files individially so i can add more of them

right now i only have 1 file callde quit.py with a function inside also called quit:

def quit():
    raise Exception("bye")

in main.py i tried doing this

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

import os 

commands=[]
for file in os.listdir(r"funcs"):
    if file.endswith(".py"):
        commands.append(file)
        file=file[:-3]
        from funcs import file
        

print(commands)

ImportError: cannot import name ‘file’ from ‘funcs’ (unknown location)

>Solution :

file is a variable here.
But import statement doesn’t work with a variable. It takes file literally as meaning "file".
You are certainly used to it. I guess you never wrote import "math", import "numpy" or import "sys", but import math import numpy or import sys.

So you known that the argument is a quoteless string, not an expression.
Exactly as funcs is, btw, in the exact same command: you are expecting funcs to be taken literally (meaning the directory with actual name "funcs", not the directory whose name is given by variable funcs), while expecting file to be taken as an expression (meaning the python file whose name is found in variable file, not the python file with actual name "file.py")

What you could do is call the __import__ function, that behaves more as you would expect

mymod = __import__('funcs', file)

And there, you have another, similar problem.
To call a function from this mymod variable, (say your quit function), you need to call
mymod.quit.quit

The first quit is the file name (the one in variable file). The second, the function name.

I take you have your own idea about how to deal with functions names (you said nothing about it. Tho I suspect you’ll end up with some ugly eval and exec here, since you probably want to know only at runtime the name of those functions to call­ — it looks like you are trying to write a sort of interpreter with dynamically loaded new functions. Unless all files contain always the same function names. But well, let’s focus on the problem you’ve asked a question about, rather than on the one I predict you’ll have afterward).

But you wouldn’t have a way to extract mymod.quit, the module, since, there again, it expect a literal module name (you can’t, like in pandas for example, use alternative syntax mymod['quit'] instead of mymod.quit.

But there is another __ to help (even if, rule of thumb, the more __ you use in a code, the worse the solution, imho. That means we are relying a bit too much on functions supposed to be internal), using __getattribute__ method.

So if the module name is in variable file, the you can get the module itself by

mymod = __import__('funcs', file)
fileMod == mymod.__getattribute__(file)
# Which then allows
fileMod.quit()

And there, we have a 3rd similar problem: you don’t want, probably, to have the module stored in a variable named fileMod, but, as from funcs import quit as quit would have done, into a variable named quit, not file.
You could there (that an awful idea, but, imho, the whole thing is an awful idea. It is probably a XY Problem, and I should probably have asked "what do you really want to do", instead of giving this answer :D) use globals() to create a new global variable whose name is the one in variable file

So altogether

mymod=__import__('funcs', file)
globals()[file] = mymod.__getattribute__(file)
# Then you can call
quit.quit()

Probably a more reasonable solution would be to let all your functions (since, after all, they are all in dir funcs in a single package

import os 

commands=[]
for file in os.listdir(r"funcs"):
    if file.endswith(".py"):
        commands.append(file)
funcs = __import__("funcs", fromlist=commands)
# Then
funcs.quit.quit()

And then call funcs.quit.quit() rather than quit.quit()

Another more reasonable solution would be to use importlib package, that bundle some utility function to call __import__ (but that doesn’t solve any of the 3 mentioned problem. Just, it removes some __)

But I surmise the only reasonable solution is to understand what are you really trying to do, and try to do it in a way that relies less on __ 😀

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading