[Tutor] Variables
Martin A. Brown
martin at linux-ip.net
Wed Aug 3 01:33:58 EDT 2016
Hello Palmer,
>> I'm trying to write a program w/ python that runs once a day and every time
>> it does it adds 20 to a variable. How do I do this so it doesn't reset the
>> variable to the original value every time I run it?
>
>You have to read the variable from a file saved to disk, add 20,
>then write back to the file.
>
>Does that answer your question? Do you need help reading and
>writing files?
Steven has given you a pointer in the right direction.
Given your description, it sounds like you do not know how to make a
program/computer remember the (incrementing) number (value) between
program runs. So, to my ear, it sounds like each time your program
runs, it starts with a value that is 0 (or nonexistent).
So, you need to come up with a strategy for persistence. You need
to save the final value of your variable at the end of the program,
in short, you need to write that to disk (somehow).
The most basic way is to write to a simple file, but....there by
dragons. Files disappear. Files become corrupt. Files sometimes
change permissions. A file that was there a moment ago may not be
any longer. So, code that accesses files needs to be
...risk-averse.
With the protections of programming languages, you often do not have
to deal in memory with the race conditions that plague access to
filesystems. People sometimes use databases, but understanding the
general race conditions that come with persistent storage will help
you whether you are trying to store values in a database or a
filesystem.
Below is a Python2 (and Python3) program I have written to
demonstrate how to read a variable from a file, increment the
variable and store that variable again. It may seem a bit long at
first, but I'm hoping from the function names that you can see how a
simple function like increment()
def increment(var, step):
return var + step
...can be a bit trickier when you need to save that data between
invocations of the program. The program can be run three different
ways:
# -- put data in nonexistent file, should end up with a '1'
#
python proggie.py stored-variable.txt
# -- put data in existing file, should end up with '2'
#
python proggie.py stored-variable.txt
# -- put data in existing file, should end up with '22' (2 + 20)
#
python proggie.py stored-variable.txt 20 # -- increment by 20
# -- increment by 20 and sleep 1 second between read/write cycle
# first time should get 42, then 62 ....
#
python proggie.py stored-variable.txt 20 1 # -- sleep
Enjoy, and I hope this little program is instructive,
-Martin
#! /usr/bin/python
#
# -- read the contents of a file
# stuff into a variable
# increment the variable
# write to a file
from __future__ import print_function
import os
import sys
import errno
import time
import logging
logging.basicConfig(stream=sys.stderr, level=logging.INFO)
logger = logging.getLogger(__name__)
def increment(var, step):
return var + step
def read_value(fname):
'''open a file, read an integer, close file, return integer
args: filename
rtrn: an integer (integer representation of file contents)
s-fx: ValueError if contents are not an integer
IOError if cannot read file
'''
with open(fname, 'r') as f:
var = int(f.read())
return var
def read_value_or_return_default(fname, default=0):
'''return value from file or a default if file does not exist (ENOENT)
args: filename (and optional default value)
rtrn: a value
s-fx: catches an ENOENT type of IOError and returns default
IOError if permissions or other issue
'''
try:
var = read_value(fname)
logger.info('Read %10d (file %s existed)', var, fname)
except IOError as e:
if e.errno == errno.ENOENT:
var = default
logger.info('New value %10d (file %s does not exist)', var, fname)
else:
raise
return var
def write_value(fname, var):
'''open a file, write contents of a var, close file
args: filename
rtrn: None
s-fx: IOError if cannot write file
'''
with open(fname, 'w') as f:
f.write(str(var))
logger.info('Stored %10d (file %s tempfile)', var, fname)
def ris(fname, step):
'''read, increment, store in tempfile, atomically replace permanent file
squawk to logging when file has been swapped into place
'''
var = read_value_or_return_default(fname, default=0)
var = increment(var, step)
newfname = fname + '.' + str(time.time())
write_value(newfname, var)
os.rename(newfname, fname)
logger.info('Swapped %10d (file %s)', var, fname)
def cli_ris(fname, step=1):
ris(fname, step)
return os.EX_OK # -- return success to operating system
def cli_loop_ris(fname, step=1, sleeptime=1):
'''run forever reading, incrementing and saving variable to a file'''
while True:
ris(fname, step)
time.sleep(sleeptime)
return os.EX_OK # -- return success to operating system
if __name__ == '__main__':
proggie, args = sys.argv[0], sys.argv[1:]
if len(args) == 1:
fname = args.pop()
sys.exit(cli_ris(fname))
elif len(args) == 2:
fname, step = args
step = int(step)
sys.exit(cli_ris(fname, step=step))
elif len(args) == 3:
fname, step, sleeptime = args
step, sleeptime = int(step), int(sleeptime)
sys.exit(cli_loop_ris(fname, step=step, sleeptime=sleeptime))
else:
sys.exit('Usage: %s <filename> [<step> [<sleeptime>]]' % (proggie))
# -- end of file
--
Martin A. Brown
http://linux-ip.net/
More information about the Tutor
mailing list