Change variable permanently - python

I'm writing a small program that helps you keep track of what page you're on in your books. I'm not a fan of bookmarks, so I thought "What if I could create a program that would take user input, and then display the number or string of text that they wrote, which in this case would be the page number they're on, and allow them to change it whenever they need to?" It would only take a few lines of code, but the problem is, how can I get it to display the same number the next time I open the program? The variables would reset, would they not? Is there a way to permanently change a variable in this way?

You can store the values in a file, and then load them at start up.
The code would look somewhat like this
variable1 = "fi" #start the variable, they can come from the main program instead
variable2 = 2
datatowrite = str(variable1) + "\n" + str(variable2) #converts all the variables to string and packs them together broken apart by a new line
f = file("/file.txt",'w')
f.write(datatowrite) #Writes the packed variable to the file
f.close() #Closes the file !IMPORTANT TO DO!
The Code to read the data would be:
import string
f = file("/file.txt",'r') #Opens the file
data = f.read() #reads the file into data
if not len(data) > 4: #Checks if anything is in the file, if not creates the variables (doesn't have to be four)
variable1 = "fi"
variable2 = 2
else:
data = string.split(data,"\n") #Splits up the data in the file with the new line and removes the new line
variable1 = data[0] #the first part of the split
variable2 = int(data[1]) #Converts second part of strip to the type needed
Bear in mind with this method the variable file is stored in plaintext with the application. Any user could edit the variables and change the programs behaviour

You need to store it on disk. Unless you want to be really fancy, you can just use something like CSV, JSON, or YAML to make structured data easier.
Also check out the python pickle module.

Variables have several lifetimes:
If they're inside of a block of code, their value only exists for that block of code. This covers functions, loops, and conditionals.
If they're inside of an object, their value only exists for the life of that object.
If the object is dereferenced, or you leave your code of block early, the value of the variable is lost.
If you want to maintain the value of something in particular, you have to persist it. Persistence allows you to write a variable out to disk (and yes, databases are technically out-to-disk), and retrieve it at a later time - after the lifetime of the variable has expired, or when the program is restarted.
You've got several options for how you want to persist the location of their page - a heavy-handed approach would be to use SQLite; a slightly less heavy handed approach would be to unpickle the object, or simply write to a text file.

Related

Is there a way to permanently add to a list in python?

