On Thu, May 27, 2021 at 8:19 AM Steven D'Aprano steve@pearwood.info wrote:
On Thu, May 27, 2021 at 07:56:16AM -0000, Shreyan Avigyan wrote:
This idea proposes to add a keyword (static, maybe?) that can create static variables that can persist throughout the program yet only accessible through the function they are declared and initialized in.
Here is a sketch of how this could work, given a function like this:
def func(arg): static spam, eggs static cheese = expression ...
At function declaration time, the two static statements tell the compiler to:
treat spam, eggs and cheese as local variables (use LOAD_FAST instead of LOAD_GLOBAL for lookups);
allocate static storage for them using the same (or similar) mechanism used for function default values;
spam and eggs get initialised as None;
cheese gets initialised to the value of `expression`, evaluated at function declaration time just as default arguments are.
When the function is called:
the interpreter automatically initialises the static variables with the stored values;
when the function exits (whether by return or by raising an exception) the static storage will be updated with the current values of the variables.
As a sketch of one possible implementation, the body of the function represented by ellipsis `...` might be transformed to this:
# initialise statics spam = LOAD_STATIC(0) eggs = LOAD_STATIC(1) cheese = LOAD_STATIC(2) try: # body of the function ... finally: STORE_STATIC(spam, 0) STORE_STATIC(eggs, 1) STORE_STATIC(cheese, 2)
Couldn't you already get pretty close to this by attaching your static values to the function __dict__?
Example:
def func(): print(func.a) func.a = 1
Usage:
func()
1
Of course that is slower because there is an attribute lookup.
But could there be a decorator that links the function __dict__ to locals(), so they are intertwined?
@staticify({ 'a':1}) def func(): print(a) print(b) func.b = 2
Usage:
func()
1 2
func.a = 3 # dynamic update of func.__dict__ func()
3 2
The locals dict in the function body would look something like this:
ChainMap(locals(), {'a':1})
--- Ricky.
"I've never met a Kentucky man who wasn't either thinking about going home or actually going home." - Happy Chandler
One subtlety: what if the body of the function executes `del spam`? No problem: the spam variable will become undefined on the next function call, which means that subsequent attempts to get its value will raise UnboundLocalError:
try: x = spam + 1 except UnboundLocalError: spam = 0 x = 1
I would use this static feature if it existed. +1
-- Steve
Same thing would happen with my idea: del a would delete a from the func.__dict__ (just like with ChainMap). But if you add it back again later, it would not be static anymore.
Example:
@staticify('a': 1) def func(): print(a) # fast static lookup del a # static is deleted a = 2 # this is local now func.b = 3 # but this is a static