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 have a strange question when using python loop. It may be easy but strange to me. Say if I have a list of strings:
seqs=['AA', 'AT']
Then I want to print out elements in the list. One way (method 1) is to use for loop:
for seq in seqs:
print seq
Which works fine. Meanwhile, I define a 'print' function (method 2) to print:
def print0(s):
print s
[print0(s) for s in seqs]
If I use the 'print0' function to print out values, this is the output:
AA
AT
[None, None]
I want to know why here comes two 'None' values, since these two values doesn't come when I use the method 1? I want to do the for loop by using paralleling technic, but with the
'None' value, delayed function from joblib package can't work. Thanks.
Update: if I want do it parallel:
Parallel(n_jobs=2)(delayed(print0)(seq) for seq in seqs)
It will give an error message:
TypeError: expected string or Unicode object, NoneType found
Since you are using the interactive interpreter, which by default prints the repr() for any object returned to the top level, you see a list of None objects, which is what got returned from the calls of your print0 function. This is why it's not good practice to create a list just for its side effects, in addition to the fact that all of those objects are stored in memory (although there's only one None object, and that list will be garbage-collected as soon as you return something else to the top level - until then, it's stored in the special variable _).
You'll recognize how the interpreter displays the repr() of any object returned to the top level:
>>> 'hello'
'hello'
And it makes sense that the following literal list is displayed:
>>> [print()]
[None]
And the same for a comprehension:
>>> [print(num) for num in range(3)]
0
1
2
[None, None, None]
But it's better to use an ordinary loop. One-liners are fun, but not always ideal.
>>> for num in range(3):
... print(num)
...
0
1
2
Note that you can get odd results if a function prints one thing and returns another:
>>> def f():
... print(1)
... return 2
...
>>> [f() for num in range(3)]
1
1
1
[2, 2, 2]
>>> for num in range(3):
... f()
...
1
2
1
2
1
2
This is a demonstration of "side-effects." Try to avoid code that makes changes in two different places at once (in this case, the interactive interpreter's displayed results and the local actions of a function).
The syntax [print0(s) for s in seqs] is a List Comprehension.
It will call print0(s) for every element in seq and put the result into a list. Because print0 returns nothing, you get a list of 2 Nones.
I see such questions so often, there should be some ultimate answer to them all, which automatically triggers whenever print and None are both present in a single question...
While the answer to the question itself is trivial, what, I think, you need to really understand is a difference between a side effect and a return value. For example:
a = 10
def three(x):
global a
a += x #side effect
print x #side effect
return 3 #returning
The value our three() function returns is 3. It also has two side effects: modifying a global variable a and printing. Those are called side effects because they modify something outside of the function: the a variable and the screen state, respectively.
In your example:
def print0(s):
print s
there's no explicit return value, only a side effect (printing). In other words, it prints something on the screen and then returns nothing. That nothing is called None in Python. If you call it like this:
a = print0(3)
it prints 3 into the console. But what is the value of a now?
>>> print a
None
Now to the list comprehension. It is a concept borrowed from functional programming (Lisp, etc.) where it's called map. There's still map function in Python, so the following two lines are equivalent:
[print0(s) for s in seqs]
map(print0, seqs)
What they both do is taking the elements of the input list (seqs), one by one, applying the function (print0) to each of them and putting the results (return values), one by one, into the output list, which they return. Each time they call your print0 function, it prints its argument s on the screen (a side effect) and then returns nothing (None), which is put into the output list by list comprehension or map. If you do it in the Python interactive console, that result appears in the output ([None, None]), if not - it is still produced by the interpreter and immediately discarded, unless you pass it as an argument to another statement. Which leads us to your final line of code and the TypeError message. You pass your function to another function, which expects a string, it doesn't care about the side effects your function may produce. The context is not completely clear to me, but you probably should define your function like this:
def print0(s):
return str(s)
Now, instead of printing s on the screen, it converts it to string and then returns it. Note that if you call them inside the interactive interpreter just like print0(s), it appears they produce the same effect, which may be confusing. However, if you do a = print0(s) you will see that a is different. In some languages the last computed value automatically becomes the return value, but with Python that isn't the case for regular functions:
def times_three(x):
x*3
returns None. However, there are also lambda-functions, for which that is the case:
times_three = lambda x: x*3
times_three(5) #returns 15
None is the return value of print0(s). When using print the result will just be displayed in the stdout but not returned as result of the function. So the comprehension list evalute the function as None.
Your funtion should instead be:
def print0(s):
return s
Another way, if you want do it interactively in a one-liner is to use .join
text = ['28', '43', '6f', '72', '65', '20', '64', '6f', '6d', '70', '65', '64', '29', '0a']
''.join(chr(int(x, 16)) for x in text)
I'm trying to write a short program which allows the user to input a list of numbers into an input() function, and then using the add_25 function add 25 to each item in a list.
I get the following error when the program runs: TypeError: 'tuple' object does not support item assignment
I tried dividing the numbers using a comma. This is the program:
testlist = [2,6,2]
def add_25(mylist):
for i in range(0, len(mylist)):
mylist[i] = mylist[i] + 25
return mylist
print add_25(testlist)
actual_list = input("Please input a series of numbers, divided by a comma:")
print add_25(actual_list)
In Python 2 input() will eval the string and in this case it will create a tuple, and as tuples are immutable you'll get that error.
>>> eval('1, 2, 3')
(1, 2, 3)
It is safer to use raw_input with a list-comprehension here:
inp = raw_input("Please input a series of numbers, divided by a comma:")
actual_list = [int(x) for x in inp.split(',')]
Or if you're not worried about user's input then simply convert the tuple to list by passing it to list().
Also note that as you're trying to update the list in-place inside of the function it makes no sense to return the list unless you want to assign another variable to the same list object. Either return a new list or don't return anything.
The function input reads a string and evaluates it as a Python expression. Thus, the comma-separated list becomes a tuple of values, these are passed to add_25(), and this function tries to assign to mylist[i] something.
And tuples are immutable, they do not support item assignment (on purpose).
You could use actual_list = list(input(...)) to convert the tuple to a list (which supports item assignment).
But every time someone uses input(), one has to warn him: input() is a security risk. It evaluates the input of the user and thus might execute arbitrary things the user typed. This means that your program will perform what the user asks it to, with your permissions. This is normally not what is considered a good design.
If you always will be the only user or if you trust all users of your program completely, then so be it.
Besides all the input() aspects covered in the other answers, I'd like to add this completely different aspect:
Your function add_25() is probably not supposed to change its input. Yours does, or tries to, and fails because tuples do not allow that.
But you actually do not have to change the input (and you should not, because this is not good style due to its ugly side-effects). Instead you could just return a new tuple:
def add_25(mytuple):
return tuple(x + 25 for x in mytuple)
This way, nothing is assigned to a tuple, just a new tuple is created and returned.
def test_tuples_of_one_look_peculiar(self):
self.assertEqual( __,(1).__class__)
self.assertEqual(__, (1,).__class__)
Let's say I have a function f() that takes a list and returns a mutation of that list. If I want to apply that function to five member variables in my class instance (i), I can do this:
for x in [i.a, i.b, i.c, i.d, i.e]:
x[:] = f(x)
1) Is there a more elegant way? I don't want f() to modify the passed list.
2) If my variables hold a simple integer (which won't work with the slice notation), is there also a way? (f() would also take & return an integer in this case)
Another solution, though it's probably not elegant:
for x in ['a', 'b', 'c', 'd', 'e']:
setattr(i, x, f(getattr(i, x)))
Python doesn't have pass by reference. The best you can do is write a function which constructs a new list and assign the result of the function to the original list. Example:
def double_list(x):
return [item * 2 for item in x]
nums = [1, 2, 3, 4]
nums = double_list(nums) # now [2, 4, 6, 8]
Or better yet:
nums = map(lambda x: x * 2, nums)
Super simple example, but you get the idea. If you want to change a list from a function you'll have to return the altered list and assign that to the original.
You might be able to hack up a solution, but it's best just to do it the normal way.
EDIT
It occurs to me that I don't actually know what you're trying to do, specifically. Perhaps if you were to clarify your specific task we could come up with a solution that Python will permit?
Ultimately, what you want to do is incompatible with the way that Python is structured. You have the most elegant way to do it already in the case that your variables are lists but this is not possible with numbers.
This is because variables do not exist in Python. References do. So i.x is not a list, it is a reference to a list. Likewise, if it references a number. So if i.x references y, then i.x = z doesn't actually change the value y, it changes the location in memory that i.x points to.
Most of the time, variables are viewed as boxes that hold a value. The name is on the box. In python, values are fundamental and "variables" are just tags that get hung on a particular value. It's very nice once you get used to it.
In the case of a list, you can use use slice assignment, as you are already doing. This will allow all references to the list to see the changes because you are changing the list object itself. In the case of a number, there is no way to do that because numbers are immutable objects in Python. This makes sense. Five is five and there's not much that you can do to change it. If you know or can determine the name of the attribute, then you can use setattr to modify it but this will not change other references that might already exist.
As Rafe Kettler says, if you can be more specific about what you actually want to do, then we can come up with a simple elegant way to do it.
I have a situation in Python(cough, homework) where I need to multiply EACH ELEMENT in a given list of objects a specified number of times and return the output of the elements. The problem is that the sample inputs given are of different types. For example, one case may input a list of strings whose elements I need to multiply while the others may be ints. So my return type needs to vary. I would like to do this without having to test what every type of object is. Is there a way to do this? I know in C# i could just use "var" but I don't know if such a thing exists in Python?
I realize that variables don't have to be declared, but in this case I can't see any way around it. Here's the function I made:
def multiplyItemsByFour(argsList):
output = ????
for arg in argsList:
output += arg * 4
return output
See how I need to add to the output variable. If I just try to take away the output assignment on the first line, I get an error that the variable was not defined. But if I assign it a 0 or a "" for an empty string, an exception could be thrown since you can't add 3 to a string or "a" to an integer, etc...
Here are some sample inputs and outputs:
Input: ('a','b') Output: 'aaaabbbb'
Input: (2,3,4) Output: 36
Thanks!
def fivetimes(anylist):
return anylist * 5
As you see, if you're given a list argument, there's no need for any assignment whatsoever in order to "multiply it a given number of times and return the output". You talk about a given list; how is it given to you, if not (the most natural way) as an argument to your function? Not that it matters much -- if it's a global variable, a property of the object that's your argument, and so forth, this still doesn't necessitate any assignment.
If you were "homeworkically" forbidden from using the * operator of lists, and just required to implement it yourself, this would require assignment, but no declaration:
def multiply_the_hard_way(inputlist, multiplier):
outputlist = []
for i in range(multiplier):
outputlist.extend(inputlist)
return outputlist
You can simply make the empty list "magicaly appear": there's no need to "declare" it as being anything whatsoever, it's an empty list and the Python compiler knows it as well as you or any reader of your code does. Binding it to the name outputlist doesn't require you to perform any special ritual either, just the binding (aka assignment) itself: names don't have types, only objects have types... that's Python!-)
Edit: OP now says output must not be a list, but rather int, float, or maybe string, and he is given no indication of what. I've asked for clarification -- multiplying a list ALWAYS returns a list, so clearly he must mean something different from what he originally said, that he had to multiply a list. Meanwhile, here's another attempt at mind-reading. Perhaps he must return a list where EACH ITEM of the input list is multiplied by the same factor (whether that item is an int, float, string, list, ...). Well then:
define multiply_each_item(somelist, multiplier):
return [item * multiplier for item in somelist]
Look ma, no hands^H^H^H^H^H assignment. (This is known as a "list comprehension", btw).
Or maybe (unlikely, but my mind-reading hat may be suffering interference from my tinfoil hat, will need to go to the mad hatter's shop to have them tuned) he needs to (say) multiply each list item as if they were the same type as the first item, but return them as their original type, so that for example
>>> mystic(['zap', 1, 23, 'goo'], 2)
['zapzap', 11, 2323, 'googoo']
>>> mystic([23, '12', 15, 2.5], 2)
[46, '24', 30, 4.0]
Even this highly-mystical spec COULD be accomodated...:
>>> def mystic(alist, mul):
... multyp = type(alist[0])
... return [type(x)(mul*multyp(x)) for x in alist]
...
...though I very much doubt it's the spec actually encoded in the mysterious runes of that homework assignment. Just about ANY precise spec can be either implemented or proven to be likely impossible as stated (by requiring you to solve the Halting Problem or demanding that P==NP, say;-). That may take some work ("prove the 4-color theorem", for example;-)... but still less than it takes to magically divine what the actual spec IS, from a collection of mutually contradictory observations, no examples, etc. Though in our daily work as software developer (ah for the good old times when all we had to face was homework!-) we DO meet a lot of such cases of course (and have to solve them to earn our daily bread;-).
EditEdit: finally seeing a precise spec I point out I already implemented that one, anyway, here it goes again:
def multiplyItemsByFour(argsList):
return [item * 4 for item in argsList]
EditEditEdit: finally/finally seeing a MORE precise spec, with (luxury!-) examples:
Input: ('a','b') Output: 'aaaabbbb' Input: (2,3,4) Output: 36
So then what's wanted it the summation (and you can't use sum as it wouldn't work on strings) of the items in the input list, each multiplied by four. My preferred solution:
def theFinalAndTrulyRealProblemAsPosed(argsList):
items = iter(argsList)
output = next(items, []) * 4
for item in items:
output += item * 4
return output
If you're forbidden from using some of these constructs, such as built-ins items and iter, there are many other possibilities (slightly inferior ones) such as:
def theFinalAndTrulyRealProblemAsPosed(argsList):
if not argsList: return None
output = argsList[0] * 4
for item in argsList[1:]:
output += item * 4
return output
For an empty argsList, the first version returns [], the second one returns None -- not sure what you're supposed to do in that corner case anyway.
Very easy in Python. You need to get the type of the data in your list - use the type() function on the first item - type(argsList[0]). Then to initialize output (where you now have ????) you need the 'zero' or nul value for that type. So just as int() or float() or str() returns the zero or nul for their type so to will type(argsList[0])() return the zero or nul value for whatever type you have in your list.
So, here is your function with one minor modification:
def multiplyItemsByFour(argsList):
output = type(argsList[0])()
for arg in argsList:
output += arg * 4
return output
Works with::
argsList = [1, 2, 3, 4] or [1.0, 2.0, 3.0, 4.0] or "abcdef" ... etc,
Are you sure this is for Python beginners? To me, the cleanest way to do this is with reduce() and lambda, both of which are not typical beginner tools, and sometimes discouraged even for experienced Python programmers:
def multiplyItemsByFour(argsList):
if not argsList:
return None
newItems = [item * 4 for item in argsList]
return reduce(lambda x, y: x + y, newItems)
Like Alex Martelli, I've thrown in a quick test for an empty list at the beginning which returns None. Note that if you are using Python 3, you must import functools to use reduce().
Essentially, the reduce(lambda...) solution is very similar to the other suggestions to set up an accumulator using the first input item, and then processing the rest of the input items; but is simply more concise.
My guess is that the purpose of your homework is to expose you to "duck typing". The basic idea is that you don't worry about the types too much, you just worry about whether the behaviors work correctly. A classic example:
def add_two(a, b):
return a + b
print add_two(1, 2) # prints 3
print add_two("foo", "bar") # prints "foobar"
print add_two([0, 1, 2], [3, 4, 5]) # prints [0, 1, 2, 3, 4, 5]
Notice that when you def a function in Python, you don't declare a return type anywhere. It is perfectly okay for the same function to return different types based on its arguments. It's considered a virtue, even; consider that in Python we only need one definition of add_two() and we can add integers, add floats, concatenate strings, and join lists with it. Statically typed languages would require multiple implementations, unless they had an escape such as variant, but Python is dynamically typed. (Python is strongly typed, but dynamically typed. Some will tell you Python is weakly typed, but it isn't. In a weakly typed language such as JavaScript, the expression 1 + "1" will give you a result of 2; in Python this expression just raises a TypeError exception.)
It is considered very poor style to try to test the arguments to figure out their types, and then do things based on the types. If you need to make your code robust, you can always use a try block:
def safe_add_two(a, b):
try:
return a + b
except TypeError:
return None
See also the Wikipedia page on duck typing.
Python is dynamically typed, you don't need to declare the type of a variable, because a variable doesn't have a type, only values do. (Any variable can store any value, a value never changes its type during its lifetime.)
def do_something(x):
return x * 5
This will work for any x you pass to it, the actual result depending on what type the value in x has. If x contains a number it will just do regular multiplication, if it contains a string the string will be repeated five times in a row, for lists and such it will repeat the list five times, and so on. For custom types (classes) it depends on whether the class has an operation defined for the multiplication operator.
You don't need to declare variable types in python; a variable has the type of whatever's assigned to it.
EDIT:
To solve the re-stated problem, try this:
def multiplyItemsByFour(argsList):
output = argsList.pop(0) * 4
for arg in argsList:
output += arg * 4
return output
(This is probably not the most pythonic way of doing this, but it should at least start off your output variable as the right type, assuming the whole list is of the same type)
You gave these sample inputs and outputs:
Input: ('a','b') Output: 'aaaabbbb' Input: (2,3,4) Output: 36
I don't want to write the solution to your homework for you, but I do want to steer you in the correct direction. But I'm still not sure I understand what your problem is, because the problem as I understand it seems a bit difficult for an intro to Python class.
The most straightforward way to solve this requires that the arguments be passed in a list. Then, you can look at the first item in the list, and work from that. Here is a function that requires the caller to pass in a list of two items:
def handle_list_of_len_2(lst):
return lst[0] * 4 + lst[1] * 4
Now, how can we make this extend past two items? Well, in your sample code you weren't sure what to assign to your variable output. How about assigning lst[0]? Then it always has the correct type. Then you could loop over all the other elements in lst and accumulate to your output variable using += as you wrote. If you don't know how to loop over a list of items but skip the first thing in the list, Google search for "python list slice".
Now, how can we make this not require the user to pack up everything into a list, but just call the function? What we really want is some way to accept whatever arguments the user wants to pass to the function, and make a list out of them. Perhaps there is special syntax for declaring a function where you tell Python you just want the arguments bundled up into a list. You might check a good tutorial and see what it says about how to define a function.
Now that we have covered (very generally) how to accumulate an answer using +=, let's consider other ways to accumulate an answer. If you know how to use a list comprehension, you could use one of those to return a new list based on the argument list, with the multiply performed on each argument; you could then somehow reduce the list down to a single item and return it. Python 2.3 and newer have a built-in function called sum() and you might want to read up on that. [EDIT: Oh drat, sum() only works on numbers. See note added at end.]
I hope this helps. If you are still very confused, I suggest you contact your teacher and ask for clarification. Good luck.
P.S. Python 2.x have a built-in function called reduce() and it is possible to implement sum() using reduce(). However, the creator of Python thinks it is better to just use sum() and in fact he removed reduce() from Python 3.0 (well, he moved it into a module called functools).
P.P.S. If you get the list comprehension working, here's one more thing to think about. If you use a list comprehension and then pass the result to sum(), you build a list to be used once and then discarded. Wouldn't it be neat if we could get the result, but instead of building the whole list and then discarding it we could just have the sum() function consume the list items as fast as they are generated? You might want to read this: Generator Expressions vs. List Comprehension
EDIT: Oh drat, I assumed that Python's sum() builtin would use duck typing. Actually it is documented to work on numbers, only. I'm disappointed! I'll have to search and see if there were any discussions about that, and see why they did it the way they did; they probably had good reasons. Meanwhile, you might as well use your += solution. Sorry about that.
EDIT: Okay, reading through other answers, I now notice two ways suggested for peeling off the first element in the list.
For simplicity, because you seem like a Python beginner, I suggested simply using output = lst[0] and then using list slicing to skip past the first item in the list. However, Wooble in his answer suggested using output = lst.pop(0) which is a very clean solution: it gets the zeroth thing on the list, and then you can just loop over the list and you automatically skip the zeroth thing. However, this "mutates" the list! It's better if a function like this does not have "side effects" such as modifying the list passed to it. (Unless the list is a special list made just for that function call, such as a *args list.) Another way would be to use the "list slice" trick to make a copy of the list that has the first item removed. Alex Martelli provided an example of how to make an "iterator" using a Python feature called iter(), and then using iterator to get the "next" thing. Since the iterator hasn't been used yet, the next thing is the zeroth thing in the list. That's not really a beginner solution but it is the most elegant way to do this in Python; you could pass a really huge list to the function, and Alex Martelli's solution will neither mutate the list nor waste memory by making a copy of the list.
No need to test the objects, just multiply away!
'this is a string' * 6
14 * 6
[1,2,3] * 6
all just work
Try this:
def timesfourlist(list):
nextstep = map(times_four, list)
sum(nextstep)
map performs the function passed in on each element of the list(returning a new list) and then sum does the += on the list.
If you just want to fill in the blank in your code, you could try setting object=arglist[0].__class__() to give it the zero equivalent value of that class.
>>> def multiplyItemsByFour(argsList):
output = argsList[0].__class__()
for arg in argsList:
output += arg * 4
return output
>>> multiplyItemsByFour('ab')
'aaaabbbb'
>>> multiplyItemsByFour((2,3,4))
36
>>> multiplyItemsByFour((2.0,3.3))
21.199999999999999
This will crash if the list is empty, but you can check for that case at the beginning of the function and return whatever you feel appropriate.
Thanks to Alex Martelli, you have the best possible solution:
def theFinalAndTrulyRealProblemAsPosed(argsList):
items = iter(argsList)
output = next(items, []) * 4
for item in items:
output += item * 4
return output
This is beautiful and elegant. First we create an iterator with iter(), then we use next() to get the first object in the list. Then we accumulate as we iterate through the rest of the list, and we are done. We never need to know the type of the objects in argsList, and indeed they can be of different types as long as all the types can have operator + applied with them. This is duck typing.
For a moment there last night I was confused and thought that you wanted a function that, instead of taking an explicit list, just took one or more arguments.
def four_x_args(*args):
return theFinalAndTrulyRealProblemAsPosed(args)
The *args argument to the function tells Python to gather up all arguments to this function and make a tuple out of them; then the tuple is bound to the name args. You can easily make a list out of it, and then you could use the .pop(0) method to get the first item from the list. This costs the memory and time to build the list, which is why the iter() solution is so elegant.
def four_x_args(*args):
argsList = list(args) # convert from tuple to list
output = argsList.pop(0) * 4
for arg in argsList:
output += arg * 4
return output
This is just Wooble's solution, rewritten to use *args.
Examples of calling it:
print four_x_args(1) # prints 4
print four_x_args(1, 2) # prints 12
print four_x_args('a') # prints 'aaaa'
print four_x_args('ab', 'c') # prints 'ababababcccc'
Finally, I'm going to be malicious and complain about the solution you accepted. That solution depends on the object's base class having a sensible null or zero, but not all classes have this. int() returns 0, and str() returns '' (null string), so they work. But how about this:
class NaturalNumber(int):
"""
Exactly like an int, but only values >= 1 are possible.
"""
def __new__(cls, initial_value=1):
try:
n = int(initial_value)
if n < 1:
raise ValueError
except ValueError:
raise ValueError, "NaturalNumber() initial value must be an int() >= 1"
return super(NaturalNumber, cls).__new__ (cls, n)
argList = [NaturalNumber(n) for n in xrange(1, 4)]
print theFinalAndTrulyRealProblemAsPosed(argList) # prints correct answer: 24
print NaturalNumber() # prints 1
print type(argList[0])() # prints 1, same as previous line
print multiplyItemsByFour(argList) # prints 25!
Good luck in your studies, and I hope you enjoy Python as much as I do.