2

I need to store the value of a counter between executions of a script, so I can trigger a specific subroutine every hundred counts. I know I can write my integer into a text file and re-read it, and I know I can pickle my variable to much the same effect (the script currently uses the latter approach).

The concern I have is to find the approach that makes the code as elegant - simple and easily comprehensible - as possible, particularly to a non-technical audience.

The pickle module name is not helpful in that regard - once you grok the metaphor, it is entirely memorable, but if you don't know it, a comment (or verbal explanation) is required to explain that it is a module for serialising Python objects to disk.

Although 'nice to have', I'm not particularly concerned about the atomicity of the storage operation, nor about strongly protecting the stored value from loss [although I do need it to persist through a server reboot].

My interest is elegance of code to access and update the value of my variable, not the elegance of code to initialise whatever is storing the value (so, if the value were to be stored in a file, I'm interested in the code to read and write to a file that already exists and holds a value, not in creating the file on first execution).

What is the most elegant (and/or most pythonic) way to store a single (numeric) value so it persists between executions of a script?

  • 1
    [Just store it in the shell environment](https://stackoverflow.com/questions/38982640/set-shell-environment-variable-via-python-script) – Taylor Cochran May 29 '20 at 21:06
  • 4
    Literally any file format? What is incomprehensible to anyone about a text file with a number in it? What do you consider *"elegant"*? – jonrsharpe May 29 '20 at 21:06
  • 3
    I would go with writing to a file. `pickle` is overkill for a single int value. – Code-Apprentice May 29 '20 at 21:06
  • @jonrsharpe - To clarify, it isn't the file I'm storing my value into that I need to be clear, its the code that reads that value in and out. To me elegance connotes brevity and clarity, but I'm open to answers that interpret elegance differently. – Peter Mabbott May 29 '20 at 21:16
  • Then what is unclear about code to read and write a file? Why not just use a sensible function name? This seems opinion based and entirely context dependent - just try something simple and *test that with your audience*. I don't understand why anyone would upvote. – jonrsharpe May 29 '20 at 21:18
  • Using pickle is pythonic ... – juanpa.arrivillaga May 29 '20 at 21:38
  • @jonrsharpe - I can - and have - implemented a solution that is 'good enough'. I don't disagree that I'm asking a question that potentially involves trading off two (or more) variables, making it potentially a contextual opinion call in the end. However, the suggestion by @a_guest objectively exceeds my solution on both measures (its a line shorter, and I can very simply rename the `db` variable to make clearer what is going on) – Peter Mabbott May 29 '20 at 21:39
  • ...where is that solution? Did you test it with your audience, and with what results? What *are* the criteria for exceeding it? Also: why are non-technical people, by which you presumably mean people who don't know about code, trying to read the code (and just *this* bit of it)? – jonrsharpe May 29 '20 at 21:40
  • @jonrsharpe fair point about showing the pickle solution. I've added it. – Peter Mabbott May 29 '20 at 22:06
  • It's still unclear what the *problem* with that is. What's inelegant about it? Does your audience not understand it, and why not, and why does that matter? Any other constraints (e.g. pickle files aren't human-readable - is that pro, con or neutral)? Honestly I think you'd get far further with an intention-revealing function name and appropriate docstring than any amount of yak shaving on the specific implementation: `if execution_count() % 100 == 0: specific_subroutine()`, then literally any implementation with the correct behaviour in that function. – jonrsharpe May 29 '20 at 22:10
  • @jonrsharpe propose it as a solution then, as I have with the two approaches I suggested in the intial post. – Peter Mabbott May 29 '20 at 22:48

3 Answers3

4

The shelve module of the standard library was designed exactly for this use case: object persistence. Here you can simply do:

with shelve.open('counter') as db:
    db['value'] = counter

It will automatically create that file and store the value of the counter in it.

a_guest
  • 34,165
  • 12
  • 64
  • 118
1

This is a take on a 'write to a text file' approach:

with open('counter', 'r') as f:
    value = int(f.read())
# Perform increments to the counter 'value' here
with open('counter', 'w') as f:
    f.write(str(value))

The loss of elegance here is the need to cast the variable from and to a str,but it is clear that you are writing and reading from a file on disk.

0

The pickle approach alluded to in my question is:

import pickle
with open('counter', 'rb') as f:
    value = pickle.load(f)    
# Perform increments to the counter 'value' here
with open('counter', 'wb') as f:
    pickle.dump(value, f)

The loss of elegance here is the need to know what the pickle module does.