Out-print of a function-call [duplicate] - python

This question already has answers here:
Modifying a list inside a function
(4 answers)
Closed 2 years ago.
I am currently new to python and I'm still learning the basics, but there is one thing I just can't wrap my head around. Why is the code in Q.1 giving the out-print 3, while Q.2 is giving the out-print [4]?
When asked, I was told that the f(x)-line at the bottom of Q.1 isn't given any variable or box to hold the new return-value given from the def. and that's the reason why the out-print of x remain 3.
This made sense to me, but then why would the out-print in Q.2 equal the return-value of g(x)? There isn't any variable or box to contain the return-value of x in this code either..
Q.1:
def f(x):
x += 1
return x
x=3
f(x)
print(x)
Q.2:
def g(x):
x[0] = x[0] + 1
return x
x = [3]
g(x)
print(x)

A Python function takes arguments by reference (something that points to the real object) whenever that argument is "complex", and takes the argument by value (a copy of the item) when it's a simple thing.
Q.1 is taking an int as an argument, then the function creates an internal copy of it and thus does not modify the value of x outside the function.
Q.2 is taking a list as an argument, which is considered complex, in which case the function takes a reference to the original and whatever happens to that reference will also happen to the original.
You can find an explanation of pass-by-reference and pass-by-value with images here

In Python, lists are mutable objects, and as a result they are passed-by-reference when used in a function call. This means that when g(x) adds 1 to the first element of x, after the function exits, the original list x will contain those changes.
Note that the specific term used is not "pass-by-reference", but rather "pass-by-name", which comes with a couple different semantics, which you can learn more about if you wish.

The function defined is Q1 is returning a value of for. x contains 3 and is passed into the function, by calling it with f(x). It gets incremented and returned to the function call. But, the function call was not stored in a variable, so it was not saved into memory. Nothing was done with the returned value. Calling the function is only editing the variable x within the local scope (within the function). When you're using print(x) it is referencing the global variable of x, which still contains 3.
In Q2, lists are mutable. Editing them within a function, the changes persist in the global scope. Because that list is mutated in the global scope, using print(x) uses the updated global variable.
I hope this makes sense. Look into scope of variables in the documentation for more.

Q1
def f(x):
x += 1
return x
x=3
f(x)
print(x)
The reason this is returning 3 and not 4 is because you haven't rebound your variable to reference this new value. Instead of f(x) you can do x = f(x).
Q2
def g(var):
var[0] = var[0] + 1
return var
x = [3]
g(x)
print(x)
To answer this without making it confusing I've changed the local variable used in the function to var so you can see what I'm trying to explain to you easier.
First you are creating a list with a integer value 3 in the first spot in the list (element 0) and you make x reference this list.
When you call g() function and pass the list, the function sets var to reference the same list (not a different one, the same one). You then tell the function to increase the integer value in the first element by 1. Since lists are mutable with certain methods, you have already changed the list for both the local variable var, and the global variable x. This means that you actually don't need to use any return of the function because the list has been mutated in place.
Have a look at this video https://youtu.be/_AEJHKGk9ns where Ned Batchelder explains more about this.

Related

problem having with openpyexcel while making a password generator [duplicate]

This question already has answers here:
How do I pass a variable by reference?
(39 answers)
Why can a function modify some arguments as perceived by the caller, but not others?
(13 answers)
Closed 9 years ago.
This may seem like a really stupid question but I am confused regarding the scope rules in Python. In the following example I send two variables (x,y) with values to a function which is supposed to change their values. When I print the results the variables had not changed.
def func1(x,y):
x=200
y=300
x=2
y=3
func1(x,y)
print x,y #prints 2,3
Now if this were C++ I would send them by reference (&) to that function and therefore be able to change their values. So what's the equivilant in Python? and more important, what actually happens when you send objects to function? does Python make new references to these objects?
Think of them as being part of the function. When the function ends, all its variables die too.
x=2
y=3
def func(x,y):
x=200
y=300
func(x,y) #inside this function, x=200 and y=300
#but by this line the function is over and those new values are discarded
print(x,y) #so this is looking at the outer scope again
If you want a function to modify a value in exactly the way you have written it, you could use a global but this is VERY bad practice.
def func(x,y):
global x #these tell the function to look at the outer scope
global y #and use those references to x and y, not the inner scope
x=200
y=300
func(x,y)
print(x,y) #prints 200 300
The problem with this is that it makes debugging a nightmare in the best case, and utterly incomprehensibly impossible in the worst case. Things like these are commonly known as "side effects" in functions -- setting a value you don't need set and doing so without explicitly returning it is kind of a Bad Thing. Generally the only functions you should write that modify items in-place are object methods (things like [].append() modify the list because it's silly to return a new list instead!)
The RIGHT way to do something like this would be to use a return value. Try something like
def func(x,y):
x = x+200 #this can be written x += 200
y = y+300 #as above: y += 300
return (x,y) #returns a tuple (x,y)
x = 2
y = 3
func(x,y) # returns (202, 303)
print(x,y) #prints 2 3
Why didn't that work? Well because you never told the program to DO anything with that tuple (202, 303), just to calculate it. Let's assign it now
#func as defined above
x=2 ; y=3
x,y = func(x,y) #this unpacks the tuple (202,303) into two values and x and y
print(x,y) #prints 202 303

