Swapping variables in python - 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.

Related

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

Initialising a list of lambda functions in python

I have a tuple of functions that I want to pre-load with some data. Currently the way I am doing this is below. Essentially, I make a list of the new functions, and add the lambda functions to it one at a time, then reconvert to a tuple. However, when I use these functions in a different part of the code, every one of them acts as if it were the last one in the list.
def newfuncs(data, funcs):
newfuncs = []
for f in funcs:
newf = lambda x: f(x, data)
newfuncs.append(newf)
return tuple(newfuncs)
Here is a simple example of the problem
funcs = (lambda x, y: x + y, lambda a, b: a - b)
funcs = newfuncs(10, funcs)
print(funcs[0](5))
print(funcs[1](5))
I would expect the number 15 to be printed, then -5. However, this code prints the number -5 twice. If anyone can help my understand why this is happening, it would be greatly appreciated. Thanks!
As mentioned, the issue is with the variable f, which is the same variable assigned to all lambda functions, so at the end of the loop, every lambda sees the same f.
The solution here is to either use functools.partial, or create a scoped default argument for the lambda:
def newfuncs(data, funcs):
newfuncs = []
for f in funcs:
newf = lambda x, f=f: f(x, data) # note the f=f bit here
newfuncs.append(newf)
return tuple(newfuncs)
Calling these lambdas as before now gives:
15
-5
If you're using python3.x, make sure to take a look at this comment by ShadowRanger as a possible safety feature to the scoped default arg approach.
This is a well-known Python "issue," or should I say "this is just the way Python is."
You created the tuple:
( x => f(x, data), x => f(x, data) )
But what is f? f is not evaluated until you finally call the functions!
First, f was (x, y)=>x+y. Then in your for-loop, f was reassigned to (x, y)=>x-y.
When you finally get around to calling your functions, then, and only then, will the value of f be looked up. What is the value of f at this point? The value is (x, y)=>x-y for all of your functions. All of your functions do subtraction. This is because f is reassigned. There is ONLY ONE f. And the value of that one and only one f is set to the subtraction function, before any of your lambdas ever get called.
ADDENDUM
In case anyone is interested, different languages approach this problem in different ways. JavaScript is rather interesting (some would say confusing) here because it does things the Python way, which the OP found unexpected, as well as a different way, which the OP would have expected. In JavaScript:
> let funcs = []
> for (let f of [(x,y)=>x+y, (x,y)=>x-y]) {
funcs.push(x=>f(x,10));
}
> funcs[0](5)
15
funcs[1](5)
-5
However, if you change let to var above, it behaves like Python and you get -5 for both! This is because with let, you get a different f for each iteration of the for-loop; with var, the whole function shares the same f, which keeps getting reassigned. This is how Python works.
cᴏʟᴅsᴘᴇᴇᴅ has shown you that the way to do what you expect is to make sure you get that different f for each iteration, which Python allows you do in a pretty neat way, defaulting the second argument of the lambda to a f local to that iteration. It's pretty cool, so their answer should be accepted if it helps you.

Parsing numbers based on dynamically specified types in Scala

