Taking an input from python file to another - python

I made a file that turns to other files and run their scripts consecutively. Most of these files have a common parameter which is an input. When I import it, it (of course) requests for input. I wish to avoid re-input of something.
Example:
MainFile.py:
import Base_params
import Liner
Base_params.py:
no_of_slices=int(input('Enter no. of Slices'))
sub_slice=int(input('enter sub slice'))
Liner.py:
from PIL import Image
import shutil
from Base_params import no_of_slices, sub_slice

The short answer is that Python handles this for you already exactly the way you want. To understand why, let me give you a little background on the import system.
When a module is imported for the first time, an empty module object is created. Then its code is executed and any names you bind are placed in its dictionary, which is also the global namespace for the module. In your case that would mean running the code of Base_params.py and creating the names no_of_slices and sub_slice based on the user input.
When the same module is imported subsequently, its code is not run (which is your concern). Instead, the object reference from sys.modules is returned. An import statement always checks whether a module is already loaded before attempting to run it again.
The reason that creating the empty module object (and placing it in sys.modules before running the module code is very important is that most modules have recursive imports. Marking the module as already imported ensures that any infinite loops are broken before they happen.
In your case, it is perfectly fine to define a module of constants that asks for user input. The first module that does import Base_params will trigger an execution of the input statements. All further occurrences of import Base_params will just bind sys.modules['Base_params'] to whatever the name Base_params in your namespace. There will not be a second query for no_of_slices and sub_slice.
The links to the official documentation I provided throughout will explain anything I missed.

Related

Python file does not recognize imported functions from other Python files

I'm trying to make my code more organized by creating separate files for various functions. I'm testing out printing scenes of dialogue with a text scrolling code, and instead of keeping every line of dialogue in one file, I have moved it to a scene0.py file in the folder scenes. In that file, I define the function playscene0.
In a different folder called scenetext, I have a file called textstuff.py which contains the defined functions print_italics (which prints italics text), texttype (which makes each character type out individually like some video games do), and textscroll (which reads lists of dialog and formats it, plus timings with time.sleep).
That aforementioned scene0.py file uses from scenetext.textstuff import * to import the above functions, plus additional variables that go along with them (unique to that file). VSCode seems to initially recognize that all the functions being used in the playscene0 function have been successfully imported.
In my importtest file:
from scenes.scene0 import playscene0
playscene0()
This gives me:
NameError: name 'print_italics' is not defined
Though it very much is defined in the file it is derived from.
I've already looked into circular imports and how they cause problems, but that doesn't seem to be the cause here. I've tried importing both time and everything from scenetext.textstuff in the importtest file directly, but the problem persists.
Any suggestions are welcome, thank you
EDIT: After adding from scenetext.textstuff import print_italics to the importtest file, it gives me a different error upon running:
ImportError: cannot import name 'print_italics' from 'scenetext.textstuff' (/Users/[me]/vscode/VOYAGE/scenetext/textstuff.py)
Not sure what causes this.
You need to add an import to the importtest file - from scenetext.textstuff import print_italics, so that the function becomes "visible".
You should import the textstuff functions BEFORE you import the playscene function that uses them
from scenetect.textstuff import print_italics
from scenes.scene0 import playscene0
playscene0()

Why is this python code running twice [duplicate]

This question already has an answer here:
Why Python print my output two times when I import the same file in which I am printing?
(1 answer)
Closed 2 years ago.
Here is the code
import random
print("Hello", end="")
print("twice")
and a screenshot of the code
When I execute this code it for some reason is running twice. The problem seems to be from the import random statement, because if I either remove that statement or import some other module it works fine.
What could be the reason for this, should I reinstall Python on my system.
There's nothing wrong with python.
The reason is simple:
Your module is importing itself (because it is also named random) - this has to do with the lookup mechanics of python. python will try to import from your root folder first, before modules from pythonpath are imported.
From the docs:
When a module named spam is imported, the interpreter first searches for a built-in module with that name. If not found, it then searches for a file named spam.py in a list of directories given by the variable sys.path. sys.path is initialized from these locations:
The directory containing the input script (or the current directory
when no file is specified).
PYTHONPATH (a list of directory names, with the same syntax as the shell variable PATH).
The installation-dependent default.
Since your file (module) is called random.py, import random will import this very file.
Now, what does "import" mean?
The statement import something will cause Python to lookup the name something, starting with the current directory.
Therefore, import random will result in an import of this very file, since its name will shadow the build-in random.
Besides, if the name to import is already in the namespace, then the import statement is ignored.
Once the module to import has been located, its code is executed.
As a result, the flow of your script is as follow:
Lookup the random.py name
Add random to the namespace
Execute the code contained in random.py
The random name already exists in the namespace, so the import random statement is ignored
Print the text
Print the text
The reason for this is you've named the script random.py and inside it you import random.
random will not import the built-in random module but, rather, the random module you've created. This leads to the script executing the same statements twice (and also leads to other ugly errors if you tried and import something from random, like from random import randrange.)
Renaming the script leads to normal behavior.
Because your scripts is called random.py, so when you import random you are executing your script as well. Mind to name correctly your scripts.
your python script is named random.py so when you import random it import itself , in python when you import module it will run it.
therefor you get print twice.
rename your script or remove the import

Way around Python imports within imports?

Sorry if this is a very novice question, I was just wondering one thing.
When in python and your code is split up amongst multiple files, how would you avoid a ton of imports on the same thing?
Say I have 2 files. Main, and Content.
Main:
import pygame
from pygame.locals import *
pygame.display.init()
blah
Content:
import pygame
from pygame.locals import *
pygame.display.init()
load content and stuff
pygame is imported twice and display.init is called twice. This is problematic in other places. Is there anyway to get around this, or must it just import and import and import?
One situation I can think of is this: A script that writes to a file everytime it is imported. That way, if it's imported 3 times, it gets run 3 times, therefore writing to the file 3 times.
Thanks in advance!
You misunderstand what import does. It's not the same as include. Loaded modules are singletons and their corresponding files are not evaluated twice.
That said, a well-constructed module will not have side-effects on import. That's the purpose of the if __name__=='__main__' idiom.
Do not attempt to "clean up" your imports. Import everything you need to use from within a file. You could make less use of import *, but this is purely for code readability and maintainability.
You should avoid having anything happen at import(except, see further down). a python file is a module first, so it can and should be used by other python modules. If something "happens" in the import stage of a python file, then it may happen in an undesirable way when that file is imported by another module.
Each module should just define things to be used: classes, functions, constants, and just wait for something else to use them.
Obviously, if no script ever does at import, then it's not possible for anything to actually get used and make stuff "happen". There is a special idiom for the unusual case that a module was called directly. Each python file has a variable, __name__ automatically created with the module name it was imported as. When you run a script from the command line (or however you have started it), it wasn't imported, and there's no name for it to have, and so the __name__ variable will have a special value "__main__" that indicates that it's the script being executed. You can check for this condition and act accordingly:
# main.py
import pygame
from pygame.locals import *
import content
def init():
pygame.display.init()
def stuff():
content.morestuff()
if __name__ == '__main__':
init()
stuff()
# content.py
import pygame
from pygame.locals import *
def init():
pygame.display.init()
def morestuff():
"do some more stuff"
if __name__ == '__main__':
init()
morestuff()
This way; init() and thus pygame.display.init() are only ever called once, by the script that was run by the user. the code that runs assuming that init() has already been called is broken into another function, and called as needed by the main script (whatever that happens to be)
import statements are supposed to be declarations that you're using something from another module. They shouldn't be used to cause something to happen (like writing to a file). As noted by Francis Avila, Python will try not to execute the code of a module more than once anyway.
This has the consequence that whether a given import statement will cause anything to happen is a global property of the application at runtime; you can't tell just from the import statement and the source code of the module, because it depends on whether any other code anywhere else in the project has already imported that module.
So having a module "do something" when executed is generally a very fragile way to implement your application. There is no hard and fast definition of "do something" though, because obviously the module needs to create all the things that other modules will import from it, and that may involve reading config files, possibly even writing log files, or any number of other things. But anything that seems like the "action" of your program, rather than just "setting up" things to be imported from the module, should usually not be done in module scope.

Where to import modules

Lets say I have a module called device which contains a class called ConfigureDevice. Lets also say that I have a module called comports which defines my com ports in a class called ComPorts (enum in C).
Now, lets say that the constructor for ConfigureDevice takes an argument called comPorts. The question is, should I import comports at the beginning of the device module or should the code creating ConfigureDevice make this import?
So, should import comports occur here:
# device module
import serialwriter
import comports
class ConfigureDevice:
def __init__(self, comPort):
self.serialWriter = serialwriter.SerialWriter(comPort)
Or should I import it in the code that creates ConfigureDevice, like this:
import device
import comports
...
device.ConfigureDevice(comports.ComPorts.COM_1)
You should generally always put import at the top of the module, where Python programmers will expect to find it, because then any import errors will happen right when the program starts, instead of happening much later when a function is finally called. We generally only put import inside a function because (a) we are trying to avoid an awkward import loop among badly-designed modules, or (b) because we want to make a 3rd-party library optional so that you only need it if you call that function.
Update: Thank you for the code samples! Beyond my initial advice, that import always go at the top of a file, I can additionally now recommend that you remove the import of comport from your device module because, from what I can see, you never use the module there — I do not see the name comport anywhere in the device module code. In general, if you try removing an import statement from a file but the program still runs, the statement did not belong there in the first place. The pyflakes program can help you find import statements that are no longer useful as your code evolves.

How to tell if a Python modules I being reload()ed from within the module

When writing a Python module, is there a way to tell if the module is being imported or reloaded?
I know I can create a class, and the __init__() will only be called on the first import, but I hadn't planning on creating a class. Though, I will if there isn't an easy way to tell if we are being imported or reloaded.
The documentation for reload() actually gives a code snippet that I think should work for your purposes, at least in the usual case. You'd do something like this:
try:
reloading
except NameError:
reloading = False # means the module is being imported
else:
reloading = True # means the module is being reloaded
What this really does is detect whether the module is being imported "cleanly" (e.g. for the first time) or is overwriting a previous instance of the same module. In the normal case, a "clean" import corresponds to the import statement, and a "dirty" import corresponds to reload(), because import only really imports the module once, the first time it's executed (for each given module).
If you somehow manage to force a subsequent execution of the import statement into doing something nontrivial, or if you somehow manage to import your module for the first time using reload(), or if you mess around with the importing mechanism (through the imp module or the like), all bets are off. In other words, don't count on this always working in every possible situation.
P.S. The fact that you're asking this question makes me wonder if you're doing something you probably shouldn't be doing, but I won't ask.
>>> import os
>>> os.foo = 5
>>> os.foo
5
>>> import os
>>> os.foo
5

Categories