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.