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

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'])

Related

Variable assignment inside for in loop

Hope you're all well with the caotic world we're living...
This might be a very beginner level question, but I'd like to understand why It is like that.
Let's say I have a list of complex:
myList = [(1.231 +2.254j), (2.875 +23.543j), ...]
I've been trying to round the values with this function:
def round_complex(x, digits):
return complex(round(x.real, digits), round(x.imag, digits))
And for doing so, I've tried this:
for item in myList:
item = round_complex(item, 2)
Expecting that myList values get changed, for example:
myList = [(1.23 +2.25j), (2.88 +23.54j), ...]
But, It does not work.
I've also tried with a more simple example, like a list of floats and the base round function from python. It also does not work.
Is there a way for me to change a value of an iterable object with this kind of for loop (for-in)?
Or do I really have to do this:
for i in range(len(myList)):
myList[i] = round_complex(myList[i], 2)
The simple answer is: NO.
Python uses a mechanism, which is known as "Call-by-Object", sometimes also called "Call by Object Reference" or "Call by Sharing" when pass function parameters.
If you pass immutable arguments like integers, strings or tuples to a function, the passing acts like call-by-value. The object reference is passed to the function parameters. They can't be changed within the function, because they can't be changed at all, i.e. they are immutable. It's different, if we pass mutable arguments. They are also passed by object reference, but they can be changed in place within the function.
So, after your iterate the list, the value (1.231 +2.254j) would be a immutable argument which your change won't affect the outside variable. But if you pass the value like [1.231 +2.254j] to function, then it will make effect like next:
test.py:
myList2 = [[(1.231 +2.254j)], [(2.875 +23.543j)]]
print(myList2)
def round_complex(x, digits):
return complex(round(x.real, digits), round(x.imag, digits))
for item2 in myList2:
item2[0] = round_complex(item2[0], 2)
print(myList2)
Execution:
$ python3 test.py
[[(1.231+2.254j)], [(2.875+23.543j)]]
[[(1.23+2.25j)], [(2.88+23.54j)]]
In a word, for you scenario, if you insist organize your input data as that & iterate with that way, you can't change the outside value directly inside the function.
You may refers to this to learn more.
The thing I understand by reading for question that you want to Assign the values of i in myList. For doing so you can use append i.e
for i in mylist:
mylist.append(round_complex(i, 2))

Swapping variables in python

I know that in Python you can swap the values of variables by doing
x,y=y,x
But I want a function that makes this swap only giving to it the variables, not having to return the values to achieve this swap. Let me be more clear with an example swapping x,y:
x,y=1,0
print(x,y) # This prints 1,0
def swapper(a,b):
#Something that swaps the variables and doesn't return anything.
swapper(x,y)
print(x,y) # This prints 0,1
Is this possible? If not, why not?
EDIT: Yes, I want to know if it's possible exactly what I wrote, not another implementation, but the function should be able to swap any two variables. You can think about this as an empty file, it won't be used for a bigger program. It's merely for learning purpose.
I think this is best explained by comparison with C/C++. Take this function:
void swap(int &x, int &y) {
int temp = *x;
*x = *y;
*y = temp;
}
This code does what you want it to do, but it's impossible in Python. Here's why:
The critical part of the C function is the function signature *x, *y which makes the arguments a pointer. When you do *x = *y, you are overwriting the memory that x points to. In python, you can't pass a pointer, only a reference. The difference is that overwriting a reference does nothing to the original object. For example,
x = "foo"
y = x
x = "bar"
print(x, y) # bar, foo not bar, bar
Any approach to solving this problem must deal with this issue, such as #adamgy's answer. His approach uses a double reference. You pass something that can i) hold references and is ii) mutable. He uses a list, but you could use a dict or any mutable object.
PS: There might be a way to do this using the CPython API, which is a little extreme.
All Python objects in the standard implementation have an underlying C object. You can implement a python function in C.
static PyObject * swap(PyObject *a, PyObject *b)
{
// logic
}
It might be possible to design a function that takes a pointer to a pointer.
static PyObject * swap(PyObject *a, PyObject *b)
{
swap_internal(&a, &b);
// more logic
}
static PyObject * swap_internal(PyObject **a, PyObject **b)
{
// logic
}
This would have the necessary double reference semantics, but I haven't checked if it actually works.
Mandatory Disclaimer: Code shown here is educational and not even particularly good. "Here be dragons" and all that.
Doing exactly what you want isn't possible without fiddling around with Python's internals because when you pass a variable into a function you're only passing its value (or a reference to its value), not the name of the variable. Because of that you've lost the information that allows you to precisely swap two variables.
If you're willing to accept some collateral damage (assuming your code isn't nested inside another function or something, which would complicate the code a ton with nonlocal variables), you can actually get your example to work. We don't know which variables to switch, so we just switch all of them.
def swapper(a, b):
# find all variables with the same values as the variables passed into swapper()
a_keys = {k for k,v in globals().items() if v==a}
b_keys = {k for k,v in globals().items() if v==b}
# swap _every_ pair of variables with those values to be sure we got the two
# that were passed in.
for k in a_keys:
globals()[k] = b
for k in b_keys:
globals()[k] = a
While we're at it, Python actually exposes a lot of its internals, and you can actually pinpoint the exact variables you're trying to swap. I'm lazy and don't really want to write/use a full Python parser, so I'm going to assume you're only calling swapper() exactly as you have written in your example (nothing else on the line). The following idea reads the current stack trace to figure out how you called swapper() to figure out the variable names to swap.
import traceback
def swapper(a, b):
# if you call swapper(x, y), then f_call == 'swapper(x, y)'
f_call = traceback.StackSummary.extract(traceback.walk_stack(None))[1].line
# parse out the arguments
first, second = (s.strip() for s in f_call.replace('swapper(', '').replace(')', '').split(','))
# actually swap the variables now that we know what they are
globals()[first], globals()[second] = globals()[second], globals()[first]
This isn't possible in Python with the data types as is.
You can read more in this question:
Passing an integer by reference in Python
Python doesn't allow to pass integers by reference, unlike C where you can pass the pointer directly and modify the value.
Changes towards x,y won't be reflected in the global scope, as the changes would only be done inside the function scope. There are two solutions to your problem.
The best way in my opinion is to simply assign the values with the x,y = y,x, however if you trully wish to have a function to swap values you could actually pass value by reference with data types such as a python list. Which is only a glorified pointer to the start of the list.
a = [0,1] # each index of the list being the variable
def swap(lst):
# lst being a list and of lenght 2
a[0],a[1] = a[1],a[0]
swap(a)
print(a) # prints [1,0]
Again, I just showed you a way to achieve what you want, but Python itself doesn't natively supports to pass values by reference in functions. Would be best to stick to the x,y = y,x or assign the values to the function return.
If you really want to use a separate function without returning anything, one workaround could be to use a list to store the two variables:
def swap(x):
x[0], x[1] = x[1], x[0]
x = [0, 1]
swap(x)
print(x)
# [1, 0]
This works because in this case you are passing a reference to a mutable object (a list), which you can modify inside of the function.

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

