why these two programs result in diffrent results? - python

I have changed the value of 'a' before calling the function get_size() in both the programs
1st:
a=''
def get_size(b):
size=len(b)
return size
def main():
a='qwerr'
print 'the size of a is:',get_size(a)
if __name__=='__main__':
main()
console:the size of a is: 5
2nd:
a=''
def get_size():
size=len(a)
return size
def main():
a='qwerr'
print 'the size of a is:',get_size()
if __name__=='__main__':
main()
console:the size of a is: 0

In the first program, you are setting a at global scope, then resetting it to another string in def main scope.

It's a scope problem. The first program creates a in the local scope of main(), then passes that to get_size(), while the second program references the global a from within get_size(). If you want the second one to work as you expect, you need to make a global within main() scope.
main()
global a
a = 'qwerr'
print 'the size of a is:',get_size()
As pointed out in the comments, a main()-scoped a is created in both versions, but since get_size() in version 1 references the global a, setting the local a in main() has no impact on what get_size() operates on.
Really though, you should try not to use globals, in part to avoid exactly the ambiguity you are experiencing here.

In the second program, get_size method will check for 'a' value in its local scope but as it is not there in it's local scope and then it will verify in it's global scope

Related

Printing the value of a global variable and then changing the value in python

The global keyword is used in a function to refer to a global variable within that function and modify it. However even if the global keyword is not used and if we just try to print the variable, python assumes it is the global variable that is being referred and simply prints that like so.
a = 2
def foo():
print(a)
foo()
the above code outputs 2. But the following code throws an error.
a = 2
def foo():
print(a)
a = 3
foo()
I get an UnboundLocalError saying local variable 'a' was referenced before assignment. Now since python is an interpreted language and execution happens one line at a time, shouldn't it first print the global value of a which is 2 (like in the first case) and then create a local variable with the same name ans assign it to 3. In the second case how does the interpreter know right at the print statement that I am referring to another variable 'a' in the next line? Why doesn't it behave in the same way as above?
PS: I do understand that using the global keyword can help me change the value of a from 2 to 3.
Python byte code is interpreted; Python source is first compiled to byte code.
Names are either local or global within a single scope, and that determination is made at compile time; you can't switch half way through a fuction. If there is any assignment to a in the function, it is local everywhere in the function unless you use global a.
a = 2
def foo():
global a
print(a)
a = 3
Without the global statement, print(a) refers to the local name a, even though it occurs before the actual assignment.

Global Variable declaration

