variable not passed to lower level? - python

I understand that variables in python are always (?) available in subfunctions.
That is why this works:
def abc():
print(a)
def main():
abc()
pass
if __name__=='__main__':
a = 'a'
main()
However, why does it not work if the definition of ais moved to main()?
def abc():
print(a)
def main():
a = 'a'
abc()
pass
if __name__=='__main__':
main()
It is still defined before it is used and should be available in abc(), right?

No, variables defined in a function are scoped to the function by default. To make it available in abc() you would need to make it global:
def main():
global a
a = 'a'
abc()
As for the 'shadowing' warning, you get it when you redefine names at inner scopes. For example, this code creates a global variable a:
if __name__ == '__main__':
a = 'a'
main()
Now if you do a = 'b' inside main() you are effectively 'shadowing' a from the outer scope by creating a local variable with the same name.

In the first code sample, 'a' is defined as a global variable. Meaning that it can be accessed by any function called after it is instantiated.
In the second code sample, 'a' is defined as a local variable. Meaning that it only exists within the "main" function. If you wanted to pass it into the "abc" function, you would have to explicitly pass that variable. That would look like:
def abc(a):
print(a)
def main():
a = 'a'
abc(a)
pass
if __name__=='__main__':
main()

Variables at the module level of your function are available to read anywhere else in the module. When you do
if __name__=='__main__':
a = 'a'
you are defining a as a module-level variable, hence why you can read it inside abc(). This is similar to why you can see your imports within other functions.
When you define a inside abc(), it's no longer at the module-level and no longer is implicitly readable elsewhere in the module.
As an aside, global variables are usually a bad idea, it's better to pass them around explicitly. See http://wiki.c2.com/?GlobalVariablesAreBad for a good summary of why.

Related

I declared variable t1 outside the function but was able to use it without using global keyword but for counta and counto I have to use global why? [duplicate]

