I've been looking at passing arrays, or lists, as Python tends to call them, into a function.
I read something about using *args, such as:
def someFunc(*args)
for x in args
print x
But not sure if this is right/wrong. Nothing seems to work as I want. I'm used to be able to pass arrays into PHP function with ease and this is confusing me. It also seems I can't do this:
def someFunc(*args, someString)
As it throws up an error.
I think I've just got myself completely confused and looking for someone to clear it up for me.
When you define your function using this syntax:
def someFunc(*args):
for x in args
print x
You're telling it that you expect a variable number of arguments. If you want to pass in a List (Array from other languages) you'd do something like this:
def someFunc(myList = [], *args):
for x in myList:
print x
Then you can call it with this:
items = [1,2,3,4,5]
someFunc(items)
You need to define named arguments before variable arguments, and variable arguments before keyword arguments. You can also have this:
def someFunc(arg1, arg2, arg3, *args, **kwargs):
for x in args
print x
Which requires at least three arguments, and supports variable numbers of other arguments and keyword arguments.
You can pass lists just like other types:
l = [1,2,3]
def stuff(a):
for x in a:
print a
stuff(l)
This prints the list l. Keep in mind lists are passed as references not as a deep copy.
You don't need to use the asterisk to accept a list.
Simply give the argument a name in the definition, and pass in a list like
def takes_list(a_list):
for item in a_list:
print item
Python lists (which are not just arrays because their size can be changed on the fly) are normal Python objects and can be passed in to functions as any variable. The * syntax is used for unpacking lists, which is probably not something you want to do now.
def sumlist(items=[]):
sum = 0
for i in items:
sum += i
return sum
t=sumlist([2,4,8,1])
print(t)
Related
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'])
I want to write a wrapper function which call one function and pass the results to another function. The arguments and return types of the functions are the same, but I have problem with returning lists and multiple values.
def foo():
return 1,2
def bar():
return (1,2)
def foo2(a,b):
print(a,b)
def bar2(p):
a,b=p
print(a,b)
def wrapper(func,func2):
a=func()
func2(a)
wrapper(bar,bar2)
wrapper(foo,foo2)
I am searching for a syntax which works with both function pairs to use it in my wrapper code.
EDIT: The definitions of at least foo2 and bar2 should stay this way. Assume that they are from an external library.
There is no distinction. return 1,2 returns a tuple. Parentheses do not define a tuple; the comma does. foo and bar are identical.
As I overlooked until JacobIRR's comment, your problem is that you need to pass an actual tuple, not the unpacked values from a tuple, to bar2:
a = foo()
foo2(*a)
a = bar()
bar2(a)
I don't necessarily agree with the design, but following your requirements in the comments (the function definitions can't change), you can write a wrapper that tries to execute each version (packed vs. unpacked) since it sounds like you might not know what the function expects. The wrapper written below, argfixer, does exactly that.
def argfixer(func):
def wrapper(arg):
try:
return func(arg)
except TypeError:
return func(*arg)
return wrapper
def foo():
return 1,2
def bar():
return (1,2)
#argfixer
def foo2(a,b):
print(a,b)
#argfixer
def bar2(p):
a,b=p
print(a,b)
a = foo()
b = bar()
foo2(a)
foo2(b)
bar2(a)
bar2(b)
However, if you aren't able to put the #argfixer on the line before the function definitions, you could alternatively wrap them like this in your own script before calling them:
foo2 = argfixer(foo2)
bar2 = argfixer(bar2)
And as mentioned in previous comments/answers, return 1,2 and return (1,2) are equivalent and both return a single tuple.
This code does not run because of arg differences. It runs if you use def foo2(*args): and def bar2(*p):.
The return 1, 2 and return (1, 2) are equivalent. The comma operator just creates a tuple, whether it is enclosed in parentheses or not.
All programming languages that I know of return a single value, so, since you want to return multiple, those values must be wrapped into a collection type, in this case, a tuple.
The problem is in the way you call the second function. Make it bar2(a) instead of bar2(*a), which breaks the tuple into separate arguments.
Having a function
def my_function (argument):
summe=argument+5
print(summe)
return
I want to loop the function for different arguments like
arguments=linspace(-0.1,-8.0,80)
and every single sum (summe) to be saved in one array together
So how can I repeat a function (the simple function above is only an example) with different arguments?
result shoul look like:
[4.9,4.8,4.7 ... -2.8,-2.9,-3.0]
You would have to return the sum from your function like this:
def my_function (argument):
summe = argument + 5
print(summe)
return summe
Then, given that you have some arguments in an array, for example:
arguments = [-0.1,8.0,80]
You can loop over these arguments and store the result of your function calls in another array using a list comprehension:
result = [my_function(arg) for arg in arguments]
This question already has answers here:
Mutability of the **kwargs argument in Python
(3 answers)
Closed 8 years ago.
Python beginner's question. I'm trying to change the value of some variables inside a function, and I don't understand why sometimes it works and sometimes it doesn't. So I would like to know what's happening behind the scenes. If I write:
def assign(self, **kwargs):
kwargs['test'] = 3
kwargs['steps'] += [1]
t = 1
s = []
assign(test=t, steps=s)
print(t)
print(s)
This still prints
1
[]
Now, if I change the function assign to
def assign(self, **kwargs):
kwargs['test'] += 3
kwargs['steps'] += [1, 2, 3]
it changes the list but not the integer. So I guess this has to do with the fact that integer are immutable and a list is mutable. So then I thought to use a dictionary instead, to make sure that my variables are changed. So then:
dict = {'test':1, 'steps': []}
assign(**dict)
print(dict)
still prints
{'test': 1, 'steps': [1, 2, 3]}
with exactly the same behavior, so now I'm really puzzled. It seems that when unpacking the dictionary, I am not passing references to the dictionary variables anymore so that these unpacked variables are being copied by value? What's the best way to achieve what I try to do then?
UPDATE
Thanks to the discussion with #6502, since
In Python there is no way to change a parameter that has been passed to a function because you cannot have "pointers" or "references".
The most pythonic way is not doing it. A function receive parameters and provide results. If the parameter is a mutable it can mutate its state but changing the call parameter itself was considered not needed.
Then I decided to return a dictionary with the results instead:
def assign(self, **kwargs):
kwargs['test'] += 3
kwargs['steps'] += [1, 2, 3]
return kwargs
dict = {'test':1, 'steps': []}
dict = assign(**dict)
print(dict)
This works of course, but I wonder the implications on large data, as it seems to me that (coming from a C++ world), there's a lot of copying around.
The first example is wrong, you get s=[1]:
That's because the list s is a parameter, steps and you change the contents of this list.
Much simpler:
def assign(step):
step += [1] # change the contents of the list
s = []
assign(step=s)
print(s) # gives [1]
That as nothing to do with keyword arguments or dict expansion. If you use ** or give the key words directly as parameters is absolutely the same.
Don't try to pass variables «by reference». That's not possible with python. Use return values instead.
def assign(test, steps):
return 3, steps + [1]
t, s = assign(3, [])
A simple way to rationalize the semantic is to consider that all Python values are indeed pointers to objects and that those pointers are always passed by value.
If you change the object pointed to the caller can see the mutation, but if you assign the variable you're just changing what it's pointing to and the caller won't notice.
In Python there is no way to change a parameter that has been passed to a function because you cannot have "pointers" or "references". The only way to mutate a variable is using its name.
A work-around (in Python 3) is to pass a closure that can access the local, for example:
def foo(x, y, set_result):
set_result(x + y)
def bar():
res = None
def set_res(x):
nonlocal res
res = x
foo(10, 20, set_res)
print(res)
This kind of trickery is however rarely needed because in languages with reference parameter passing the most common use is to return multiple values, e.g. (C++)
bool read_xy(double& x, double& y);
where the function needs to return three values, x, y and a success flag.
In Python however this is not needed as you can just write
return x, y
and use it as
x, y = read_xy()
Hi everyone this is probably something extremely simple that i'm overlooking but can someone point me in the right direction for how to handle this problem.
def nodeFunction(self,*args):
return self[1] + self[2]
Basically what I am trying to do is grab the data passed in through the arguments. I am just stuck on the syntax for referencing the arguments inside the function when using *args.
args is simply a tuple:
def nodeMethod(self, *args):
return args[0], args[1]
Is that what you mean?
Note that there's nothing special about "args". You could use any variable name. It's the * operator that counts.
>>> class Node(object):
... def nodeMethod(self, *cornucopia):
... return cornucopia[0], cornucopia[1]
...
>>> n = Node()
>>> n.nodeMethod(1, 2, 3)
(1, 2)
Still, "args" is the most idiomatic variable name; I wouldn't use anything else without a good reason that would be obvious to others.
def nodeFunction(self, arg1, arg2, *args)
*arg in argument list means: pass the remaning arguments as a list in variable arg. So check how to handle lists. Note: list index starts from 0.