I am kind of a beginner with Python and have dealt with the concept of a global variable. When I thought I understood the concept, I saw a short code which proved me wrong:
message="global"
def enclosure():
message="enclosure"
def local():
global message
message="local"
local()
print(message)
print(message)
enclosure()
print(message)
The output of that is:
global
enclosure
local
I dont understand, why the second output is enclosure, because when you call the enclosure function, within this function the funciton local is called, in which the global variable message is set to "local", which then as of my understanding should be printed out at the end when calling the enclosure function (so i would expect global, local, local..).
So where is my thinking error?
When you assigned message="enclosure" in enclosure, you made message a local variable for that scope. It doesn't matter that the nested function changed the global message; enclosure didn't declare message global, so it maintains its own locally scoped variable independent of the global one (that local shares).
In general, you should try to avoid global variables if possible. There is usually a cleaner way to achieve what you want.
In your example, you have two string variables, both called message. One has the scope of the whole module, it is initially bound to the value "global" and then inside the local method it is rebound to the value "local".
The second variable is also called message and has the scope of the enclosure method. It is initially set to the value "enclosure" and is not modified.
Your first print call is at module scope, so prints the value of the module-scoped message, which is "global". Your second call is inside the enclosure so prints the value of the other variable which is "enclosure". And finally you print the value of the module-scoped message which has now been changed to the value "local".
In reality you have two variables, for clarity I added a suffix 1 and 2:
message1="global"
def enclosure():
message2="enclosure" # this is a new declaration, it is a new message.
def local():
global message1
message1="local"
local()
print(message2) # in this scope, only message2 is visible
print(message1)
enclosure()
print(message1)
So you see, you created two message, and you use at the second print the second variable named message
i hope this will help you:
def generate_closure(income_tax_rate = 0.33):
def this_is_closure_which_will_give_final_money(raw_income):
final_money = raw_income - (raw_income * income_tax_rate)
return final_money
return this_is_closure_which_will_give_final_money
standard_tax_calculator = generate_closure()
classic_salary = standard_tax_calculator(2000)
final_classic_money = print(classic_salary)
classic_salary_2 = standard_tax_calculator(2499)
final_classic_money_2 = print(classic_salary_2)
rich_people_tax_calculator = generate_closure(income_tax_rate = 0.50)
rich_salary = rich_people_tax_calculator(15000)
final_rich_money = print(rich_salary)
rich_salary_2 = rich_people_tax_calculator(19499)
final_rich_money_2 = print(rich_salary_2)
print("\n------------------------------")
def generate_closure(trapped):
def closure(x):
return trapped ** x
return closure
f = generate_closure(10)
print(f)
f(3)
print(f(3)) # f remember the value 10
del generate_closure
print(f(2)) # it still does work !
print(f.__closure__[0].cell_contents) # here is the hidden value
Here is a function which return another function.
A closure is not a variable.
A closure aims at avoid using global variable.
Take care not to use key-word the wrong way.
You can think to use closure when some argument it will use are known to be constant.

About assigning value to variables in Python [duplicate]

This question already has answers here:
How do I pass a variable by reference?
(39 answers)
Closed 7 years ago.
Here I wrote two simple programs and expected the results to be same:
program 1(result=123):
price=[]
def checkCondition(a,b):
if a<b:
price.append(123)
if __name__ == '__main__':
checkCondition(1,2)
print price[0]
program 2(result=''):
price=''
def checkCondition(a,b):
if a<b:
price=123
if __name__ == '__main__':
checkCondition(1,2)
print price
Why it couldn't assign 123 to price in program 2?
You're assigning a local variable. Tell Python to use the global variable instead:
price=''
def checkCondition(a,b):
global price # now reassigning price
if a<b:
price=123
if __name__ == '__main__':
checkCondition(1,2)
print price
From the Python doc Naming and binding:
If a name binding operation occurs anywhere within a code block, all uses of the name within the block are treated as references to the current block. [...]
If the global statement occurs within a block, all uses of the name specified in the statement refer to the binding of that name in the top-level namespace.
There are two types of python variables: globals and locals. Globals are reachable from all positions in your code. But locals are only reachable from the def() - definition they were created from. By default variables you create in a function are local and so there is a global price (='') amd a local price in your function(=123). To make it global and replace the existing global variable with the new one type on the beginning of your function definition:
global price
This makes the price variable in your functuon global.
The first one worked because your were not making a local variable. You did something on an existing variable (price). If the existing variable is global or not is not important then.
You need to tell the interpreter that you are referring to global name, as names inside functions are local to their scope by default:
price=''
def checkCondition(a,b):
global price
if a<b:
price=123
if __name__ == '__main__':
checkCondition(1,2)
print price
Note that inside a function, you can use a global variable, but can't change it without declaring it with global (see here).
The quote in the doc that matters:
It would be impossible to assign to a global variable without global, although free variables may refer to globals without being declared global.
The first program used the variable by calling a method, which is okay and it price resolves to the global variable. For the second you intended to change a global variable's value, which isn't doable unless the variable is declared with global. Since you can't change the global variable's value, it will create a new local variable and assign the value to it.
To fix it, you need to use global to declare it first:
price=[]
def checkCondition(a,b):
global price
if a<b:
price.append(123) # also works without the global
price = 123
if __name__ == '__main__':
checkCondition(1,2)
print price

Saving changes to newPic when copying an image in jython

