Global variable not defined even though it appears in globals() - python

I wrote this code:
def openFile():
f = open("test.txt", "r")
mainInput = f.read()
global tupleMain
tupleMain = [tuple(mainInput.split(" ")) for mainInput in mainInput.strip(",").split("\n")]
As you can see, I have defined tupleMain as a global variable, but when I try to use it outside the function, I get:
NameError: name 'tupleMain' is not defined
If I run:
is_global = "tupleMain" in globals()
print(is_global)
The output is:
True
I just don't get why it says it's not defined if it's in globals() and have set it to global.
Thanks in advance
EDIT: I use the variable in the following function:
def tableFunction():
fname = [x[2] for x in tupleMain]
sname = [x[3] for x in tupleMain]
position = [x[1] for x in tupleMain]
salary = [x[4] for x in tupleMain]
team = [x[0] for x in tupleMain]
playerTable = PrettyTable()
playerTable.field_names= ["Surname", "First Name", "Salary", "Position", "Team"]
for x in tupleMain:
playerTable.add_row([x[3], x[2], x[4], x[1], x[0]])
print(playerTable)

You never called the function before using the global variable it declares in some other function, so the code inside the function which declares the variable as global never got executed. You need to at-least execute or call the function before referencing the global variable.
Either call the function before you use the global variable elsewhere or define the global variable at the module level inside your code.

Related

How to access the nonlocal variable in enclosing function from inner function if inner function already has its variable with the same name Python

I need to find the way to reference variable x = "Nonlocal" from inner_function_nonlocal(). Probably, the way how I referenced the x = "Global": globals()['x'], but I need your help with that one, please!
Please note: I can NOT comment or delete x = "Local" in order to write nonlocal x instead of it.
x = "Global"
def enclosing_funcion():
x = "Nonlocal"
def inner_function_global():
x = "Local"
print(globals()['x']) # Call the global a
def inner_function_nonlocal():
x = "Local" # <- This line can NOT be commented!!!
print(_?_?_?_?_) # <- What should I specify here in order to print x which is nonlocal?
inner_function_global()
inner_function_nonlocal()
if __name__ == '__main__':
enclosing_funcion()
output should be:
Global (this is already achieved)
Nonlocal (need help to get this one)
You can add a method to get at the Nonlocal value:
x = "Global"
def enclosing_funcion():
x = "Nonlocal"
def non_local():
return x
def inner_function_global():
x = "Local"
print(globals()['x']) # Call the global a
def inner_function_nonlocal():
x = "Local" # <- This line can NOT be commented!!!
print(non_local()) # <- What should I specify here in order to print x which is nonlocal?
inner_function_global()
inner_function_nonlocal()
if __name__ == '__main__':
enclosing_funcion()
Result:
Global
Nonlocal

New to using functions in Python

I am trying to understand why newNameList is not defined:
ListofNames1 = ['Mark', 'Andrew']
ListofNames2 = ['Anjela', 'Lora']
names = ListofNames1
def greeting(names):
newNameList = []
for item in names:
newNameList.append(str(names))
return (names)
print(greeting(names))
def function2(newNameList):
for each in newNameList:
newNameList2.append(newNameList.upper())
return (newNameList2)
print(function2(newNameList))
The output
['Mark', 'Andrew']
...
NameError: name 'newNameList' is not defined.
The name error occurs on the last line in the code.
newNameList is only defined within the scope of function2. Since the print statement is not indented at the same level of function2 then newNameList is not visible to it. The three variables defined at a top-level scope are ListofNames1, ListofNames1, and names. These are the only three variables that can be passed to function2 in the print statement.
Yes, You can do it.
For example:
def use_greeting_function(name):
new_list_name = greeting(name)
Now new_list_name has the output of greeting function and you can use it in the function afterwards.
NameError: name 'newNameList' is not defined.
tells you what's wrong. You should have defined newNameList outside the greetings() function.
I have rewritten your code:
ListofNames1 = ['Mark', 'Andrew']
ListofNames2 = ['Anjela', 'Lora']
names = ListofNames1
newNameList = []
def greeting(names):
for item in names:
newNameList.append(names)
return names
print(greeting(names))
def function2(newNameList):
newNameList2 = []
for each in newNameList:
newNameList2.append(str(newNameList).upper())
return newNameList2
print(function2(newNameList))
And using the upper() method on a list doesn't work. Convert it to str first.

Variable binding time in Python closures

