Changing variables across files Python - python

Heyo, I've run upon a problem.
So I have three files:
Main Program
Functions
Data
And I want the Main Program to call a function from the Functions module, which changes a variable in Data. Then I need to use the new variable elsewhere in the Main Program.
This is what I want, shown as a simplified demonstration program:
The Data file:
#data.py
#just an short depiction of my actual file
text = ""
The Functions file:
#functions.py
from data import *
def printHi():
global text
text = "hi"
print(text)
The Main Program:
#mainProgram.py
from functions import *
from data import *
printHi()
print(text)
What I expected would happen would be that when I run the Main Program:
The Functions file and Data file is imported.
Then it calls the "printHi" method from the Functions file.
The variable "text" from the Data file is assigned "hi", and is printed.
The the Main Program prints the "text" variable.
And I supposed that the text variable would be "hi". However, to my disappointment, it prints blank. It does indeed print the initial text value.
I really have NO idea why this is so. Shouldn't the text variable have already been changed? Could you please explain what part about my program is wrong and how to correct it?

The short answer is simply not to do this. It's a Bad Idea for all the reasons that global variables are always bad ideas: because they lead to stack overflow questions that read like "If I do this thing I shouldn't do, it does something I didn't expect -- why did it do that?" Whose easiest answer is, as you've now read, "That's why you shouldn't do that thing."
The long answer is a bit beyond me without spending a whole lot more time on the matter, but the longer answer is simple enough. When you do those "star" imports (from modulename import *) you're rebinding the name of the variable. What functions.printHi thinks of as text is not data.text but actually functions.text. When it's changed in printHi, it changes functions.text which should still be okay, since mainProgram is also importing functions.
However remember that mainProgram ISN'T actually importing functions, it's from functions import *'ing. That means what mainProgram thinks of as text is neither data.text nor functions.text, but mainProgram.text. When functions.printHi changes functions.text, it doesn't touch mainProgram.text.
The short answer applies here because these sorts of pitfalls are non-obvious unless you can think deeply enough about your code to understand them. If you are able to think that deeply about your code, you should be able to write something that can sidestep such pitfalls entirely. For instance: "global mutable state" is generally a bad thing. Avoid it.
To just make this work, drop all your "star" imports. The following code works:
# functions.py
import data
def printHi():
# plus! You don't need the `global` anymore.
data.text = "hi"
print(data.text)
# mainProgram.py
import functions
import data
functions.printHi() # prints "hi" from inside functions.printHi
print(data.text) # also prints "hi"

Cool, we have a lot of people saying "don't do this!". Well, what should you do then? The good way to do this is to pass the text variable into the function and out of it. Like so:
The Data file:
#data.py
#just an short depiction of my actual file
text = ""
The Functions file:
#functions.py
from data import *
def printHi(atext):
atext = "hi"
print(atext)
return atext
The Main Program:
#mainProgram.py
from functions import *
from data import *
text = printHi(text)
print(text)
That solves your problem. You should probably also get rid of the * imports as the other answer suggests but that's a philosophical question.

Related

Is there a problem in creating a fileobject inside a function, returning it to the parent function, and closing it there?