From my understanding, Python has a separate namespace for functions, so if I want to use a global variable in a function, I should probably use global.
However, I was able to access a global variable even without global:
>>> sub = ['0', '0', '0', '0']
>>> def getJoin():
... return '.'.join(sub)
...
>>> getJoin()
'0.0.0.0'
Why does this work?
See also UnboundLocalError on local variable when reassigned after first use for the error that occurs when attempting to assign to the global variable without global. See Using global variables in a function for the general question of how to use globals.
The keyword global is only useful to change or create global variables in a local context, although creating global variables is seldom considered a good solution.
def bob():
me = "locally defined" # Defined only in local context
print(me)
bob()
print(me) # Asking for a global variable
The above will give you:
locally defined
Traceback (most recent call last):
File "file.py", line 9, in <module>
print(me)
NameError: name 'me' is not defined
While if you use the global statement, the variable will become available "outside" the scope of the function, effectively becoming a global variable.
def bob():
global me
me = "locally defined" # Defined locally but declared as global
print(me)
bob()
print(me) # Asking for a global variable
So the above code will give you:
locally defined
locally defined
In addition, due to the nature of python, you could also use global to declare functions, classes or other objects in a local context. Although I would advise against it since it causes nightmares if something goes wrong or needs debugging.
While you can access global variables without the global keyword, if you want to modify them you have to use the global keyword. For example:
foo = 1
def test():
foo = 2 # new local foo
def blub():
global foo
foo = 3 # changes the value of the global foo
In your case, you're just accessing the list sub.
This is the difference between accessing the name and binding it within a scope.
If you're just looking up a variable to read its value, you've got access to global as well as local scope.
However if you assign to a variable who's name isn't in local scope, you are binding that name into this scope (and if that name also exists as a global, you'll hide that).
If you want to be able to assign to the global name, you need to tell the parser to use the global name rather than bind a new local name - which is what the 'global' keyword does.
Binding anywhere within a block causes the name everywhere in that block to become bound, which can cause some rather odd looking consequences (e.g. UnboundLocalError suddenly appearing in previously working code).
>>> a = 1
>>> def p():
print(a) # accessing global scope, no binding going on
>>> def q():
a = 3 # binding a name in local scope - hiding global
print(a)
>>> def r():
print(a) # fail - a is bound to local scope, but not assigned yet
a = 4
>>> p()
1
>>> q()
3
>>> r()
Traceback (most recent call last):
File "<pyshell#35>", line 1, in <module>
r()
File "<pyshell#32>", line 2, in r
print(a) # fail - a is bound to local scope, but not assigned yet
UnboundLocalError: local variable 'a' referenced before assignment
>>>
The other answers answer your question. Another important thing to know about names in Python is that they are either local or global on a per-scope basis.
Consider this, for example:
value = 42
def doit():
print value
value = 0
doit()
print value
You can probably guess that the value = 0 statement will be assigning to a local variable and not affect the value of the same variable declared outside the doit() function. You may be more surprised to discover that the code above won't run. The statement print value inside the function produces an UnboundLocalError.
The reason is that Python has noticed that, elsewhere in the function, you assign the name value, and also value is nowhere declared global. That makes it a local variable. But when you try to print it, the local name hasn't been defined yet. Python in this case does not fall back to looking for the name as a global variable, as some other languages do. Essentially, you cannot access a global variable if you have defined a local variable of the same name anywhere in the function.
Accessing a name and assigning a name are different. In your case, you are just accessing a name.
If you assign to a variable within a function, that variable is assumed to be local unless you declare it global. In the absence of that, it is assumed to be global.
>>> x = 1 # global
>>> def foo():
print x # accessing it, it is global
>>> foo()
1
>>> def foo():
x = 2 # local x
print x
>>> x # global x
1
>>> foo() # prints local x
2
You can access global keywords without keyword global
To be able to modify them you need to explicitly state that the keyword is global. Otherwise, the keyword will be declared in local scope.
Example:
words = [...]
def contains (word):
global words # <- not really needed
return (word in words)
def add (word):
global words # must specify that we're working with a global keyword
if word not in words:
words += [word]
This is explained well in the Python FAQ
What are the rules for local and global variables in Python?
In Python, variables that are only referenced inside a function are implicitly global. If a variable is assigned a value anywhere within the function’s body, it’s assumed to be a local unless explicitly declared as global.
Though a bit surprising at first, a moment’s consideration explains this. On one hand, requiring global for assigned variables provides a bar against unintended side-effects. On the other hand, if global was required for all global references, you’d be using global all the time. You’d have to declare as global every reference to a built-in function or to a component of an imported module. This clutter would defeat the usefulness of the global declaration for identifying side-effects.
https://docs.python.org/3/faq/programming.html#what-are-the-rules-for-local-and-global-variables-in-python
Any variable declared outside of a function is assumed to be global, it's only when declaring them from inside of functions (except constructors) that you must specify that the variable be global.
global makes the variable visible to everything in the module, the modular scope, just as if you had defined it at top-level in the module itself. It's not visible outside the module, and it cannot be imported from the module until after it has been set, so don't bother, that's not what it is for.
When does global solve real problems? (Note: Checked only on Python 3.)
# Attempt #1, will fail
# We cannot import ``catbus`` here
# as that would lead to an import loop somewhere else,
# or importing ``catbus`` is so expensive that you don't want to
# do it automatically when importing this module
top_level_something_or_other = None
def foo1():
import catbus
# Now ``catbus`` is visible for anything else defined inside ``foo()``
# at *compile time*
bar() # But ``bar()`` is a call, not a definition. ``catbus``
# is invisible to it.
def bar():
# `bar()` sees what is defined in the module
# This works:
print(top_level_something_or_other)
# This doesn't work, we get an exception: NameError: name 'catbus' is not defined
catbus.run()
This can be fixed with global:
# Attempt #2, will work
# We still cannot import ``catbus`` here
# as that would lead to an import loop somewhere else,
# or importing ``catbus`` is so expensive that you don't want to
# do it automatically when importing this module
top_level_something_or_other = None
def foo2():
import catbus
global catbus # Now catbus is also visible to anything defined
# in the top-level module *at runtime*
bar()
def bar():
# `bar` sees what is defined in the module and when run what is available at run time
# This still works:
print(top_level_something_or_other)
# This also works now:
catbus.run()
This wouldn't be necessary if bar() was defined inside foo like so:
# Attempt 3, will work
# We cannot import ``catbus`` here
# as that would lead to an import loop somewhere else,
# or importing ``catbus`` is so expensive that you don't want to
# do it automatically when importing this module
top_level_something_or_other = None
def foo3():
def bar():
# ``bar()`` sees what is defined in the module *and* what is defined in ``foo()``
print(top_level_something_or_other)
catbus.run()
import catbus
# Now catbus is visible for anything else defined inside foo() at *compile time*
bar() # Which now includes bar(), so this works
By defining bar() outside of foo(), bar() can be imported into something that can import catbus directly, or mock it, like in a unit test.
global is a code smell, but sometimes what you need is exactly a dirty hack like global. Anyway, "global" is a bad name for it as there is no such thing as global scope in python, it's modules all the way down.
It means that you should not do the following:
x = 1
def myfunc():
global x
# formal parameter
def localfunction(x):
return x+1
# import statement
import os.path as x
# for loop control target
for x in range(10):
print x
# class definition
class x(object):
def __init__(self):
pass
#function definition
def x():
print "I'm bad"
Global makes the variable "Global"
def out():
global x
x = 1
print(x)
return
out()
print (x)
This makes 'x' act like a normal variable outside the function. If you took the global out then it would give an error since it cannot print a variable inside a function.
def out():
# Taking out the global will give you an error since the variable x is no longer 'global' or in other words: accessible for other commands
x = 1
print(x)
return
out()
print (x)

Why can I access variables that are conditionally defined outside of function in Python?

I am coming from C, C++, and Java background. So I am curious to know why the following Python code works:
def f1():
print(xy)
if __name__ == "__main__":
print("Hello")
xy = 34
f1()
It prints:
Hello
34
How can I access xy in function f1? xy is not defined inside f1 also, xy is defined in a conditional block of if __name__ == "__main__"?
Global Variables
In Python, a variable declared outside of the function or in global
scope is known as global variable. This means, global variable can be
accessed inside or outside of the function.
While in many or most other programming languages variables are treated as global if not otherwise declared, Python deals with variables the other way around. They are local, if not otherwise declared.
def f():
print(x)
x = "Something"
f()
This prints "Something"

Global Variable Python

A=[]
def main():
global A
A=[1,2,3,4,5]
b()
def b():
if(len(A)>0):
A=[7,8,9]
else:
if(A[3]==4):
A.remove(2)
main()
This code gives error in line A.remove(2) giving reason:"UnboundLocalError: local variable 'A' referenced before assignment"
but A list is global and for sure it has been initialized in main() function.Please explain why this is giving error?
As A has been initialized again in b function, will this cause error?
The reason you are getting this is because when you performed this assignment in your function:
A = [7, 8, 9]
The interpreter will now see A as a locally bound variable. So, what will happen now, looking at this condition:
if(len(A)>0):
Will actually throw your first UnboundLocalError exception, because, due to the fact, as mentioned, you never declared global A in your b function and you also created a locally bound variable A = [7, 8, 9], you are trying to use a local A before you ever declared it.
You actually face the same issue when you try to do this:
A.remove(2)
To solve this problem with respect to your code, simply declare the global A back in your b() function.
def b():
global A
if(len(A)>0):
A=[7,8,9]
else:
if(A[3]==4):
A.remove(2)
However, the better, ideal and recommended way to do this is to not use global and just pass the arguments to your function
A = [1, 2, 3, 4]
def main(list_of_things):
# do whatever operations you want to do here
b(list_of_things)
def b(list_of_things):
# do things with list_of_things
main(A)
You must declare a variable global in any function that assigns to it.
def b():
global A
if some_condition:
A.append(6)
else:
A.remove(2)
Without declaring A global within the scope of b(), Python assumes that A belongs in the b() namespace. You can read it, but cannot edit it (any changes made will not persist to the true A.
You're allowed to set A to something inside the function A = ... will work, but only within the scope of the function.
If you try to mutate A inside of the function without defining A in your function's namespace, then Python will tell you that you are trying to mutate a variable outside of your purview with UnboundLocalError
By declaring A global, the interpreter knows that you mean to edit the global variable.
I'm assuming that you meant for your code to look something like this (Otherwise, it runs fine)
A=[]
if __name__ == '__main__':
def main():
global A
A=[1,2,3,4,5]
b()
def b():
global A
if some_condition:
A=[7,8,9]
else:
A.remove(2)
print A
main()
print A
print A

importing other files in python and global variables

I cannot quite find a good description on how import works when importing your own files.
I was having trouble importing a file with a global variable and managed to get it to work when I put the global variable just before the files main function.
Can someone explain why it works this way?
A quick run down on how import actually works.
It did not work when I did this (pseudocode):
file1:
import file2
file2.main()
file2:
main():
glob_var = 0
def add():
global glob_var
glob_var += 1
add()
But worked if I put the variable first like this:
file1:
import file2
file2.main()
file2:
glob_var = 0
main():
def add():
global glob_var
glob_var += 1
add()
'main' is just a method. Variable inside a method is local by definition. Thats why 2nd way is working.
The reason it didn't work is because you are declaring the global variable inside of main. (you did miss the colon after definition of main which makes it confusing but looking at the indentation I suppose it's a definition). Global variables have to be defined outside the scope of any local function. This is a case of nested function definition.
You can do without global variables as well if that's what you are looking for. If however you want to use the variable defined in main inside a nested function then you can do the following:
In python 3 there is a way to get this thing done however using the nonlocal keyword
def main():
var = 10
def nested_fun():
nonlocal var
var = var + 1
As you see we do not need a global variable here.
Edit: In case of python 2 this does not work. However you can use a list in the main and modify that list inside nested function.
def main():
var = [10]
def nested_fun():
nonlocal var
var[0] = var[0] + 1
If I understand the question correctly, it's regarding the global variable and have nothing to do with importing.
If you want to define a global variable, it has to be defined in module level. The main function is not the global scope, that's why the first code does not work as expected. By moving the variable declaration outside of main, it would be defined in global scope, so the add method can access it using as a global variable.
I think we have to begin with what global statement means. From the docs:
It means that the listed identifiers are to be interpreted as globals.
The important point is it's only about interpretation, i.e. global does not create anything. This is the reason, why your first example does not work. You are trying to add +1 to something not existing. OTOH, global_var = 100 would work there and it would create a new global variable.

How to pass variables over functions in python 3

#Test
def test():
test1 = input("Type something: ")
test()
print(test1)
print(test1)
NameError: name 'test1' is not defined
'test1' is not defined
This is bothering me. I'm learning python and trying to write a small game for practice, and it seems that variables that are declared in a function don't carry over. Is there a way to get by this? Am I not supposed to use test() to close the function? Or should I figure out and use a class instead? Or perhaps is it just a quirk of python? Thanks for any help.
By default, all the names assigned inside a function definition are put in the local scope (the
namespace associated with the function call). If you need to assign a name that
lives at the top level of the module enclosing the function, you can do so by declaring
it in a global statement inside the function. If you need to assign a name
that lives in an enclosing def, as of Python 3.X you can do so by declaring it in a
nonlocal statement.
Read this: https://docs.python.org/3.4/tutorial/classes.html#python-scopes-and-namespaces
You need to return the value and store the returned value to print it.
def test():
test1 = input("Type something: ")
return test1
a = test()
print(a)
In general, functions should rely on arguments and return values instead of globals.
def test():
test1 = input("Type something: ")
These two lines define a function called test. When test is called (test()), the line inside will be run. The line inside assigns input to the variable test1. But test1 is scoped to the test function -- the name test1 only exists inside the function, so once the function ends, the name disappears.
Functions are called to produce output (or side-effects, but in this case, output). You do that by using the return keyword to end your function and return a variable. In this case, you could do return test1 inside your function (technically you could just to return input(...) directly too, and skip the creation of the variable entirely).
test()
This calls the function. You can do this at any time after the function is defined; you don't need to do it to "close" the function.
If you modify your function to return a value, then you'll need to do something with the return value on this line. Something like result = test(). That assigns the return value of test to the result variable.
print(test1)
This isn't working because test1 only exists inside the function namespace, and you are calling this line outside of the function namespace. If you've made the changes I suggested above, you can do print(result) instead.

Categories

Resources