I need a little bit of help on overwriting python variables. Here's the best example I could give. IF someone opens up my program (in .exe or .py) and this were to come up:
var = 5
var = raw_input("Enter the new variable value: ") ##THE PERSON ENTERS 3
var = 3
Now, the user closes the file/program, next time they open it, they want the program to remember that var = 3, so it overwrote the var = 5 with var = 3. I don't know if this is possible, but if it is, could you let me know?
To Clarify: I want my .py or .exe to remember that a variable was changed, and overwrite the old variable with the new one, so the next time they open the file, the variable is already changed.
You'll need to somehow store the value, for example in a file, database, or with some service.
For example, using a simple file:
import io,os
try:
with io.open('~/.jordan_last_value', 'r', encoding='utf-8') as f:
var = f.read()
except IOError: # Read failed
var = raw_input('Enter the new variable value')
# Save value to disk
with io.open('~/.jordan_last_value', 'w', encoding='utf-8') as f:
f.write(var)
print ('Current value is ' + var)
As you can see, this can be somewhat complex, so you may want to refresh your knowledge of file handling. Also, this example code can just store strings.
If you want to be able to store more complex objects, you'll need a way to transform them from and to bytestrings first. Have a look at the json or pickle modules for that.
You can use pickle module, json or whatever :P
Using the pickle module:
import pickle
try: # try to open the file
with open('jordan_data.pkl', 'r+') as f:
var = pickle.load(f)
except IOError: # if it doesn't exist, get new input
var = raw_input("Enter the new variable value: ") # THE PERSON ENTERS 3
with open('jordan_data.pkl', 'a+') as f: # 'a' will create the file if it doesn't exist
pickle.dump(var, f) # then, save the file
Related
I need to make a program, that will ask user for what .txt file they want to rewrite to a new file and what should the new files name be + the new file has to be in all uppercase. Also after doing that the program has to show the amount of symbols(characters) in the new file.
f1 ask the name of the file they want to re-write.
f2 ask what the new name should be.
#xxxxxxxxxxxx
f1 = input("xxxxxxxxxxx xxxxxxxxxxxx (xxxxxxxxxx: ):")
f2 = input("xxxxxxxxxxxxxxxxxxxxxx (xxxxxxxx: ):")
#xxxxxxxxxxxxxxxxxxxxx
FirstFail = open(f1, 'r')
NewOnes = FirstFail.readlines()
#xxxxxxxxx
Indeed = open(f2, 'w')
Indeed.write((str(NewOnes)).upper())
#xxxxxxxxxxxx
FirstFail.close()
Indeed.close()
#xxxxxxxxxxxxx
Sym = open(str(Indeed, 'r'))
print(str.count(start=0, end=len(Sym)))
This is the error I'm getting:
Sym = open(str(Indeed, 'r'))
TypeError: decoding to str: need a bytes-like object, _io.TextIOWrapper found
Now I know that Nfail is in the wrong format and I need to somehow change it but have no Idea how.
the 2 last lines makes no sense:
Sym = open(str(Nfail, 'r'))
passes a tuple(file handle,'r') to open.
print(str.count(start=0, end=len(Sym)))
tries to call method count without object, and passing len(Sym) which can't work since Sym is a file handle
I'd rewrite that like this:
with open(f2, 'r') as Sym:
print(len(Sym.read()))
also no need to read the file to get the size, just do:
print(os.path.getsize(f2))
(you may have a slight difference on windows because of \r\n => \n conversion but that's the fastest way to get a file size: the file isn't even read)
I am trying to create a basic mathematical quiz and need to be able to store the name of the user next to their score. To ensure that I could edit the data dynamically regardless of the length of the user's name or the number of digits in their score, I decided to split up the name and score with a comma and use the split function. I'm new to file handling in python so don't know if I am using the wrong mode ("r+") but when I complete the quiz, my score is not recorded at all, nothing is added to the file. Here is my code:
for line in class_results.read():
if student_full_name in line:
student = line.split(",")
student[1] = correct
line.replace(line, "{},{}".format(student_full_name, student[1]))
else:
class_results.write("{},{}".format(student_full_name, correct))
Please let me know how I can get this system to work. Thank you in advance.
Yes r+ opens the file for both reading and writing and to summarize:
r when the file will only be read
w for only writing (an existing file with the same name will be erased)
a opens the file for appending; any data written to the file is automatically added to the end.
I will recommend instead of comma separation to benifit from json or yaml syntax, it fits better in this case.
scores.json:
{
"student1": 12,
"student2": 798
}
The solution:
import json
with open(filename, "r+") as data:
scores_dict = json.loads(data.read())
scores_dict[student_full_name] = correct # if already exist it will be updated otherwise it will be added
data.seek(0)
data.write(json.dumps(scores_dict))
data.truncate()
scores.yml will looks as follow:
student1: 45
student2: 7986
Solution:
import yaml
with open(filename, "r+") as data:
scores_dict = yaml.loads(data.read())
scores_dict[student_full_name] = correct # if already exist it will be updated otherwise it will be added
data.seek(0)
data.write(yaml.dump(scores_dict, default_flow_style=False))
data.truncate()
to instal yaml python package: pip install pyyaml
Modifying a file in place is generally a poor way to do this. It risks errors causing the resulting file to be half new data, half old, with the split point being corrupted. The usual pattern is to write to a new file, then atomically replace the old file with the new file, so either you have the entire original old file and a partial new file, or the new file, not a mish-mash of both.
Given your example code, here is how you would fix it up to do that:
import csv
import os
from tempfile import NamedTemporaryFile
origfile = '...'
origdir = os.path.dirname(origfile)
# Open original file for read, and tempfile in same directory for write
with open(origfile, newline='') as inf, NamedTemporaryFile('w', dir=origdir, newline='') as outf:
old_results = csv.reader(inf)
new_results = csv.writer(outf)
for name, oldscore in old_results:
if name == student_full_name:
# Found our student, replace their score
new_results.writerow((name, correct))
# The write out the rest of the lines unchanged
new_results.writerows(old_results)
# and we're done
break
else:
new_results.writerow((name, oldscore))
else:
# else block on for loop executes if loop ran without break-ing
new_results.writerow((student_full_name, correct))
# If we got here, no exceptions, so let's keep the new data to replace the old
outf.delete = False
# Atomically replaces the original file with the temp file with updated data
os.replace(outf.name, origfile)
Ok so I've been playing with python and spss to achieve almost what I want. I am able to open the file and make the changes, however I am having trouble saving the files (and those changes). What I have (using only one school in the schoollist):
begin program.
import spss, spssaux
import os
schoollist = ['brow']
for x in schoollist:
school = 'brow'
school2 = school + '06.sav'
filename = os.path.join("Y:\...\Data", school2) #In this instance, Y:\...\Data\brow06.sav
spssaux.OpenDataFile(filename)
#--This block are the changes and not particularly relevant to the question--#
cur=spss.Cursor(accessType='w')
cur.SetVarNameAndType(['name'],[8])
cur.CommitDictionary()
for i in range(cur.GetCaseCount()):
cur.fetchone()
cur.SetValueChar('name', school)
cur.CommitCase()
cur.close()
#-- What am I doing wrong here? --#
spss.Submit("save outfile = filename".)
end program.
Any suggestions on how to get the save outfile to work with the loop? Thanks. Cheers
In your save call, you are not resolving filename to its actual value. It should be something like this:
spss.Submit("""save outfile="%s".""" % filename)
I'm unfamiliar with spssaux.OpenDataFile and can't find any documentation on it (besides references to working with SPSS data files in unicode mode). But what I am going to guess is the problem is that it grabs the SPSS data file for use in the Python program block, but it isn't actually opened to further submit commands.
Here I make a test case that instead of using spssaux.OpenDataFile to grab the file, does it all with SPSS commands and just inserts the necessary parts via python. So first lets create some fake data to work with.
*Prepping the example data files.
FILE HANDLE save /NAME = 'C:\Users\andrew.wheeler\Desktop\TestPython'.
DATA LIST FREE / A .
BEGIN DATA
1
2
3
END DATA.
SAVE OUTFILE = "save\Test1.sav".
SAVE OUTFILE = "save\Test2.sav".
SAVE OUTFILE = "save\Test3.sav".
DATASET CLOSE ALL.
Now here is a paired down version of what your code is doing. I have the LIST ALL. command inserted in so you can check the output that it is adding the variable of interest to the file.
*Sequential opening the data files and appending data name.
BEGIN PROGRAM.
import spss
import os
schoollist = ['1','2','3']
for x in schoollist:
school2 = 'Test' + x + '.sav'
filename = os.path.join("C:\\Users\\andrew.wheeler\\Desktop\\TestPython", school2)
#opens the SPSS file and makes a new variable for the school name
spss.Submit("""
GET FILE = "%s".
STRING Name (A20).
COMPUTE Name = "%s".
LIST ALL.
SAVE OUTFILE = "%s".
""" %(filename, x,filename))
END PROGRAM.
When I use pickle, it works fine and I can dump any load.
The problem is if I close the program and try to dump again, it replaces the old file data with the new dumping. Here is my code:
import pickle
import os
import time
dictionary = dict()
def read():
with open('test.txt', 'rb') as f:
a = pickle.load(f)
print(a)
time.sleep(2)
def dump():
chs = raw_input('name and number')
n = chs.split()
dictionary[n[0]] = n[1]
with open('test.txt', 'wb') as f:
pickle.dump(dictionary, f)
Inpt = raw_input('Option : ')
if Inpt == 'read':
read()
else:
dump()
When you open a file in w mode (or wb), that tells it to write a brand-new file, erasing whatever was already there.
As the docs say:
The most commonly-used values of mode are 'r' for reading, 'w' for writing (truncating the file if it already exists), and 'a' for appending…
In other words, you want to use 'ab', not 'wb'.
However, when you append new dumps to the same file, you end up with a file made up of multiple separate values. If you only call load once, it's just going to load the first one. If you want to load all of them, you need to write code that does that. For example, you can load in a loop until EOFError.
Really, it looks like what you're trying to do is not to append to the pickle file, but to modify the existing pickled dictionary.
You could do that with a function that loads and merges all of the dumps together, like this:
def Load():
d = {}
with open('test.txt', 'rb') as f:
while True:
try:
a = pickle.load(f)
except EOFError:
break
else:
d.update(a)
# do stuff with d
But that's going to get slower and slower the more times you run your program, as you pile on more and more copies of the same values. To do that right you need to load the old dictionary, modify that, and then dump the modified version. And for that, you want w mode.
However, a much better way to persist a dictionary, at least if the keys are strings, is to use dbm (if the values are also strings) or shelve (otherwise) instead of a dictionary in the first place.
Opening a file in "wb" mode truncates the file -- that is, it deletes the contents of the file, and then allows you to work on it.
Usually, you'd open the file in append ("ab") mode to add data at the end. However, Pickle doesn't support appending, so you'll have to save your data to a new file (come up with a different file name -- ask the user or use a command-line parameter such as -o test.txt?) each time the program is run.
On a related topic, don't use Pickle. It's unsafe. Consider using JSON instead (it's in the standard lib -- import json).
Right now i am working with a file .txt with this information:
["corrector", "Enabled"]
["Inteligencia", "Enabled"]
Then in my python program it loads that data at the very beggining, this way:
for line in open("menu.txt", 'r'):
retrieved = json.loads(line)
if retrieved[0] == "corrector":
corrector = retrieved[1]
if retrieved[0] == "Inteligencia":
Inteligencia = retrieved[1]
So far it works perfect, however as this is for a chat bot, i want to make possible to change the value of that variables directly from the chat, and i tried this code when i call "!Enable corrector" from the chat.
if corrector == "Enabled":
room.message("ERROR: Already Enabled")
else:
data = []
with open('menu.txt', 'r+') as f:
for line in f:
data_line = json.loads(line)
if data_line[0] == "corrector":
data_line[1] = "Enabled"
data.append(data_line)
f.seek(0)
f.writelines(["%s\n" % json.dumps(i) for i in data])
f.truncate()
room.message("corrector enabled")
That also works, and if i open the .txt file i can see the value it's already changed. The real problem is that python didn't seem to accept that i changed a variable, and it still thinks it's "disabled" while it's already "enabled". It won't read the variable as "enabled" until i restart the program.
I was wondering if there is a refresh option for variables or a workaround to change the value of a variables on the fly and make the effect lasts without a restart.
change the value of a variables on the fly
This code changes the value of a variable on the fly:
a = 1
a = 2
Your question suggests that you want to be able to look up a value by a calculated name. The solution is to use a dict:
mydict = {'corrector':0}
mydict['corrector'] = 1
If you want to change the values in the file, you'll need to write out a new file based on the data you have. It looks like you're loading json, so the json module will help you out with that.