consider the python code below:
def create_fout_bt(location):
fout = open(os.path.join(location, 'The Book Thief.txt'), 'w')
# Added 'w' in Edit 1. Can't believe none of you guys noticed it! :P
return fout
def main():
location = r'E:\Books\Fiction'
fout_bt = create_fout_bt(location)
fout_bt.write('Author: Markus Zusak\n')
fout_bt.close()
main()
In this code, the fileobject named fout is created inside the function create_fout_bt, but not closed within the same function. What I understand is that we have to close every fileobject we create; so is this ok? In practice, the code works fine and the output file is generated with the content I wrote to it, but just wondering if a fileobject is dangling somewhere out there.
Thanks for your time.
Edit 1:
Thank you for introducing me to the python with statement. Hopefully I'll use it in the future.
Also, let me clarify that the code I mentioned here is a generic, simple case. Of course it doesn't make sense to define a function just to create a fileobject! In the real scenario, I will be writing to many different files concurrently. For example:
fout1.write('%s: %f' %('Magnetic Field', magnetic_field))
fout2.write('%s: %f' %('Power', power))
fout3.write('%s: %f' %('Cadence', cadence))
Now this requires creating the fileobjects fout1, fout2, fout3:
fout1 = open(os.path.join(rootPath, 'filename1.txt'), 'w')
fout2 = open(os.path.join(rootPath, 'filename2.txt'), 'w')
fout3 = open(os.path.join(rootPath, 'filename3.txt'), 'w')
Since there are many of them, I wanted to put them inside a function to make it look better - now a single function call will get me all the fileobjects:
fout1, fout2, fout3 = create_file_objects(rootPath)
Moreover, in the real scenario, I have to write into a file at multiple locations in the program. From what I have understood, if I'm using 'with', I'll have to open the file in append mode each time I have to write into it (making the code look cluttered); compared to using an 'open()' function which will keep the file open till I use the close() function.
Like deceze commented, the problem I'm worried about is spreading the responsibility of the fileobject to multiple functions. In my first example,
'fout' is the variable created inside the function 'create_fout_bt' and 'fout_bt' is the variable to which that value is assigned by the latter. Now, I know 'fout_bt' is taken care of with the statement 'fout_bt.close()', but what about 'fout' inside the function 'create_fout_bt'? Will it be disposed off when the function 'create_fout_bt' returns?
Hope my doubt is more clear. Do let me know if I just missed something obvious. Any comments on how to make my future posts more palatable will also be much appreciated. :)
Your code works fine, I try #Sujay 's suggestion, it raises an error I/O operation on closed file after fout_bt.close()
If you afraid of your code style, you can use with to do it.
code:
def create_fout_bt(location):
fout = open(os.path.join(location, 'The Book Thief.txt'),"a")
return fout
def main():
location = r'E:\Books\Fiction'
with create_fout_bt(location) as fout_bt:
fout_bt.write('Author: Markus Zusak\n')
main()
The only thing is that the code that opens the file (create_fout_bt) cannot guarantee that the file will also be closed. Which isn't an issue per se, but it spreads that responsibility around and may lead to situations in which the file isn't closed, because the caller doesn't handle the returned file handle correctly. It's still fine to do this, you just need to be diligent. One way this could be improved is with this:
with create_fout_bt(location) as fout_bt:
fout_bt.write('Author: Markus Zusak\n')
Using a with context manager on the file object, regardless of whether directly created with open or "indirectly" via create_fout_bt, guarantees that the file will be closed, regardless of errors happening in your code.
you can use 'with'.
with 'with' you don't need to close your files anymore and it automatically close it self.
do it like this :
with create_fout_bt(location) as fout_bt:
fout_bt.write('Author: Markus Zusak\n')

Python nameError help when importing from another file