I want to create a program that stores my race data in lists sorted my race length(I'm a runner). So when I add it, it add temporarily and as soon as I restart the code, it deletes the old one. I want it to permanently change the code and be added permanently.
my code:
#All the sub-folders
fivek = []
tenk = []
twomi = []
sixteen = []
eight = []
four = []
two = []
Half = []
Full = []
#choose which folder
distance = input("Length of Race? (5k, 10k, 2mi, 1600, 800, 400, 200, Half, Full)")
if distance == "5k":
time=str(input("What was your time? (Put date in parenthesis Ex. 20:00(1-1-20))"))
fivek.append(time)
print(fivek)
am I being clear enough? Let me know if I'm being too hazy.
so using csv like this?
import csv
time = []
length = []
place = []
timeResult = input("What was your time?")
lengthResult = input("What was the race length?")
placeResult = input("Where was the race?")
pace.append(placeResult)
time.append(timeResult)
length.append(lengthResult)
with open('times.csv', newline='') as f:
thewriter = csv.writer(f)
thewriter.writerow([length, time, place])
No. Python lists are objects that are created in memory. Memory is empty when your Python script starts, and the objects in it disappear when your script ends. So what you need to do is fill your list from a form of permanent storage, such as a file on your disk. i.e. you don't want to modify the code itself to contain your data. Instead, your code reads in data from an external source.
So you might want to look at the csv library:
https://docs.python.org/3/library/csv.html. This allows you to read from a file on disk at the start of your script to populate a list initially. You then add entries to the list in your script, and at the end, save the updated list back to disk. A tabular csv (comma separated values) file has the advantage that it is plain text, so it can be read by a great range of other software, and is especially well-suited to being opened in a spreadsheet if you want to inspect your data that way. Pickling is a way of directly saving Python objects to disk, but the resulting files aren't directly readable by anything except Python itself.
Lastly, you might find it convenient to save all of your data in a single table, with a column for race length, and another column for race time. This allows for a lot more flexibility for analysis later on. Inside your code, after reading in a single csv file formatted in that way, you would get a single list of dictionaries, where each entry is a Python dictionary that has a key (the race length) and a value (the race time).

How to share a variable between two python scripts run separately

I'm an extreme noob to python, so If there's a better way to do what I'm asking please let me know.
I have one file, which works with flask to create markers on a map. It has an array which stores these said markers. I'm starting the file through command prompt, and opening said file multiple times. Basically, how would one open a file multiple times, and have them share a variable (Not the same as having a subfile that shares variables with a superfile.) I'm okay with creating another file that starts the instances if needed, but I'm not sure how I'd do that.
Here is an example of what I'd like to accomplish. I have a file called, let's
say, test.py:
global number
number += 1
print(number)
I'd like it so that when I start this through command prompt (python test.py) multiple times, it'd print the following:
1
2
3
4
5
The only difference between above and what I have, is that what I have will be non-terminating and continuously running
What you seem to be looking for is some form of inter-process communication. In terms of python, each process has its own memory space and its own variables meaning that if I ran.
number += 1
print(number)
Multiple times then I would get 1,2..5 on a new line. No matter how many times I start the script, number would be a global.
There are a few ways where you can keep consistency.
Writing To A File (named pipe)
One of your scripts can have (generator.py)
import os
num = 1
try:
os.mkfifo("temp.txt")
except:
pass # In case one of your other files already started
while True:
file = open("temp.txt", "w")
file.write(num)
file.close() # Important because if you don't close the file
# The operating system will lock your file and your other scripts
# Won't have access
sleep(# seconds)
In your other scripts (consumer.py)
while True:
file = open("temp.txt", "r")
number = int(file.read())
print(number)
sleep(# seconds)
You would start 1 or so generator and as many consumers as you want. Note: this does have a race condition that can't really be avoided. When you write to the file, you should use a serializer like pickler or json to properly encode and decode your array object.
Other Ways
You can also look up how to use pipes (both named and unnamed), databases, ampq (IMHO the best way to do it but there is a learning curve and added dependencies), and if you are feeling bold use mmap.
Design Change
If you are willing to listen to a design change, Since you are making a flask application that has the variable in memory why don't you just make an endpoint to serve up your array and check the endpoint every so often?
import json # or pickle
import flask
app = Flask(__name__)
array = [objects]
converted = method_to_convert_to_array_of_dicts(array)
#app.route("/array")
def hello():
return json.dumps(array)
You will need to convert but then the web server can be hosted and your clients would just need something like
import requests
import json
while True:
result = requests.get('localhost/array')
array = json.loads(str(result.body)) # or some string form of result
sleep(...)
Your description is kind of confusing, but if I understand you correctly, one way of doing this would be to keep the value of the variable in a separate file.
When a script needs the value, read the value from the file and add one to it. If the file doesn't exist, use a default value of 1. Finally, rewrite the file with the new value.
However you said that this value would be shared among two python scripts, so you'd have to be careful that both scripts don't try to access the file at the same time.
I think you could use pickle.dump(your array, file) to serie the data(your array) intoto a file. And at next time running the script, you could just load the data back with pickle.dump(your array, file)

How to append a list so that the changes are persistent?

I am new to Python and relatively new to coding in general, I was just trying to write a test bit of code to see if a list could be appended, and then when that .py is reloaded the changes are saved into it?
I'm not sure if this is possible with lists without a decent amount more work, but none of my attempts have managed to get me there.
The test code I have at the moment is:
lDUn = []
lDPw = []
def enterUn():
usrName = input(str("Enter your desired username:\n"))
if usrName in lDUn:
print ("Username is already in use, please try again")
enterUn()
else:
print ("Username created!")
lDUn.append(usrName)
enterUn()
def enterPw():
pW1 = input(str("Enter your desired password:\n"))
pW2 = input(str("please re-enter your password:\n"))
if pW1 == pW2:
print ("Password created!")
lDPw.append(pW1)
else:
print ("Passwords do not match, please try again")
enterPw()
enterPw()
When lDUn and lDPw are checked for inclusion later on they register no problem, but when the program is closed and re-opened later they are gone.
I have tried making it writing the 'pW' and 'usrName' inputs into a .txt but have failed to get it to search those .txts for the specific strings later on. (but that is for a different question) Other than that I'm not sure what to do with my current knowledge of Python.
The values of variables (in this case, the contents of your lists) are never automatically saved when you restart the program. You would need to write some code that saves the values to a file before the program exits, and also some code that reads the values in from the file when the program starts up again.
It's up to you just how you convert the lists into bytes that you can put in a file. One common way would be to just write the strings from the lists into the file, one per line, and then read them again. You can do this using the methods of file objects.
Another option is to use the pickle module. This may save you a bit of effort, since you just give it a Python object and it handles the conversion into bytes for you, but you won't be able to view and edit the resulting file. (Well, you can, but it will look like gibberish since it's a binary file.)
Here's basically what you do:
You set a file or files where you will store those lists.
At the begining of your code you load the data from files into lists.
Each time you modify one of the lists you also modify the related file (the most basic implementation would be to recreate the file).
You work with in-memory data in other cases.
That will work fine as long as you deal with small files and small "traffic". If any of those increases then you will have serious peformance and/or consistency issues. To properly solve these problems you should use a proper database, starting with sqlite (which doesn't require a separate server).

How do i replace a specific value in a file in python

Im trying to replace the zero's with a value. So far this is my code, but what do i do next?
g = open("January.txt", "r+")
for i in range(3):
dat_month = g.readline()
Month: January
Item: Lawn
Total square metres purchased:
0
monthly value = 0
You could do that -
but that is not the usual approach, and certainly is not the correct approach for text files.
The correct way to do it is to write another file, with the information you want updated in place, and then rename the new file to the old one. That is the only sane way of doing this with text files, since the information size in bytes for the fields is variable.
As for the impresion that you are "writing 200 bytes to the disk" instead of a single byte, changing your value, don't let that fool you: at the Operating system level, all file access has to be done in blocks, which are usually a couple of kilobytes long (in special cases, and tunned filesystems it could be a couple hundred bytes). Anyway, you will never, in a user-space program, much less in a high level language like Python, trigger a diskwrite of less than a few hundred bytes.
Now, for the code:
import os
my_number = <number you want to place in the line you want to rewrite>
with open("January.txt", "r") as in_file, open("newfile.txt", "w") as out_file:
for line in in_file:
if line.strip() == "0":
out_file.write(str(my_number) + "\n")
else:
out_file.write(line)
os.unlink("January.txt")
os.rename("newfile.txt", "January.txt")
So - that is the general idea -
of course you should not write code with all values hardcoded in that way (i.e. the values to be checked and written fixed in the program code, as are the filenames).
As for the with statement - it is a special construct of the language wich is very appropriate to oppening files and manipulating then in a block, like in this case - but it is not needed.
Programing apart, the concept you have to keep in mind is this:
when you use an application that lets you edit a text file, a spreadsheet, an image, you, as user, may have the impression that after you are done and have saved your work, the updates are comitted to the same file. In the vast, vast majority of use cases, that is not what happens: the application uses internally a pattern like the one I presented above - a completly new file is written to disk and the old one is deleted, or renamed. The few exceptions could be simple database applications, which could replace fixed width fields inside the file itself on updates. Modern day databases certainly do not do that, resorting to appending the most recent, updated information, to the end of the file. PDF files are another kind that were not designed to be replaced entirely on each update, when being created: but also in that case, the updated information is written at the end of the file, even if the update is to take place in a page in the beginning of the rendered document.
dat_month = dat_month.replace("0", "45678")
To write to a file you do:
with open("Outfile.txt", "wt") as outfile:
And then
outfile.write(dat_month)
Try this:
import fileinput
import itertools
import sys
with fileinput.input('January.txt', inplace=True) as file:
beginning = tuple(itertools.islice(file, 3))
sys.stdout.writelines(beginning)
sys.stdout.write(next(file).replace('0', 'a value'))
sys.stdout.write(next(file).replace('0', 'a value'))
sys.stdout.writelines(file)

Python how to change the value of a variable on the fly

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.

Categories