Editor's note:
Perhaps the following, taken from the OP's own answer, better illustrates the surprising behavior:f() { local b=1; g; echo $b; }; g() { b=2; }; f # -> '2'
I.e., g()
was able to modify f()
's local $b
variable.
In Zsh and Bash, if I have the following function f() { a=1; g; echo $a; }
and the following function g() { a=2; }
when I run f
, I get the following output instead of the expected:
$ f
2
Is there anyway to disable this variable bleedthrough from function to function?
I'm working on a rather large and important bash/zsh script at work that uses a ton of variables in various functions; many of these functions depend upon a larger master function, however because of the variable bleed through some rather unfortunate and unexpected behavior and bugs have come to the forefront, preventing me from confidently furthering development, since I'd like to address this strange issue first.
I've even tried using local
to localize variables, but the effect still occurs.
EDIT: Note that my question isn't about how to use local variables to prevent variable bleed through or about how local variables work, how to set local variables, how to assign a new value to an already declared local variable, or any of that crap: it is about how to prevent variables from bleeding into the scope of caller/called functions.
Nested functions can access variables of the enclosing scope. In Python, these non-local variables are read-only by default and we must declare them explicitly as non-local (using nonlocal keyword) in order to modify them. Following is an example of a nested function accessing a non-local variable.
The nonlocal keyword is used to work with variables inside nested functions, where the variable should not belong to the inner function. Use the keyword nonlocal to declare that the variable is not local.
Please note that unlike other languages like C, Python doesn't have any separate scope for loops, if/else, etc. Thus, changing variables inside a loop will change the global variable also. After understanding global and local variables, let's dive into the scope of variables in nested functions.
Show activity on this post. The nested function looks up variables from the parent scope when executed, not when defined.
The function or class variables defined inside the function/class etc are function scoped. They are available to use anywhere within the function. You cannot use them outside the function. In the following example, the variable fnVar is defined inside the someFn function. This makes it function scoped. You can access it from within the someFn.
There are different ways to change the value of the local variable of the outer function from the inner function. The first way is to use an iterable. def f1(): #outer function a = def f2(): #outer function a = 2 print (a) #prints 2 f2() print (a) #prints 2 f1()
Using local
creates a variable that is not inherited from the parent scope.
There are useful things to add.
A local variable will be inherited (and can be modified) if the function that declares it calls another function. Therefore, local
protects changes to a variable of the same name inherited from higher in the scope, but not lower in the scope. The local
declaration must therefore be used at each level, unless of course you actually want to alter the value in the parent scope. This is counter to what most programming languages would do, and has advantages (quick and dirty data sharing) but creates difficult to debug failure modes.
A local variable can be exported with local -x
to make it usable by sub-processes (quite useful), or made readonly upon creation with local -r
.
One nice trick is you can initialise a variable with the value inherited from the parent scope at the time of creation :
local -r VAR="$VAR"
If, like me, you always use set -u
to avoid silently using uninitialized variables, and cannot be sure the variable already is assigned, you can use this to initialize it with an empty value if it is not defined in the parent scope:
local -r VAR="${VAR-}"
I feel like an idiot for not realizing this sooner; I'm going to go ahead and post this question & answer anyway, just in case other scrubs like me encounter the same issue: you have to declare both variables as local:
f() { local b=1; g; echo $b; }
g() { b=2; }
f
# output: 2
f() { local b=1; g; echo $b; }
g() { local b=2; }
f
# output: 1
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With