I have a function in maya that imports in other functions and creates a shelf with buttons for specific functions. I have a function that has a scriptJob command that works fine. if I import that file in manually and not through the shelf button, but gives a NameError when using the shelf script to run it.
This is an example of the script
myShelf.py file:
import loopingFunction
loopingFunction.runThis()
loopingFunction.py file:
import maya.cmds as mc
def setSettings():
#have some settings set before running this
runThis()
def runThis():
print "yay this ran"
evalDeferred(mc.scriptJob(ro=True,ac=["'someMesh.outMesh',runThis"])
if I run this through the shelf function, I get a runThis nameError is not defined and if I try modifying the scriptJob command to loopingFunction.runThis, I get a nameError loopingFunction is not defined(not sure if using loopingFunction.runThis is even correct, to be honest)
Not sure how I can get around this without having to manually import in the function rather than through the shelf file.
Using string references for callback functions like this often leads to scope problems. (More on that, and why not to use strings, here)
If you pass the function directly to the callback as an object, instead of using a string, it should work correctly as along as you have actually imported the code.
in this case you want an evalDeferred -- do you actually need it? -- so it helps to add a little function around the actual code so that the scriptjob creation actually happens later -- otherwise it will get evaluated before the deferral is scheduled.
def runThis():
print "callback ran"
def do_scriptjob():
cmds.scriptJob(ro=True, ac=('someMesh.outMesh', runThis)
cmds.evalDeferred(do_scriptjob)
In both runThis and do_scriptjob I did not add the parens -- we are letting the evalDeferred and the scriptJob have the function objects to call when they are ready. Using the parens would pass the results of the functions which is not what you want here.
Incidentally it looks like you're trying to create a new copy of the scriptJob inside the scriptJob itself. It'd be better to just drop the runOnce flag and leave the scriptJob lying around -- if something in runThis actually affected the someMesh.outMesh attribute, your maya will go into an infinite loop. I did not change the structure in my example, but I would not recommend writing this kind of self-replicating code if you can possibly avoid it.
You have a problem of nested/maya scope variables
mc.scriptJob(ro=True,ac=["'someMesh.outMesh',runThis"]
This line is a maya command string that is evaluated in the main maya scope (like a global)
As your function have a namespace with the import : 'loopingFunction', you need to enforce it in the string command.
import loopingFunction
loopingFunction.runThis()
You should write
evalDeferred(mc.scriptJob(ro=True,ac=["'someMesh.outMesh',loopingFunction.runThis"])
If you want something more general, you can do :
def runThis(ns=''):
print "yay this ran"
if ns != '':
ns += '.'
evalDeferred(mc.scriptJob(ro=True,ac=["'someMesh.outMesh',{}runThis".format(ns)])
and then run in shelf :
import loopingFunction
loopingFunction.runThis('loopingFunction')
like this you can write any formof namepsaces :
import loopingFunction as loopF
loopF.runThis('loopF')

Python - How to call code from an external file

I have revised this question to make it much more simple.
I am running a program in python 3.x.
I want this program to open a file name example.py and run the code inside it.
This is the contents of the file:
#example1.py
print('hello world')
#example2.py
print('hello world 2')
#main.py
someMagicalCodeHere(executes example2.py)
#prints hello world
I need to do this without it being an imported file.
The problem with imported files is they are declared beforehand in the main.py. My main.py will be creating example1.py, example2.py etc and filling them with code, and then later referencing back to them as needed. There may be thousands or millions.
This is part of a large project that we are trying to switch over to a new language. We don't know python yet, and we need this concept to be viable to continue learning the language.
I have tried
exec(example.py)
I have tried
with open('example.py', 'r') as ex:
ex.read()
Thanks in advance for the answer, and thanks for all who have answered thus far.
I'm assuming you have some kind of a function that converts strings to such answers, or perhaps a dictionary. Otherwise the solution to this problem would be beyond the scope of current progress in NLP.
def ask_question_and_get_response(question=None):
answer = input(question)
return answer
I must also assume that you have a way to convert the original question, such as "What is your name?", to one that the user may in turn ask your bot, "What is my name?". Let that function look like what follows:
def get_reflex_question(question):
<your implementation>
return reflex_question
With both of these in hand, we can create a file (if one doesn't already exist), and write what can be interpreted as Python code to it.
def make_code(answer, reflex_question)
with open("filename", "a") as file:
file.write("\n")
file.write("if userBoxAsks == %s:\n\t" % (reflex_question))
file.write("print(answer)")
Which will output code to a file of your naming.
To run that file, you could use the subprocess module (read documentation), or simply import this file of yours as a module itself.
Whenever you update the file, you could reload the import so that the new code runs too. In Python3.x, you can do importlib.reload(filename) to refresh the import.
Alright after much deliberation, hunting and searching, I discovered through experimentation, found the answer to my own question.
#c:\\one.py
print('hello world')
#c:\\main.py
import os.path
filename = "c:\\one.py"
if not os.path.isfile(filename):
print ('File does not exist.')
else:
with open(filename) as f:
content = f.read().splitlines()
for line in content:
exec(line)
Returns (without quotes) 'Hello World'
Note that these solutions are not secure and considered risky. So obviously meant for play/test purpose
Python 2:
execfile('example2.py')
Python 3:
with open('example2.py') as f:
exec(f.read())

Python: internally defined open() causes "Type Error", "argument requires no arguments, 1 given"

This is quite likely something simple that I have an issue with, but I do not have another machine to figure out if it's my laptop's python version right now.
When I run my program, I recieve the following error: "Type Error: function open() requires no arguments (2 given)"
The code snippet in question:
import tkinter as tk
from tkinter import filedialog as fdg
def update_queue():
conf_file = open("config.txt", "a")
fd = fdg.LoadFileDialog(master)
file = fd.go(pattern="*.jpg")
conf_file.write(file)
conf_file.close()
I'm not yet too good with Python, and would appreciate any pointers ("Your code looks twistier than last night's burnt spaghetti" counts as well) as to why the open() function fails.
Also of note, if I call open outside of a defined function, it opens the file, and can complete all actions done on it, but if I close the file, I cannot re open the file from within a function. I attempted to use the os file functions, but recieved the error "LoadFileDialog does not work with buffer-defined file functions." Understandable.
If I use conf_file.flush(), assuming I opened it outside of a function, will it flush whatever I write/append, so that I can read from the file again later?
EDIT: What I mean, is, will this work all the time, or would this be considered a hack?
is that the whole code? make sure you did not import another open function somewhere. or redefined it.
Assuming that open() was declared later on and you just didn't include it in the code, you probably declared it as
def open():
#code here
If this is the case, you just didn't add in the arguments when declaring the function and it should be:
def open(x, y):
#code here
where x and y could be anything you like.
Please come back and post the rest of your code (i highly doubt this is all of it) to get better answers. What is truly going on is at most a speculation on out part.

Python: how to input python-code part like \input in Tex?

I want to input code in Python like \input{Sources/file.tex}. How can I do it in Python?
[added]
Suppose I want to input data to: print("My data is here"+<input data here>).
Data
1, 3, 5, 5, 6
The built-in execfile function does what you ask, for example:
filename = "Sources/file.py"
execfile( filename )
This will execute the code from Sources/file.py almost as if that code were embedded in the current file, and is thus very similar to #include in C or \input in LaTeX.
Note that execfile also permits two optional arguments allowing you to specify the globals and locals dicts that the code should be executed with respect to, but in most cases this is not necessary. See pydoc execfile for details.
There are occasional legitimate reasons to want to use execfile. However, for the purpose of structuring large Python programs, it is conventional to separate your code into modules placed somewhere in the PYTHONPATH and to load them using the import statement rather than executing them with execfile. The advantages of import over execfile include:
Imported functions get qualified with the name of the module, e.g. module.myfunction instead of just myfunction.
Your code doesn't need to hard-code where in the filesystem the file is located.
You can't do that in Python. You can import objects from other modules.
otherfile.py:
def print_hello():
print "Hello World!"
main.py
import otherfile
otherfile.print_hello() # prints Hello World!
See the python tutorial
Say you have code in "my_file.py". Any line which is not in a method WILL get executed when you do:
import my_file
So for example if my_file.py has the following code in it:
print "hello"
Then in the interpreter you type:
import my_file
You will see "hello".
My question was clearly too broad, as the variety of replies hint -- none of them fully attack the question. The jchl targets the scenario where you get python-code to be executed. The THC4k addresses the situation where you want to use outside objects from modules. muckabout's reply is bad practice, as Xavier Ho mentioned, why on earth it uses import when it could use exec as well, the principle of least privileges to the dogs. One thing is still missing, probably because of the conflict between the term python-code in the title and the addition of data containing integers -- it is hard to claim that data is python-code but the code explains how to input data, evaluations and executable code.
#!/usr/bin/python
#
# Description: it works like the input -thing in Tex,
# you can fetch outside executable code, data or anything you like.
# Sorry I don't know precisely how input(things) works, maybe misusing terms
# or exaggerating.
#
# The reason why I wanted input -style thing is because I wanted to use more
# Python to write my lab-reports. Now, I don't need to mess data with
# executions and evalutions and data can be in clean files.
#TRIAL 1: Execution and Evaluation not from a file
executeMe="print('hello'); a = 'If you see me, it works'";
exec( executeMe )
print(a);
#TRIAL 2: printing file content
#
# and now with files
#
# $ cat IwillPrint007fromFile
# 007
f = open('./IwillPrint007fromFile', 'r');
msg = f.read()
print("If 007 == " + msg + " it works!");
# TRIAL 3: Evaluation from a file
#
# $cat IwillEvaluateSthing.py
# #!/usr/bin/python
# #
# # Description:
#
#
# evaluateMe = "If you see me again, you are breaking the rules of Sky."
f = open('./IwillEvaluateSthing.py', 'r');
exec(f.read());
print(evaluateMe);

Categories

Resources