Python modify single variable by reference

I have seen other questions related to this topic, but haven't really found an answer to the following simple problem:
VB Code:
Function f_x(ByRef x As Integer)
x = x + 1
End Function
Sub test()
Dim w As Integer
w = 2
Call f_x(w)
MsgBox w
End Sub
The output above is 3, whereby the variable "w" is modified through the pointer "x" inside the function "F_x()" (i.e. "by reference").
Can I write a similar function in Python, which modifies a single numerical variable through a pointer (i.e. "by reference")? I understand that a list or a Numpy array will be modified (automatically) by reference when passed to a function, but what about a single numerical variable?
EDIT: as per suggestion below, I am adding my attempt to code this in Python (which obviously doesn't work):
def test_function(y):
y = y + 1
x = 2
test_function(x)
print(x)
The output above is 2, not 3.
Edit 2: why on earth would anyone bother with choosing whether to pass a numerical variable by reference (through a pointer) or by value? What if the task is to write a computationally efficient code and one is dealing with large floating point numbers: here, a pointer ("by reference") will only need to store the memory address, whilst "by value" approach will have to "copy" the entire variable inside the function.
You could put your variable in a mutable object like a dict:
def test_function(y):
y['x'] = y['x'] + 1
d = {'x': 2}
test_function(d)
print(d['x'])
Primitive types are immutable.

Update the referred variable in dictionary is not working [duplicate]

How can I pass an integer by reference in Python?
I want to modify the value of a variable that I am passing to the function. I have read that everything in Python is pass by value, but there has to be an easy trick. For example, in Java you could pass the reference types of Integer, Long, etc.
How can I pass an integer into a function by reference?
What are the best practices?
It doesn't quite work that way in Python. Python passes references to objects. Inside your function you have an object -- You're free to mutate that object (if possible). However, integers are immutable. One workaround is to pass the integer in a container which can be mutated:
def change(x):
x[0] = 3
x = [1]
change(x)
print x
This is ugly/clumsy at best, but you're not going to do any better in Python. The reason is because in Python, assignment (=) takes whatever object is the result of the right hand side and binds it to whatever is on the left hand side *(or passes it to the appropriate function).
Understanding this, we can see why there is no way to change the value of an immutable object inside a function -- you can't change any of its attributes because it's immutable, and you can't just assign the "variable" a new value because then you're actually creating a new object (which is distinct from the old one) and giving it the name that the old object had in the local namespace.
Usually the workaround is to simply return the object that you want:
def multiply_by_2(x):
return 2*x
x = 1
x = multiply_by_2(x)
*In the first example case above, 3 actually gets passed to x.__setitem__.
Most cases where you would need to pass by reference are where you need to return more than one value back to the caller. A "best practice" is to use multiple return values, which is much easier to do in Python than in languages like Java.
Here's a simple example:
def RectToPolar(x, y):
r = (x ** 2 + y ** 2) ** 0.5
theta = math.atan2(y, x)
return r, theta # return 2 things at once
r, theta = RectToPolar(3, 4) # assign 2 things at once
Not exactly passing a value directly, but using it as if it was passed.
x = 7
def my_method():
nonlocal x
x += 1
my_method()
print(x) # 8
Caveats:
nonlocal was introduced in python 3
If the enclosing scope is the global one, use global instead of nonlocal.
Maybe it's not pythonic way, but you can do this
import ctypes
def incr(a):
a += 1
x = ctypes.c_int(1) # create c-var
incr(ctypes.ctypes.byref(x)) # passing by ref
Really, the best practice is to step back and ask whether you really need to do this. Why do you want to modify the value of a variable that you're passing in to the function?
If you need to do it for a quick hack, the quickest way is to pass a list holding the integer, and stick a [0] around every use of it, as mgilson's answer demonstrates.
If you need to do it for something more significant, write a class that has an int as an attribute, so you can just set it. Of course this forces you to come up with a good name for the class, and for the attribute—if you can't think of anything, go back and read the sentence again a few times, and then use the list.
More generally, if you're trying to port some Java idiom directly to Python, you're doing it wrong. Even when there is something directly corresponding (as with static/#staticmethod), you still don't want to use it in most Python programs just because you'd use it in Java.
Maybe slightly more self-documenting than the list-of-length-1 trick is the old empty type trick:
def inc_i(v):
v.i += 1
x = type('', (), {})()
x.i = 7
inc_i(x)
print(x.i)
A numpy single-element array is mutable and yet for most purposes, it can be evaluated as if it was a numerical python variable. Therefore, it's a more convenient by-reference number container than a single-element list.
import numpy as np
def triple_var_by_ref(x):
x[0]=x[0]*3
a=np.array([2])
triple_var_by_ref(a)
print(a+1)
output:
7
The correct answer, is to use a class and put the value inside the class, this lets you pass by reference exactly as you desire.
class Thing:
def __init__(self,a):
self.a = a
def dosomething(ref)
ref.a += 1
t = Thing(3)
dosomething(t)
print("T is now",t.a)
In Python, every value is a reference (a pointer to an object), just like non-primitives in Java. Also, like Java, Python only has pass by value. So, semantically, they are pretty much the same.
Since you mention Java in your question, I would like to see how you achieve what you want in Java. If you can show it in Java, I can show you how to do it exactly equivalently in Python.
class PassByReference:
def Change(self, var):
self.a = var
print(self.a)
s=PassByReference()
s.Change(5)
class Obj:
def __init__(self,a):
self.value = a
def sum(self, a):
self.value += a
a = Obj(1)
b = a
a.sum(1)
print(a.value, b.value)// 2 2
In Python, everything is passed by value, but if you want to modify some state, you can change the value of an integer inside a list or object that's passed to a method.
integers are immutable in python and once they are created we cannot change their value by using assignment operator to a variable we are making it to point to some other address not the previous address.
In python a function can return multiple values we can make use of it:
def swap(a,b):
return b,a
a,b=22,55
a,b=swap(a,b)
print(a,b)
To change the reference a variable is pointing to we can wrap immutable data types(int, long, float, complex, str, bytes, truple, frozenset) inside of mutable data types (bytearray, list, set, dict).
#var is an instance of dictionary type
def change(var,key,new_value):
var[key]=new_value
var =dict()
var['a']=33
change(var,'a',2625)
print(var['a'])

Need help using a mutator function in python

So I need to use a mutator method to change elements of a list in Python. I would normally do this using a function that can return a value, but for this assignment we are not allowed to return any values in the function.
Here's an example of the general idea that i'm talking about
def changeX(x):
x = 5
x = 3
changeX(x)
print(x)
The output for this would obviously be 3 since I did not change x.
So my question is, how would I approach this assignment? I need to use the mutator method to modify my variable but I'm not sure how.
You get the results you do because you pass a primitive value into your "mutator" function.
If you pass in a list, you'll see that you can change the value in place:
def changeX(x):
x[0]=3
x = [1,2,3]
changeX(x)
print (x)
It will print [3,2,3]. Check it out:
https://repl.it/EIZW/0

How to change the scope of a variable in a function? Python [duplicate]

This question already has answers here:
How do I pass a variable by reference?
(39 answers)
Why can a function modify some arguments as perceived by the caller, but not others?
(13 answers)
Closed 9 years ago.
This may seem like a really stupid question but I am confused regarding the scope rules in Python. In the following example I send two variables (x,y) with values to a function which is supposed to change their values. When I print the results the variables had not changed.
def func1(x,y):
x=200
y=300
x=2
y=3
func1(x,y)
print x,y #prints 2,3
Now if this were C++ I would send them by reference (&) to that function and therefore be able to change their values. So what's the equivilant in Python? and more important, what actually happens when you send objects to function? does Python make new references to these objects?
Think of them as being part of the function. When the function ends, all its variables die too.
x=2
y=3
def func(x,y):
x=200
y=300
func(x,y) #inside this function, x=200 and y=300
#but by this line the function is over and those new values are discarded
print(x,y) #so this is looking at the outer scope again
If you want a function to modify a value in exactly the way you have written it, you could use a global but this is VERY bad practice.
def func(x,y):
global x #these tell the function to look at the outer scope
global y #and use those references to x and y, not the inner scope
x=200
y=300
func(x,y)
print(x,y) #prints 200 300
The problem with this is that it makes debugging a nightmare in the best case, and utterly incomprehensibly impossible in the worst case. Things like these are commonly known as "side effects" in functions -- setting a value you don't need set and doing so without explicitly returning it is kind of a Bad Thing. Generally the only functions you should write that modify items in-place are object methods (things like [].append() modify the list because it's silly to return a new list instead!)
The RIGHT way to do something like this would be to use a return value. Try something like
def func(x,y):
x = x+200 #this can be written x += 200
y = y+300 #as above: y += 300
return (x,y) #returns a tuple (x,y)
x = 2
y = 3
func(x,y) # returns (202, 303)
print(x,y) #prints 2 3
Why didn't that work? Well because you never told the program to DO anything with that tuple (202, 303), just to calculate it. Let's assign it now
#func as defined above
x=2 ; y=3
x,y = func(x,y) #this unpacks the tuple (202,303) into two values and x and y
print(x,y) #prints 202 303

Categories

Resources