Python nested functions variable scoping
When I run your code I get this error:
UnboundLocalError: local variable '_total' referenced before assignment
This problem is caused by this line:
_total += PRICE_RANGES[key][0]
The documentation about Scopes and Namespaces says this:
A special quirk of Python is that – if no
global
statement is in effect – assignments to names always go into the innermost scope. Assignments do not copy data — they just bind names to objects.
So since the line is effectively saying:
_total = _total + PRICE_RANGES[key][0]
it creates _total
in the namespace of recurse()
. Since _total
is then new and unassigned you can't use it in the addition.
Access variable from function inside of nested function
You have two options:
Give $content
as a parameter
function foo() {
$content = 'foobar';
function bar($content) {
echo $content; // echos something
}
}
Take $content
outside of the function and use global there.
$content = '';
function foo() {
global $content;
$content .= 'foobar';
function bar($content) {
global $content;
echo $content; // echos something
}
}
Variable scope in Python nested function
It seems this is a commonly asked question as stated in this link. The reason is that variable a
inside swim
becomes a local variable as soon as there is an assignment to a
. It shadows the external a
, and local a
is not defined before assignment in function swim
, so the error rises.
Thanks for all your guys' answers!
Using 'get' Inside Nested Functions on Local Variables
Since you are asking, this definitely looks like a bad design to me. The recommended approach is to stick to R's way of pass-by-value. And as much as possible, make every function take everything it uses as arguments:
test1 <- function(a1, b1, c1 = 1) {
testvalue <- c1 * a1 * b1
testvalue
}
test2 <- function(cc = 1) {
a <- 1
b <- 2
test1(a1 = a, b1 = b, c1 = cc)
}
cc <- 3
test2(cc = cc)
(I replaced c
with cc
since it is the name of a function, hence a bad idea to use as variable name.)
A less acceptable but maybe closer approach to what you have is to not pass all arguments to your functions and let R look for them in the calling stack:
test1 <- function(a1, b1) {
testvalue <- cc * a1 * b1
testvalue
}
test2 <- function() {
a <- 1
b <- 2
test1(a, b)
}
cc <- 3
test2()
If for some reason the first approach does not work for you, please explain why so I get a chance to maybe convince you otherwise. It is the recommended way of programming in R.
Following on the discussion and your edit, I'll recommend you look at the proto
package as an alternative to get
and assign
. Essentially, proto objects are environments so it's nothing you can't do with base
R but it helps make things a bit cleaner:
test1 <- function(x) {
testvalue <- x$c * x$a * x$b
x$a <- 3.5
testvalue
}
test2 <- function(x) {
x$a <- 1
x$b <- 2
cat(x$a, '\n')
test1(x)
cat(x$a, '\n')
}
library(proto)
x <- proto(c = 3)
test2(x)
From a programming point of view, test1
and test2
are functions with side-effects (they modify the object x
). Beware that its a risky practice.
Or maybe a better approach is to make test1
and test2
be methods of a class, then it is acceptable if they modify the instance they are running on:
x <- proto() # defines a class
x$test1 <- function(.) {
testvalue <- .$c * .$a * .$b
.$a <- 3.5
testvalue
}
x$test2 <- function(.) {
.$a <- 1
.$b <- 2
cat(.$a, '\n')
.$test1()
cat(.$a, '\n')
}
library(proto)
y <- x$proto(c = 3) # an instance of the class
y$test2()
If you are not interested in using a third-party package (proto
), then look at R's support for building classes (setClass
, setRefClass
). I do believe using an object-oriented design is the right approach given your specs.
Using Global Variables inside a Nested Function in Python
In add
, x
is not a global variable; it's local to add
. You either need to make it global as well, so that add
and change
are referring to the same variable
def add():
global x
x = 15
def change():
global x
x = 20
print("Before making changes: ", x)
print("Making change")
change()
print("After making change: ", x)
add()
print("value of x",x)
or you need to declare x
in change
as nonlocal, rather than global.
def add():
x = 15
def change():
nonlocal x
x = 20
print("Before making changes: ", x)
print("Making change")
change()
print("After making change: ", x)
add()
print("value of x",x)
Local variables in nested functions
The nested function looks up variables from the parent scope when executed, not when defined.
The function body is compiled, and the 'free' variables (not defined in the function itself by assignment), are verified, then bound as closure cells to the function, with the code using an index to reference each cell. pet_function
thus has one free variable (cage
) which is then referenced via a closure cell, index 0. The closure itself points to the local variable cage
in the get_petters
function.
When you actually call the function, that closure is then used to look at the value of cage
in the surrounding scope at the time you call the function. Here lies the problem. By the time you call your functions, the get_petters
function is already done computing it's results. The cage
local variable at some point during that execution was assigned each of the 'cow'
, 'dog'
, and 'cat'
strings, but at the end of the function, cage
contains that last value 'cat'
. Thus, when you call each of the dynamically returned functions, you get the value 'cat'
printed.
The work-around is to not rely on closures. You can use a partial function instead, create a new function scope, or bind the variable as a default value for a keyword parameter.
Partial function example, using
functools.partial()
:from functools import partial
def pet_function(cage=None):
print "Mary pets the " + cage.animal + "."
yield (animal, partial(gotimes, partial(pet_function, cage=cage)))Creating a new scope example:
def scoped_cage(cage=None):
def pet_function():
print "Mary pets the " + cage.animal + "."
return pet_function
yield (animal, partial(gotimes, scoped_cage(cage)))Binding the variable as a default value for a keyword parameter:
def pet_function(cage=cage):
print "Mary pets the " + cage.animal + "."
yield (animal, partial(gotimes, pet_function))
There is no need to define the scoped_cage
function in the loop, compilation only takes place once, not on each iteration of the loop.
Why nested functions can access variables from outer functions, but are not allowed to modify them
def f1():
x = { 'value': 5 }
def f2():
x['value'] += 1
Workaround is to use a mutable object and update members of that object. Name binding is tricky in Python, sometimes.
Related Topics
Execute Python Script Via Crontab
How to Make a Python Script Run Like a Service or Daemon in Linux
Python Pysftp Get_R from Linux Works Fine on Linux But Not on Windows
Why Is Printing to Stdout So Slow? Can It Be Sped Up
Use the Default Python Rather Than the Anaconda Installation When Called from the Terminal
Os.Walk Without Hidden Folders
Python Script as Linux Service/Daemon
Call to Operating System to Open Url
Can Python Select What Network Adapter When Opening a Socket
What Do I Use on Linux to Make a Python Program Executable
Cqlsh Connection Error: 'Ref() Does Not Take Keyword Arguments'
Linux Command-Line Call Not Returning What It Should from Os.System
Uninstall Python Built from Source
Set Chrome Browser Binary Through Chromedriver in Python