2

Is there a way to SAVE the value of a variable (say an integer) in python? My problem involves calling (entering and exiting) multiple times the same python script (python file, not python function) which in the end creates a txt file. I'd like to name the txt files depending on the number of times the python code was called: txt1.txt,..., txt100.txt for example.

EDIT: The question is not related with the SAVE parameter in fortran. My mistake.

6
  • what have you tried so far? give it a go, maybe try looking on google 'compose python strings' (to create your filename) and then 'create file with python' and it should come up fairly easy to understand :) Commented May 2, 2013 at 15:59
  • The pickle and shelf modules both provide some interface for storing some constant values in files that persist between executions of a program. I'd look into those to start. Commented May 2, 2013 at 16:02
  • You might want to tell users that Fortran's save works like C's static to clarify what you mean. There are more C users here than Fortran ones. Commented May 2, 2013 at 16:16
  • post edit: so are you wondering how to write a text file, or do you want to know how to preserve a variable's value across calls to a function? Commented May 2, 2013 at 16:17
  • 3
    Your clarification here is good ... But you still need to explain better what you mean by "entering and exiting the same python code". that could easily be interpreted as entering and exiting the same function within a script or calling the script multiple times. Commented May 2, 2013 at 16:17

3 Answers 3

7

Not really. The best you can do is to use a global variable:

counter = 0
def count():
    global counter
    counter += 1
    print counter

An alternative which bypasses the need for the global statement would be something like:

from itertools import count
counter = count()
def my_function():
    print next(counter) 

or even:

from itertools import count
def my_function(_counter=count()):
    print next(_counter)

A final version takes advantage of the fact that functions are first class objects and can have attributes added to them whenever you want:

def my_function():
    my_function.counter += 1
    print my_function.counter

my_function.counter = 0 #initialize.  I suppose you could think of this as your `data counter /0/ statement.

However, it looks like you actually want to save the count within a file or something. That's not too hard either. You just need to pick a filename:

def count():
    try:
        with open('count_data') as fin:
            i = int(count_data.read())
    except IOError:
        i = 0
    i += 1
    print i
    with open('count_data','w') as fout:
        fout.write(str(i))
Sign up to request clarification or add additional context in comments.

16 Comments

@HenryKeiter -- Do you know fortran? (I do -- pretty well). I believe that it answers the question just fine. when you exit a function, in python, everything is gone. There is no save.
@HenryKeiter: what exactly do you think the question is?
@HenryKeiter -- That's not what save does in fortran. save does nothing between invocations of the program.
@jpcgandre -- Wait. You mean python myscript gives file1 then python myscript gives file2 and so on? Because you won't get that with fortran's save. you need to clarify what you're asking here ...
@jpcgandre: wait, what? So by like the fortran save you mean "nothing at all like the fortran save"? Fortran's save doesn't serialize.
|
5

NOTE: I'm assuming that what you mean by:

calling (entering and exiting) multiple times the same python code

is that you want to call the whole Python script multiple times, in which case you need to serialize your counter in some way external to the Python interpreter, to make it available next time. If you're just asking about calling the same function or method several times within one Python session, you can do that a variety of ways and I'd point you to mgilson's answer.

There are plenty of ways to serialize things, but your implementation doesn't really have anything to do with the language. Do you want to store it in a database? Write the value to a file? Or is it enough to just retrieve an appropriate value from context? For instance, this code will get you a new file each time it is called, based on the contents of output_dir. It's obviously rough, but you get the idea:

import os

def get_next_filename(output_dir):
    '''Gets the next numeric filename in a sequence.

    All files in the output directory must have the same name format,
    e.g. "txt1.txt".
    '''

    n = 0
    for f in os.listdir(output_dir):
        n = max(n, int(get_num_part(os.path.splitext(f)[0])))
    return 'txt%s.txt' % (n + 1)

def get_num_part(s):
    '''Get the numeric part of a string of the form "abc123".

    Quick and dirty implementation without using regex.'''

    for i in xrange(len(s)):
        if s[i:].isdigit():
            return s[i:]
    return ''

Or of course you can just write a file called something like runnum.cfg somewhere next to the Python script, and write your current run number into it, then read that when the code launches.

4 Comments

I like the directory scanning to get the next number approach. +1.
This "let the files themselves be the system state" pattern is one I often use myself.
@HenryKeiter: I believe you assume a file already exists in the folder. Am I right?
@jpcgandre I was when I first wrote it, but I've since edited the answer so it'll work whether or not any files already exist in the folder. (Just change n to begin at 0 instead of 1).
1

mgilson's response provides good options to the original question. Another approach is to refactor the code to separate the concerns of choosing filenames from computing + saving. Here's a code sketch:

for i in ...:
   filename = 'txt%d.txt' % (i,)
   do_something_then_save_results(..., filename)

If you need to do this in a lot of places and want to reduce code duplication, a generator function can be useful:

def generate_filenames(pattern, num):
   for i in xrange(num):
       yield pattern % (i,)

...
for filename in generate_filenames('txt%d.txt', ...):
   do_something_then_save_results(..., filename)

Replace "..." with whatever's meaningful in your application.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.