I have a question about the python variables. As you see below, I have defined with L a list
and with I an integer variable after that, i have added new number to list inside function as locally.I can use the changed list outside the function as globally; on the other hand same situation is not for the integer variable.
Can someone help me please ? What is the difference?
PS:I know that ,I use integer variable inside the function as local variable because of that, it doesn't change on global. but why not a list variable?
L=[]
I=5
def change_var(I,L):
I=10
L.append(12)
print('Inside function I',I)
print('Inside function L',L)
return I,L
change_var(I,L)
print('Outside function I',I)
print('Outside function L',L)
Result
>>>Inside function I 10
>>>Inside function L [12]
>>>Outside function I 5
>>>Outside function L [12]```
If a variable gets affected a value anywhere inside the body of a function (as in variable = ...), then it is considered to be local, unless you explicitely declare it global in this function.
You treat I and L very differently:
You assign a value to I in I = 10, so it is considered local, and so a different variable from the other, global I. The changes you make to it can't be reflected on the other, global I. If you wanted to act on the global I, you should have declared global I at the start of your function.
You don't assign anything to L, you just mutate the unique, already existing global list.
You would have to change the name of the variables you are using inside the function, since you are creating new variables for I and L when inside the function, if you don't. In my example, I have changed them to lowercase(i and l). Also, when you put a number/variable inside the function parenthesis, it sets the variables inside the function to that number/variable, rather than putting that number inside the variable. So, when you put change_var(I,L), it effectively running the function, but putting the lines i=I and l=L at the start, rather than replacing all is with Is. To fix this, you will have to make I global when inside the function, so it affects code outside of the function, and then make I equal i.
The full code would be
L=[]
I=5
def change_var(i,l):
i=10
l.append(12)
print('Inside function I',i)
print('Inside function L',l)
global I
I=i
return i,l
change_var(I,L)
print('Outside function I',I)
print('Outside function L',L)
The code should work, but I'm sorry if my explanation didn't make any sense - I'm still quite new to answering on Stack Overflow.
Related
New to coding and I'm challenging myself to write a program where the user inputs values into a list and sorts them by another input value. When I run the program, I get a traceback error saying that 'nl' is not defined. I think I may have something out of order or I'm not using something correctly. Some advice would be helpful!
def listsort(l1):
for num in l1:
n1 = []
if num <= inp:
n1.append(num)
for x in n1:
print(x, end=' ')
def newlist():
nl = []
while True:
l_inp = input('Add to list: ')
if l_inp == 'done':
return nl
else:
float(l_inp)
nl.append(l_inp)
continue
newlist()
inp = float(input('Enter a number: '))
print('These numbers are less than or equal to', inp)
listsort(nl)
n1 has a function only scope, means can be accessed only inside function.
Declare the variable as global n1 inside both functions.
nl is declared in newlist and you only have scope to that variable in that function, if you want to access it from outside then you should declare nl outside the function and send it as a parameter to "newlist"
error in python shell showing scope of nl
There are two scopes in Python namely local and global. A local scope variable is declared within a function an that cannot be accessed outside the function in which it is defined. You have defined 'nl' inside the function. So, you can't access that outside that function. Hence, the reason for that error
The answer to your question revolves around an idea called scope, and understanding scopes will make it much easier to figure out problems like this in the future. Everyone learns differently, so don't feel you have to know all this right now, but if you want to know the details, read on!
Scope
Each variable in your program exists in something called a scope. Here is a diagram of your program. It has three scopes - a global scope and a scope for each function, listsort and newlist. Every function has its own scope, and every Python file has its own global scope.
Which scope a variable ends up in depends on where it is introduced. Some ways for variables to be introduced are assignment (for example n1, nl, l_inp and inp are all assigned with the = symbol), as a for loop variable (for example num and x are loop variables) and as a function parameter (l1 is a function parameter). A variable lives in the tightest scope around where it is introduced.
You can see that scopes are nested. The function scopes are inside the global scope. This is important. You can see that the inp variable is in global scope, but it can still be used in the listsort scope because the listsort scope is inside the global scope. Code inside a function scope can "see out" to variables in the global scope. But code in the global scope can't "see in" to variables in function scope.
Okay, so how do I get the variables out of a function?
The variables in a function's scope go away when the function returns. But you can return the value of a variable. Your function newlist returns the value of nl. But where does that value go? Well, nowhere, because your program doesn't assign it to a variable. You can do that by writing:
nl = newlist()
That will save the value into a new variable called nl in the global scope. But this is a different variable from the nl in newlist. You can of course use any variable name you like, just because you stored this value in a variable called nl inside newlist doesn't mean you have to put it in a variable with the same name at the global scope. You could write:
gl = newlist()
And then later on use:
listsort(gl)
And that would work just as well.
I've got myself a bit confused regarding variables in Python, just looking for a bit of clarification.
In the following code, I will pass a global variable into my own Python function which simply takes the value and multiplies it by 2. Very simple. It does not return the variable after. The output from the print function at the end prints 10500 rather than 21000, indicating that the local variable created within the function did not actually edit the global variable that was passed to, but rather used the value as its argument.
balance = 10500
def test(balance):
balance = balance * 2
test(balance)
print(balance)
However, in my second piece of code here, when I pass a list/array into a separate function for bubble sorting, it is the actual array that is edited, rather than the function just using the values.
def bubble_sort(scores):
swapped = True
while swapped:
swapped = False
for i in range(0, len(scores)-1):
if scores[i] > scores[i+1]:
temp = scores[i]
scores[i] = scores[i+1]
scores[i+1] = temp
swapped = True
scores = [60, 50, 60, 58, 54, 54]
bubble_sort(scores)
print(scores)
Now when I print my scores list, it has been sorted. I am confused as to why the top function did not change the global variable that was passed to it, while the second function did? I understand using the global keyword within functions means I am still able to write code that will edit a global variable within my own functions, but maybe I am missing some basic understanding.
I think your confusion is about mutability.
Ints are immutable. When you assign balance initially, because it is an int, the value of balance won't change unless you reassign it. You know this, because you reassign it in your definition. However, the confusion in your situation is because there are actually two "balance" variables. The global one, and the one that exists inside your function each time you call. The assignment that happens within your function does not actually affect the assignment of the global variable. It doubly isn't really doing anything because there's no return value.
To actually change things, you would want
def test(balance):
balance = balance * 2
return balance
balance = test(balance)
The list situation is different because lists are actually mutable. This makes it so that when you're changing values in scores, you're really changing values in scores. And so when you call your function on it, it changes things without the need for reassignment.
This is generally a situation of remembering the inherent properties of the data types in python. Certain things are mutable and certain things are not. You can probably google up a quick chart, and the more you work in python, remembering the differences becomes second nature.
In both functions, the global variable is shadowed by the local variable.
In the test function, the global and local variables start by pointing to the same value, but the local variable is reassigned to another value.
In the bubble_sort function, the global and local variables also start by pointing to the same value. This time, instead of reassigning the local variable to a new value, you mutate the object it is pointing to. If in the bubble_sort function you reassigned the local variable, you would end up with a similar outcome to your test function.
Very simple problem (At least I think so): So I have a global variable, in this case test, and I want to assign an other value to it in a function. This is my code:
test = "Hello"
def launch():
test = "F"
launch()
print(test)
I wanted test to equal "F", but it doesn't. Instead, the output of this is that test still equals "Hello". I assume it creates a variable inside the function and then assigns a value to it.
But why does this work then:
test = {
"?": "Hallo"
}
def launch():
test["?"] = "F"
launch()
print(test)
The output of this is how I wanted it to be: test["?"] is equal to "F".
How is this working and why isn't the first code example?
Is there any way to use the first code how I wanted it to work?
You need to add a global test line to the top of the function to tell it to reference an existing variable instead of creating a new one. It's ambiguous otherwise.
Why does the second one work though? Because it isn't ambiguous. From context, it knows that you must be referencing an existing variable instead of attempting to create a new one.
test["?"] = "F"
is essentially
test.__setItem__("?", "F")
and that only makes sense if test already exists. It knows that you aren't trying to create a new local variable.
The language only requires a global test statement in cases where it can't tell whether or not you want to use an existing variable or create a new one.
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, however, it’s assumed to be a local unless explicitly declared as global.
So, change it as follows:
test = "Hello"
def launch():
global test
test = "F"
In your second example you don't declare the dictionary (like test = {}). Hence, python looks for a global variable test. You can access global variables by:
def launch():
global test
test = "F"
In the first case, you're trying to access a global variable but you have also redeclared it as a local variable.
test = "Hello" #global variable by default.
def launch():
test = "F" # local variable by default. It's restricted to the function launch().
launch()
print(test) # Accessing global variable because print can't see test of launch.
test = "Hello" #global variable by default.
def launch():
global test
test = "F" # Accessing global value of test.
launch()
print(test) # Accessing global variable test.
In second case,you're assigning to a global variable, not redeclaring it as a local variable. There in lies the difference.
test = {'?':"Hello"} #global variable by default.
def launch():
test['?'] = "F" # global variable access by default. It's NOT restricted to the function launch().
launch()
print(test) # Accessing global variable.
In your first test, in your launch function, the test variable is recreated, with no link to the global function. It's a particularity of python.
If you wanted to change the global function you should have done like this :
def launch():
global test
test = 'F'
With your second test, test is a dictionary.
And yes, when you change a dictionary in a function without declaring it as a global variable, it changes the dictionary outside of the function as well.
If you want to know the real reason, it's way more complicated if you don't know C language... Python was programmed in C (for CPython at least), and in C, managing variables is very different than in Python.
In C, when you want to modify a variable in a function, you have to give to the function the memory address of the variable as a parameter (that variable is called a Pointer).
If you don't give the pointer of your global variable to the function where you want to modify it, it won't work.
When your launch function was called in your first example, test wasn't modified, because as you haven't declared test as global, python hasn't given the pointer of test to the launch function (only its value).
When you use dictionaries, Python will also give the value of the dictionary, but it will be a pointer to its elements. So you will be able to modify them.
That's why you can modify the elements in the dictionary, but you can't modify the dictionary. Example :
a = {"a":123, 'b':456}
def modif():
a = {"aa":123}
modif()
print(a)
results in:
{'a': 123, 'b': 456}
So the dictionary hasn't been modified. It works the same way with the lists (and I suppose with every iterable that support item assignment)
I tried to simplify, it's more complicated in reality, but it may teach you some thing I hope.
I am new to Python so I am unsure about the difference in variable assignment before or after the function definition.
Specifically, the first example was adopted from Lutz's book.
def tester(start):
print("inside tester")
def nested(label):
print("inside nested")
print(label,nested.state)
nested.state += 1
print("done with nested")
nested.state = start
print("done with tester")
return nested
F = tester(0)
F('spam')
F.state
F.state
The objective of the code is to store the state information without using nonlocal.
I am unsure what nested.state means here. I am unsure because nested.state is used inside nested() function (i.e. nested.state +=1) and outside nested() function (i.e. nested.state = start).
I modified the code above to see whether Python accepts assigning variable after function declaration for nested() and to see whether there is any concept I am missing relating to function.variable call (i.e. nested.state call).
def tester(start):
def nested(label):
print(label, state)
state += 1 #replaced 'nested.state' with 'state' here
state = start #replaced 'nested.state' with 'state' here
return nested
F=tester(0)
F('spam')
F('ham')
Unfortunately, above code generates error local variable 'state' referenced before assignment. This tells me that I am missing some concept about function.variable (i.e. nested.state).
Can someone please help me understand three things:
I. why it is that the code with nested.state doesn't generate any error but state does?
II. what does nested.state mean? If nested.state is a mechanism to access function's variables, why is it that the call inside nested() function also uses nested.state and not state?
III. If nested.state is a mechanism to access variable inside function, then why is it that PyCharm fails to show state under dropdown when I type nested.?
I'd appreciate any help. I research SO, and couldn't find any explanation on such problems.
The reason the first code example worked is because it was assigning and referencing an attribute of the nested function object. The key concept to understand here, is that Python allows you to assign new, arbitrary attributes to objects - including functions:
>>> def func(a, b):
return a + b
>>> func(1, 2)
3
>>> func.attr = 5
>>> func.attr
5
The first code example takes advantage of this fact by using the nested function object to store the necessary state. This is the same concept as using any other object to store the state. It's particularly convenient, however, to use a function since it's readily available.
In the second example, a normal variable is used. Because of this, normal scoping rules apply which means simply that the state variable defined in tester is not the state variable being referenced in nested. Thus, an error is raised.
Actually, I think you're asking a question about scope in Python, ignoring your code, check this:
def scope_level_1():
variable = 'Scope_level_1'
def scope_level_2():
variable = 'Scope_level_2'
def core():
nonlocal variable
variable += '_TOUCHED_AND_MODIFIED_BY_CORE'
print(variable)
return core()
return scope_level_2()
scope_level_1()
# 'Scope_level_2_TOUCHED_AND_MODIFIED_BY_CORE'
Don't worry about the keyword nonlocal, treat it just as a declaring to make code more readable.
First, remember a += b is the same as a = a + b. So a must exist before getting to the +=.
Simply put, in the first example the function nested has an attribute called state (accessed by nested.state). It is an attribute, which means that once you tell nested that it has an attribute called state (you are doing this in line 9 when nested.state = start) it keep that attribute. So, in the first example nested.state exists when you get to the +=.
In the second example, you are declaring a variable called state in tester, and another variable called state in nested. The one in nested could be called potato for all that matters, because it is not the same variable. Therefore when you arrive to the +=, the variable state does not exist!
For example, why does this work?
def func1(func1var):
def innerfunc(innerfuncvar):
if func1var == 1:
print innerfuncvar
else:
print 5
func2(innerfunc)
def func2(function):
function(9)
When innerfunc is called in func2, how does it know the values of func1var?
You've created a closure. Basically, think of it like this, from the point of view of the inner function:
func1var = whatever
def func2(function):
function(9)
def innerfunc(innerfuncvar):
if func1var = 1:
print innerfuncvar
else:
print 5
func2(innerfunc)
It doesn't care whether func1var is in an outer or global scope -- it just looks for it in each scope outward, starting with it's own local scope. It's just like when you reference a module global variable from inside a class or function in that module.
Python actually goes to some lengths to do this for you. When you define a function inside a function, you may use variables from the outer function in the inner function. This is true for any depth of nesting (that is, you can have a function inside a function inside a function inside a function... to any depth... and the innermost function can use variables from any of the enclosing functions). If there are conflicting names, the innermost variable with the name requested is used.
What's more, Python actually captures any variables you use from the outer function and stores them in the inner function, which is called a closure. So you can not only pass a function to another function, as you are doing, but you can return a function from a function, and variables you use from the outer function that were in effect when the function was defined will still be accessible from the returned function, even though the outer function isn't running any more. This is a fairly advanced feature, but it lets you do something like this:
def make_adder(increment):
def adder(number):
return number + increment
adder.__name__ = "adder(%s)" % increment
return adder
This function is a function that creates a function that adds the specified value to it. For example:
add1 = make_adder(1)
add5 = make_adder(5)
print add1(10) # 11
print add5(10) # 15
In this case, the value you pass to make_adder is captured and stored in the function that gets returned. This allows you to create a bunch of functions that add any number to their arguments. Which is a trivial example that isn't actually very useful in real life, but serves to illustrate the feature.
Each time you call func1(func1var), Python actually builds a new function innerfunc(). Since func1var is perfectly defined when innerfunc() is created, the code of the new innerfunc() function contains the correct value of func1var.