There are similar questions on Stack Overflow, but I cannot find what I am doing wrong in my code.
def copyPic():
file=pickAFile()
oldPic=makePicture(file)
newPic=makeEmptyPicture(getWidth(oldPic),getHeight(oldPic))
for y in range(0,getHeight(oldPic)):
for x in range(0,getWidth(oldPic)):
oldPixel=getPixel(oldPic,x,y)
colour=getColor(oldPixel)
newPixel=getPixel(newPic,x,y)
setColor(newPixel,colour)
explore(newPic)
When I use explore(newPic) or show(newPic) outside of the function, gives a blank white canvas.
Is this because the newPic is not saved? How do I 'save' the changes to newPic?
It is a matter of scope of the variable :
When you define a function (here copyPic()) all the variables created inside this function are "visible" by the function only. The global program does not know anything about its existence.
The Python interpreter reads the code in the order it is written (sequentially).
As newPic is defined in the function in the first place, it belong to it and is destroyed once the function terminates.
That is why you can't refer to newPic afterward.
To fix this you have to return the variable (keyword return) such that you can get it from the main program when calling the copyPic() function.
You have to do as follows :
def copyPic():
file=pickAFile()
oldPic=makePicture(file)
newPic=makeEmptyPicture(getWidth(oldPic),getHeight(oldPic))
for y in range(0,getHeight(oldPic)):
for x in range(0,getWidth(oldPic)):
oldPixel=getPixel(oldPic,x,y)
colour=getColor(oldPixel)
newPixel=getPixel(newPic,y,x)
setColor(newPixel,colour)
return newPic # HERE IS THE IMPORTANT THING
newPic = copyPic() # Here we assign the returned value to a new variable
# which belong to the "global scope".
explore(newPic)
Note : Here, I used 2 variables called identically newPic. Those are considered as two different variables by the Jython Interpreter :
The first one belongs to the function (function scope)
The second one belongs to the main program (also called global scope)
Thus the code above is exactly equivalent to this one :
def copyPic():
file=pickAFile()
...
return newPic
newPic_2 = copyPic() # Here we store / assign the "newPic" returned by the
# copy function into another variable "newPic_2" (which
# is a "global variable").
explore(newPic_2)
EDIT :
An alternative to all of this would have been to use the global keyword to tell the interpreter that newPic was to be found from the global scope :
newPic = None # First declare "newPic" globally.
def copyPic():
global newPic # Tell the function to refer to the global variable.
...
#return newPic # No need to return anything, the function is
# modifying the right variable.
copyPic()
explore(newPic)
Note that generally speaking, one try to avoid using global variables. There is always better designs, specially with Python which is clearly object oriented...
I hope I made myself clear. If not, do not hesitate to ask further explanations.

Unbound Local error in Python I can't shake!

http://pastie.org/1966237
I keep getting an unbound local error. I don't understand why it occurs, if the program is running right, it should go straight into the second assignment of the print_et_list function within the main function, looping itself without actually looping. The program only quits using sys.exit() in the hey_user function.
I included the whole program for context, it isn't too long. Let me know if you want to have a look at the text files I use in the program, however I'm sure it's unlikely that it is the source of the problem.
UnboundLocalError happens when you read the value of a local variable before you set it. Why is score a local variable rather than a global variable? Because you set it in the function. Consider these two functions:
def foo():
print a
vs
def bar():
a = 1
print a
In foo(), a is global, because it is not set inside the function. In bar(), a is local. Now consider this code:
def baz():
print a
a = 1
Here, a is set within the function, so it's local. But it hasn't been set at the time of the print statement, so you get the UnboundLocalError.
You forgot to pass score into hey_user().
Looks like it's probably the score variable. It's a local in main(), but you try to reference it in hey_user().
If you want to make score a global variable, be sure to declare it with the global statement:
def main ():
global score
score = 0
question, solution = print_et_list()
scoresofar = hey_user (solution)
print "\nYour score is now", scoresofar
question, solution = print_et_list()

Categories