Quantcast
Channel: Planet Python
Viewing all articles
Browse latest Browse all 22851

The Lunar Cowboy: Historical Values in Python

$
0
0

Often in programming we have some "constant" value that we define as a variable in Python. But the only try constant is change.

Consider for example you have a program that needs to process a file with a certain filename. So you might have something like:

FILENAME="foo.txt"data=Path(FILENAME).read_text(encoding="UTF-8")

This program is installed and runs for a while, but then at some point it is decided that instead of "foo.txt" we want the file name to be "bar.txt". It's easy to change our FILENAME variable to "bar.txt", but what about those existing systems that ran the program and have the filename foo.txt? You might see something like this:

FILENAME="bar.txt"OLD_FILENAME="foo.txt"if(path:=Path(OLD_FILENAME)).exists():path=path.rename(FILENAME)else:path=Path(FILENAME)

I was thinking wouldn't it be nice if FILENAME knew its old value? Wouldn't it even be nicer if FILENAME knew about all it's "historic values"? That's when I came up with something like this:

classHistory:def__new__(cls,history):hist=[*history]value=hist[-1]base=type(value)returnbase.__new__(type("History",(History,base),{"_history":hist}),value)@propertydefprevious(self):returntype(self)(self._history[:-1])@propertydeffirst(self):returntype(self)([self._history[0]])def__getattr__(self,name):ifnotname.startswith("v"):raiseAttributeError(name)version=int(name[1:])ifname[1:].isdigit()else0if0<version<=len(self._history):returntype(self)(self._history[:version])raiseValueError(f"Invalid version: {name}")

Instances of the History class look like plain values but have a history, for example:

>>>FILENAME=History(["foo.txt","bar.txt","baz.txt"])>>>FILENAME'baz.txt'>>>FILENAME.previous'bar.txt'>>>FILENAME.previous.previous'foo.txt'>>>FILENAME.v1'foo.txt'

So now let's rewrite the previous code example:

FILENAME=History(["foo.txt","bar.txt"])if(path:=Path(FILENAME.previous)).exists():path=path.rename(FILENAME)else:path=Path(FILENAME)

I probably wouldn't do anything like this in production code, but I do think it's pretty intersting and demonstrates the flexibility of Python for creating "Pythonic" interfaces.


Viewing all articles
Browse latest Browse all 22851

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>