Multiple return values in python

I want to change a python function to return two values. How do I achieve that without affecting any of the previous function calls which only expect one return value?
For eg.
Original Definition:
def foo():
x = 2
y = 2
return (x+y)
sum = foo()
Ne Definition:
def foo():
x = 2
y = 2
return (x+y), (x-y)
sum, diff = foo()
I want to do this in a way that the previous call to foo also remains valid?
Is this possible?
def foo(return_2nd=False):
x = 2
y = 2
return (x+y) if not return_2nd else (x+y),(x-y)
then call new version
sum, diff = foo(True)
sum = foo() #old calls still just get sum
By changing the type of return value you are changing the "contract" between this function and any code that calls it. So you probably should change the code that calls it.
However, you could add an optional argument that when set will return the new type. Such a change would preserve the old contract and allow you to have a new one as well. Although it is weird having different kinds of return types. At that point it would probably be cleaner to just create a new function entirely, or fix the calling code as well.
I'm sorry to tell you, but function overloading is not valid in Python. Because Python does not do type-enforcement, multiple definitions of foo results in the last valid one being used. One common solution is to define multiple functions, or to add a parameter in the function as a flag (which you would need to implement yourself)

Which of these are immutable in Python?

I am trying to figure out whether the following are immutable in Sage (which is built on Python so I believe if it is immutable in python, I believe in most cases it will be immutable in Sage)
Below are objects e, f, g, i
class e: pass
f = e()
g = pi # (g's "type" in Sage is symbolic expression. It's supposed to be 3.1415....etc)
i = lambda x: x*x
I gather that e is a class which means it is mutable (Does an immutable class make sense? Can't all classes be modified?). Since f is an instance of a class, I am guessing it is also mutable since classes are mutable.
Since numbers are immutable in Python, g should be immutable as well since it is a number despite being irrational
Finally i is a function which means it should be mutable?
I'm not quite sure I understand that concept of immutability. What would it mean for a function to be immutable? For a class to be immutable?
e is mutable. You can, for instance, add a new method on the class: e.foo = lambda self,x: x.
f is mutable. You can, for instance, add a new field to this class instance: f.x = 99.
g is immutable. You can't change anything about it.
i is not immutable. You can do all sorts of evil things to it: i.func_code = (lambda x: 123).func_code after which i(10) will be 123 instead of 100. (You can also do more reasonable things to it. After i.__doc__ = "This function returns the square of its argument." you will get a more helpful result from help(i).)
An object is mutable if there's something you can do to the object that changes its possible future behaviour. You can't change the behaviour of 10; you can change the behaviour of a function object, or a class, or a class instance, or a list. (But not a tuple. Once a tuple is made, it stays just as it is for as long as it exists.)
Formally? An object is mutable if it can change value without changing identity.
Lists are mutable, so the value of a particular instance can change over time:
>>> x = orig_x = []
>>> x == []
True
>>> x += [1]
>>> x == [] # The value of x has changed
False
>>> x is orig_x # But the identity remains the same
True
Numbers are immutable, however, so their value can't change. Instead, the variable has to be updated to refer to a completely different object:
>>> x = orig_x = 1
>>> x == 1
True
>>> x += 1
>>> x == 1 # Again, the value of x has changed
False
>>> x is orig_x # But now the identity has changed as well
False
Immutability is an important concept, since knowing that an object's value can't change lets you make certain assumptions about it (for example, dict effectively requires immutable keys and set and frozenset require immutable members, as the value of an object affects how it should be stored in the data structure. If mutable entries were permitted, they may end up being in the wrong place if they are modified after being stored)
Contrary to popular belief, user defined classes that don't override the definition of equality are technically immutable. This is because the default definition of the "value" of a user defined class is just id(self). When an object's value is its identity, there is obviously no way for them to differ over time, and hence the object doesn't quality as "mutable".
Informally? Most people use an intuitive "Can I change it?" definition along the lines of Gareth McCaughan's answer. It's the same basic idea as the formal definition, just using a broader meaning of the term "value" than the technical definition in terms of equality checks.

Categories

Resources