Coming from a Python background, I'm used to having types available as objects at runtime. Having that, combined with the fact that at least in the case of int and float these type objects also happen to be callables that act as parsers (e.g. int("234") == 234, like Scala's "234".toInt == 234), I can come up with a solution to parse, say, a matrix of either integers or floating point numbers from a text file. The only thing I have to do is configure a parameter:
ITEM_TYPE = int # or float
and I'm good to go:
with open('matrix.dat') as f:
matrix_data_raw = parse_raw_matrix(f.read())
matrix = [map(ITEM_TYPE, row) for row in matrix]
changing the value of ITEM_TYPE to float immediately gives me a list of list of floats at runtime (there's no static typing but the contents of matrix are still strongly typed to be either list[list[int]] or list[list[float]]).
In Scala, I would expect the static type of matrix to be e.g. either Matrix[Int] or Matrix[Double] (from, say, a more general type Matrix[T: Numeric] = Vector[Vector[T]]). However, being a relative beginner with Scala, I'm a bit lost as to how to achieve this. There's no obvious/easy way to just switch the value of a parameter from classOf[Int] to classOf[Double]—even if I did that and dynamically chose the parser function accordingly (which would straightforward), how would I go about changing the runtime type of matrix from, say, Matrix[Int] to Matrix[Double]? And what would I have to declare the static type of matrix to be—Matrix[Numeric]?
Before you judge the naiveté of the question, I'll admit that I'm aware that the Scala'esque solution probably requires a somewhat different approach, but I just liked the idea of starting my thoughts off of the (IMO rather elegant) Python solution.
Try this:
// Define this whereever makes sense, possibly as an abstract method in a trait
// with suitable concrete implementations that you can mix in to the class doing
// the matrix work, or with the body determined based on config data, etc.:
def itemType: String => Number = _.toInt // or _.toDouble or whatever
// Set up your read:
val matrixDataRaw = parseRawMatrix(f.read()) // Matrix[String] at this point
val matrix = matrixDataRaw.map(itemType)
You might, however, be better off passing itemType into your parsing function and converting the text snippets before putting them in the matrix class (which currently needs a map method defined on it to do the transform).
I think it is worth pointing out that the runtime type of your matrix is always Matrix[Object] - running on the JVM, generic types are erased at runtime.
That said, you can still specify the runtime type of the elements in your matrix. I think you'd have to do this with a function though. I'll use lists to illustrate this:
val int: (String => Number) = _.toInt
val float: (String => Number) = _.toFloat
You'd have to define any of these that you'd potentially use at runtime. That done, usage is simple:
val NUM_TYPE: (String => Number) = int // or whichever you choose
...
val list = List("1", "2", "3") map (NUM_TYPE)
This will always give you back a List[Number], but it will be populated with (in this case) Ints.
You cannot do this. The best thing I can suggest would be if you know you're either going to be getting ints or floats, do both of them.
trait Matrix[+A]
def parseRawData[A : Numeric](fp: io.Source, parseNum: String => A): Matrix[A]...
def manipulateRawData[A : Numeric](fp: io.Source): Matrix[A] = {
val mat = parseRawData
val numeric = implicitly[Numeric[A]]
...
}
if (ints) {
manipulateRawData[Int](fp, _.toInt)
}
else if (doubles) {
manipulateRawData[Double](fp, _.toDouble)
}
You can see that you end up with a Matrix[AnyVal] at the end (be careful about your types), but it will do the right thing intermediately.

Initialize a list of objects in Python

I'm a looking to initialize an array/list of objects that are not empty -- the class constructor generates data. In C++ and Java I would do something like this:
Object lst = new Object[100];
I've dug around, but is there a Pythonic way to get this done?
This doesn't work like I thought it would (I get 100 references to the same object):
lst = [Object()]*100
But this seems to work in the way I want:
lst = [Object() for i in range(100)]
List comprehension seems (intellectually) like "a lot" of work for something that's so simple in Java.
There isn't a way to implicitly call an Object() constructor for each element of an array like there is in C++ (recall that in Java, each element of a new array is initialised to null for reference types).
I would say that your list comprehension method is the most Pythonic:
lst = [Object() for i in range(100)]
If you don't want to step on the lexical variable i, then a convention in Python is to use _ for a dummy variable whose value doesn't matter:
lst = [Object() for _ in range(100)]
For an equivalent of the similar construct in Java, you can of course use *:
lst = [None] * 100
You should note that Python's equvalent for Java code
(creating array of 100 null references to Object):
Object arr = new Object[100];
or C++ code:
Object **arr = new Object*[100];
is:
arr = [None]*100
not:
arr = [Object() for _ in range(100)]
The second would be the same as Java's:
Object arr = new Object[100];
for (int i = 0; i < arr.lenght; i++) {
arr[i] = new Object();
}
In fact Python's capabilities to initialize complex data structures are far better then Java's.
Note:
C++ code:
Object *arr = new Object[100];
would have to do as much work as Python's list comprehension:
allocate continuous memory for 100 Objects
call Object::Object() for each of this Objects
And the result would be a completely different data structure.
I think the list comprehension is the simplest way, but, if you don't like it, it's obviously not the only way to obtain what you desire -- calling a given callable 100 times with no arguments to form the 100 items of a new list. For example, itertools can obviously do it:
>>> import itertools as it
>>> lst = list(it.starmap(Object, it.repeat((), 100)))
or, if you're really a traditionalist, map and apply:
>>> lst = map(apply, 100*[Object], 100*[()])
Note that this is essentially the same (tiny, both conceptually and actually;-) amount of work it would take if, instead of needing to be called without arguments, Object needed to be called with one argument -- or, say, if Object was in fact a function rather than a type.
From your surprise that it might take "as much as a list comprehension" to perform this task, you appear to think that every language should special-case the need to perform "calls to a type, without arguments" over other kinds of calls to over callables, but I fail to see what's so crucial and special about this very specific case, to warrant treating it differently from all others; and, as a consequence, I'm pretty happy, personally, that Python doesn't single this one case out for peculiar and weird treatment, but handles just as regularly and easily as any other similar use case!-)
lst = [Object() for i in range(100)]
Since an array is it's own first class object in python I think this is the only way to get what you're looking for. * does something crazy.

Categories

Resources