1

I have two scripts 1 and 2, I would need these two script to work independently from one another, but I also need script 2 to be able to use the function in script 1 if needed. I tried to automate as much as possible, so each script has a number of variables inside already defined.

Here is an oversimplified example of the scrips that I am talking about.

Script 1:

def plustwo(n):
    out = n + 2
    print(out)

m=3
plustwo(m)

Result:
5

Script 2:

from file import plustwo

z=5
plustwo(z)

Result: 
5
7

As you can see, when I import the function from script 1, even if I use from file import plustwo, also the variable is imported, this causes script 2 to return two results, one with variable m (5) and another with variable z (7).

Do I necessarily need to create a third script, identical to script 2 but without the m variable? Is there a way to exclude such variable from the import? (I just want the function from script 2, so that I can use script 1 with the variables it already has.)

martineau
  • 119,623
  • 25
  • 170
  • 301
ArabJohnny
  • 13
  • 3
  • 1
    No, that fundamentally wouldn’t work. Instead, rewrite your modules to separate parts that you want to be usable separately. But you can also use the `if __name__ == '__main__'` idiom to execute code inside a module only if it’s run directly (but not if it’s being loaded as a module). – Konrad Rudolph Apr 06 '22 at 16:13
  • Your scripts need to have all their statements, besides function declarations, put in an `if __name__ == '__main__:` statement, so that no statements will run when you import. Then you can just do `from script1 import plustwo`. There's countless examples of such `main` statements online. – Random Davis Apr 06 '22 at 16:15
  • There is an existing answer [go to this link](https://stackoverflow.com/questions/20309456/call-a-function-from-another-file). I think should answer your question – SOMEONE_14_ Apr 06 '22 at 16:17
  • Thanks a lot for your super quick answer guys! I thought i would have to wait a day or two. I can try straight away! – ArabJohnny Apr 06 '22 at 16:17

2 Answers2

2

In script 1, you can add if __name__ == '__main__':, so that it only executes

m=3
plustwo(m)

if the program is run directly from script1.py.

In the end, you only need to modify script 1 a little bit:

def plustwo(n):
    out = n + 2
    print(out)

if __name__ == '__main__':
    m=3
    plustwo(m)
GGberry
  • 929
  • 5
  • 21
  • This is the right answer; what the OP is asking for is not possible (modules are always completely executed on import), but the end result (`plustwo` isn't invoked on import, just when run as a script) is precisely what the `if __name__ == '__main__':` guard is for (the code under the guard is parsed, but not executed because the check is false). I'd recommend putting the code itself in a `def main():` function (outside the guard), and having the guard be `if __name__ == '__main__': main()`, removing the risk of utility functions inadvertently relying on globals only defined in script mode. – ShadowRanger Apr 06 '22 at 16:24
  • There's also a small performance benefit to running significant code in a function instead of in global scope, but it's obviously meaningless for this little code. – ShadowRanger Apr 06 '22 at 16:26
0

No, it is not.

An import statement will always execute the whole target module the first time it runs. Even when the import is written to cherry pick just a few functions and names from the target file, the file is still executed from the first to last line - this is the way the language works.

The "module object" created in this execution (basically a namespace with all the functions, classes and variables defined globally in the module), is them made available on the sys.modules dictionary. On a second import statement referencing the same file, it will not run again: the cached version is used to pick any function or variables from it.

The practice for when a module file has direct side-effects on itself, and it still desirable that parts of it should be importable, is to put the code that you don't want to execute upon importing in a block that only runs if the automatic variable __name__ contains the string "__main__". Python does that so a module can "know" if a module is running as the main program, or has been imported as part of a greater system.

The idiom for this is ubiquous in Python projects and usually look like:


...

if __name__ == "__main__":
    # this block only runs when the coded is executed as the main program
    m = 3
    plustwo(m)

(This comes, for obvious reasons, at the end of the file, after the function has been defined)

Otherwise, the only possible workaround for that would be to read the module file as a text file, parse and re-generate another source file dynamically, containing only the lines one is interested in, which would then be imported. And even so, the functions or classes imported in this way would not possibly address any other function, class or variable in the same module, of course.

jsbueno
  • 99,910
  • 10
  • 151
  • 209
  • You can just use an import guard to determine if you are being imported or run as the main script – Mad Physicist Apr 06 '22 at 16:22
  • All true, but likely way over the OP's head at this point I'm afraid. – martineau Apr 06 '22 at 16:24
  • yes - I am on a bad day, and just missed that the OP probably just needs the `if __name__ == '__main__'` pattern. I had edited the answer to contain that, but kept the paragraph with the "out of this world" way, nonetheless. – jsbueno Apr 06 '22 at 16:26
  • 1
    Yes, i just needed that bit, but thanks nonetheless for the info! I'm pretty new to python – ArabJohnny Apr 06 '22 at 16:35