From Python's Programming FAQ, this doesn't work as many people expect:
>>> squares = []
>>> for x in range(5):
... squares.append(lambda: x**2)
>>> squares[2]() # outputs 16, not 4
The following explanation is offered:
This happens because x is not local to the lambdas, but is defined in
the outer scope, and it is accessed when the lambda is called --- not
when it is defined.
This is fine. However, the explanation does not sound entirely correct to me. Consider this:
def buildFunction():
myNumber = 6 # Won't compile without this line
def fun():
return myNumber
return fun
def main():
myNumber = 3 # Ignored
myFun = buildFunction()
myNumber = 3 # Ignored
print(myFun()) # prints 6, not 3
This makes sense, but can someone please offer a more accurate/general definition of when variable binding of Python closures occurs?
Consider this:
def main():
def buildFunction():
def fun():
return myNumber
return fun
myNumber = 3 # can use this...
myFun = buildFunction()
myNumber = 3 # ... or this
print(myFun()) # prints 3 this time
This is more comparable to the lambda example because the closure function is nested within the scope that declares the variable of interest. Your example had two different scopes so had two, completely unrelated, myNumbers.
In case you haven't come across the nonlocal keyword, can you guess what this will print?
def main():
def buildFunction():
nonlocal myNumber
myNumber = 6
def fun():
return myNumber
return fun
myNumber = 3
myFun = buildFunction()
# myNumber = 3
print(myFun())
Every variable has a scope.
Name lookup (getting the value that the name points to) resolves by default to the most inner scope.
You can only override names in local scope or a containing scope(using the keywords nonlocal and global).
In your second example in main you assign myNumber to a different scope that your fun function can access.
squares = []
for x in range(5):
squares.append(lambda: x**2) # scope = global / lambda
print(squares[2]())
def buildFunction():
myNumber = 6 # scope = global / buildFunction
def fun():
return myNumber # scope = global / buildFunction / fun
return fun
myNumber = 1 # scope = global
def main():
myNumber = 3 # scope = global / main. Out of scope for global / buildFunction
myFun = buildFunction()
print(myFun())
When fun is called, Python looks at fun's local scope and can't find myNumber.
So it looks at its containing scope.
The buildFunction scope has myNumber in scope (myNumber = 6) so fun returns 6.
If buildFunction did not have myNumber in scope then Python looks at the next scope.
In my version the global scope has myNumber = 1
So fun would return 1.
If myNumber also does not exist in the global scope, a NameError is raised because myNumber could not be found in local scope nor any of its containing scopes.

Global variable's value lost between function calls in python

I know I must have missed something basic -- just want to make sure I get the precise answer.
I have the following code. Why CACHE_KEYS is still None after load() while CACHE is not?
import bisect
import csv
DB_FILE = "GeoLiteCity-Location.csv"
# ['locId', 'country', 'region', 'city', 'postalCode', 'latitude', 'longitude', 'metroCode', 'areaCode']
CACHE = []
CACHE_KEYS = None
def load():
R = csv.reader(open(DB_FILE))
for line in R:
CACHE.append(line)
# sort by city
CACHE.sort(key=lambda x: x[3])
CACHE_KEYS = [x[3] for x in CACHE]
if __name__ == "__main__":
load()
# test
# print get_geo("Ruther Glen")
I think making it global would work. Any variable defined in the global scope which is to be edited should be specified as global in that function. Your code just makes a local variable CACHE_KEYS and stores the information correctly. But, to make sure that it is copied to the global variable, declare the variable as global in the function. You call the append function on CACHE and hence that works fine. Your code after the changes.
import bisect
import csv
DB_FILE = "GeoLiteCity-Location.csv"
# ['locId', 'country', 'region', 'city', 'postalCode', 'latitude', 'longitude', 'metroCode', 'areaCode']
CACHE = []
CACHE_KEYS = None
def load():
R = csv.reader(open(DB_FILE))
for line in R:
CACHE.append(line)
# sort by city
CACHE.sort(key=lambda x: x[3])
global CACHE_KEYS
CACHE_KEYS = [x[3] for x in CACHE]
if __name__ == "__main__":
load()
Anytime you assign a value to a global variable you have to declare it as global. See the following code snippet.
listOne = []
def load():
listOne+=[2]
if __name__=="__main__":
load()
The above code has an assignment and not an append call. This gives the following error.
UnboundLocalError: local variable 'listOne' referenced before assignment
But, executing the following snippet.
listOne = []
def load():
listOne.append(2)
if __name__=="__main__":
load()
gives the following output.
>>> print listOne
[2]
The thing is in
CACHE_KEYS = [x[3] for x in CACHE]
CACHE_KEYS is defined in the global scope. In the above line, you are assigning it a new value, bringing it into the local scope, In order to manipulate the variable in a function (and keep it's value later), global it :
def load():
global CACHE_KEYS
...
CACHE.sort(key=lambda x: x[3])
CACHE_KEYS = [x[3] for x in CACHE]

How to refer to the local module in Python?

Let's say we have a module m:
var = None
def get_var():
return var
def set_var(v):
var = v
This will not work as expected, because set_var() will not store v in the module-wide var. It will create a local variable var instead.
So I need a way of referring the module m from within set_var(), which itself is a member of module m. How should I do this?
def set_var(v):
global var
var = v
The global keyword will allow you to change global variables from within in a function.
As Jeffrey Aylesworth's answer shows, you don't actually need a reference to the local module to achieve the OP's aim. The global keyword can achieve this aim.
However for the sake of answering the OP title, How to refer to the local module in Python?:
import sys
var = None
def set_var(v):
sys.modules[__name__].var = v
def get_var():
return var
As a follow up to Jeffrey's answer, I would like to add that, in Python 3, you can more generally access a variable from the closest enclosing scope:
def set_local_var():
var = None
def set_var(v):
nonlocal var
var = v
return (var, set_var)
# Test:
(my_var, my_set) = set_local_var()
print my_var # None
my_set(3)
print my_var # Should now be 3
(Caveat: I have not tested this, as I don't have Python 3.)

Categories