Basically my title is the question:
Example:
>>> l=[1,2,3]
>>> *l
SyntaxError: can't use starred expression here
>>> print(*l)
1 2 3
>>>
Why is that???
because it's equivalent to positional arugments corspondent to the list, so when your not calling it somewhere that can take all the arguments, it makes no sense, since there are nowhere to put the arguments
f.x.
print(*[1,2,3])
# is the same as
print(1,2,3)
and
*[1,2,3]
#is the same as - and do not think of it as a tuple
1,2,3 # here how ever that makes it a tuple since tuples not defined by the parenthasies, but the point is the same
there is however a slight exception to this which is in tuple, list, set and dictionaries as of python 3.5 but that is an exception, and can also be used to assign left over values, how ever python can see your doing non of these.
EDIT
I undeleted my answer since i realised only the last part was wrong.
I think this is actually a question about understanding *l or generally *ListLikeObject.
The critical point is *ListLikeObject is not a valid expression individually. It doesn't mean "Oh please unpack the list".
An example can be 2 *[1, 2, 3](As we all know, it will output [1, 2, 3, 1, 2, 3]). If an individual *[1, 2, 3] is valid, what should it output? Should it raise a runtime exception as the evaluated expression is 2 1 2 3 and it is invalid(Somehow like divided by 0)?
So basically, *[1, 2, 3] is just a syntax sugar that helps you to pass arguments. You don't need to manually unpack the list but the interpreter will do it for you. But essentially it is still passing three arguments instead of one tuple of something else.
Related
I came across this particular piece of code in one of "beginner" tutorials for Python. It doesn't make logical sense, if someone can explain it to me I'd appreciate it.
print(list(map(max, [4,3,7], [1,9,2])))
I thought it would print [4,9] (by running max() on each of the provided lists and then printing max value in each list). Instead it prints [4,9,7]. Why three numbers?
You're thinking of
print(list(map(max, [[4,3,7], [1,9,2]])))
# ^ ^
providing one sequence to map, whose elements are [4,3,7] and [1,9,2].
The code you've posted:
print(list(map(max, [4,3,7], [1,9,2])))
provides [4,3,7] and [1,9,2] as separate arguments to map. When map receives multiple sequences, it iterates over those sequences in parallel and passes corresponding elements as separate arguments to the mapped function, which is max.
Instead of calling
max([4, 3, 7])
max([1, 9, 2])
it calls
max(4, 1)
max(3, 9)
max(7, 2)
map() takes each element in turn from all sequences passed as the second and subsequent arguments. Therefore the code is equivalent to:
print([max(4, 1), max(3, 9), max(7, 2)])
It looks like this question has been answered already, but I'd like to note that map() is considered obsolete in python, with list comprehensions being used instead as they are usually more performant. Your code would be equivalent to print([max(x) for x in [(4,1),(3,9),(7,2)]]).
Also, here is an interesting article from Guido on the subject.
Most have answered OPs question as to why,
Here's how to get that output using max:
a = [4,3,7]
b = [1,9,2]
print(list(map(max, [a, b])))
gives
[7, 9]
This question already has answers here:
Why does adding a trailing comma after an expression create a tuple?
(6 answers)
Closed 6 months ago.
I had introduced a bug in a script of mine by putting a comma after a function call. Here I will illustrate with a silly example:
def uppered(my_string):
return my_string.upper()
foo = uppered("foo")
print(foo)
This returns, as expected, a string:
FOO
However, if I change the script so that I call the function with a comma appended after the function call, like this:
foo = uppered("foo"),
Then I get a tuple back (!):
('FOO',)
This seems so weird to me - I would have expected the interpreter to return a SyntaxError (as it does if I have two commas instead of one). Can someone please enlighten me what the logic is here and where to find more information on this behavior. My google-fu let me down on this very specific detail.
Because you have created a tuple.
foo = uppered("foo"),
Is equivalent to:
foo = (uppered("foo"),)
Which creates a single-elemnt tuple, obviously equivalent to
foo = ('FOO',)
Tuples in Python can be written as:
my_tuple = ()
or:
my_tuple = (1, 2)
or:
my_tuple = 1, 2
Don't believe me? Well:
>>> my_tuple = 1,
>>> my_tuple
(1,)
Well, it's how Python syntax works. A single comma after a value will turn create a tuple with this value as the first and only element. See answers for this question for a broader discussion.
Imagine there is an omitted pair of parentheses:
foo = (uppered("foo"),)
Why so? It to write like this:
stuff = foo(), bar(), baz()
# More code here
for thing in stuff:
You could've used a pair of parentheses (and you do need them in other languages), but aesthetics of Python require syntax to be as short and clear as possible. Commas are necessary as separators, but parentheses really aren't. Everything between the beginning side of expression and the end of the line (or :, or closing parentheses/brackets in case of generators or comprehensions) is to be elements of the created tuple. For one element tuple, this syntax should be read as "a tuple of this thing and nothing more", because there is nothing between comma and end of the line.
You can use .join() function. It returns string concatenated with
elements of tuple.
g = tuple('FOO')
k = ''
K = k.join(g)
print(K)
print(type(K))
FOO
class 'str'
This questions stems from PEP 448 -- Additional Unpacking Generalizations and is present in Python 3.5 as far as I'm aware (and not back-ported to 2.x). Specifically, in the section Disadvantages, the following is noted:
Whilst *elements, = iterable causes elements to be a list,
elements = *iterable, causes elements to be a tuple. The reason for this may confuse people unfamiliar with the construct.
Which does indeed hold, for iterable = [1, 2, 3, 4], the first case yields a list:
>>> *elements, = iterable
>>> elements
[1, 2, 3, 4]
While for the second case a tuple is created:
>>> elements = *iterable,
>>> elements
(1, 2, 3, 4)
Being unfamiliar with the concept, I am confused. Can anyone explain this behavior? Does the starred expression act differently depending on the side it is on?
The difference between these two cases are explained when also taking into consideration the initial PEP for extended unpacking: PEP 3132 -- Extended iterable unpacking.
In the Abstract for that PEP we can see that:
This PEP proposes a change to iterable unpacking syntax, allowing to specify a "catch-all" name which will be assigned a list of all items not assigned to a "regular" name.
(emphasis mine)
So in the first case, after executing:
*elements, = iterable
elements is always going to be a list containing all the items in the iterable.
Even though it seems similar in both cases, the * in this case (left-side) means: catch everything that isn't assigned to a name and assign it to the starred expression. It works in a similar fashion as *args and **kwargs do in function definitions.
def spam(*args, **kwargs):
""" args and kwargs group positional and keywords respectively """
The second case (right-side) is somewhat different. Here we don't have the * working in a "catch everything" way as much as we have it working as it usually does in function calls. It expands the contents of the iterable it is attached to. So, the statement:
elements = *iterable,
can be viewed as:
elements = 1, 2, 3, 4,
which is another way for a tuple to be initialized.
Do note, a list can be created by simple using elements = [*iterable] which will unpack the contents of iterable in [] and result in an assignments of the form elements = [1, 2, 3, 4].
I want to write my own sum function to get the sum of a variable-length argument.
def myadd(*tuple):
sum=0
for element in tuple:
sum=sum+element
return(sum)
call method 1:
myadd(*(1,2,3,4))
It is the most formal way to call the function.no problem here.
call method 2:
myadd(1,2,3,4)
It also can get the result,why?
call method 3:
myadd((1,2,3,4))
error TypeError: unsupported operand type(s) for +: 'int' and 'tuple'.
In my point of view,call 2 and call 3 can not be accepted by python,there are no * operator in the position of arguments?can you tell me the pricinple of the operation on python function ?
You're mixing up variable-argument parameters and argument unpacking. This is a common mistake for beginners, because they both use the same * for syntax, and they're not completely unrelated… but they're not nearly as closely related as you think.
These two calls do the exact same thing:
myadd(*(1,2,3,4))
myadd(1, 2, 3, 4)
What the * means here is "take the following iterable, and unpack it into a bunch of separate arguments.
It doesn't matter whether the function you're calling was defined as f(*args), f(a, b, c, d), or f(a, b, *args), you're passing it 4 arguments.
This means method 1 is not "the most formal way to call the function"; in fact, it's just an obfuscated version of method 2.
This, on the other hand, does not do the same thing:
myadd((1, 2, 3, 4))
That passes a single argument, which happens to be a tuple.
So, your function is defined like this:
def myadd(*tuple):
This means whatever it arguments it's passed, no matter how they're passed (except for keyword arguments, but let's ignore that for the moment), they're going to be tossed into a list named tuple. So, let's look at your three cases.
In the first case, you're passing 4 arguments, all of which are integers. So, tuple gets a list of 4 integers. When you iterate over that list, each member is an integer, so you can add them up with no problem.
In the second case—which, again, is exactly the same—you're passing 4 integers, so tuple gets a list of 4 integers.
In the third case, you're passing 1 argument, which is a tuple, so tuple gets a list of 1 tuple. When you iterate over that list, each member is a tuple, and you can't add that to a number.
For more details, see Arguments and parameters, which has links to all the useful places to look in the docs, and hopefully a readable overview.
You are passing the whole tuple as one argument, and tuples cannot be added to numbers. If you want to pass all the tuple elements as individual arguments, use the * operator:
myadd(*x)
def myadd(x):
sum=0
for element in x:
sum=sum+element
return(sum)
x=(1,2,3)
print myadd(x)
output
6
The assignment:
Write a function called splitList(myList, option) that takes, as input, a list and an option, which is either 0 or 1. If the value of the option is 0, the function returns a list consisting of the elements in myList that are negative, and if the value of the option is 1, the function returns a list consisting of the elements in myList that are even.
I know how to determine if a number is even and if a number is negative. I'm struggling with how to return a new list of negative or even numbers based on "option"
This is what I've gotten so far:
def splitList(myList):
newlist = []
for i in range(len(myList)):
if (myList[i]%2 == 0):
newlist.append(myList [i])
return newlist
This program gives the following error:
Traceback (most recent call last): File "<string>", line 1, in <fragment>
builtins.TypeError: splitList() takes exactly 1 positional argument (4 given)
As I mentioned in my comment, you should standardize your indentation: four spaces is Python standard. You can usually set your editor to insert four spaces instead of tabs (don't want to mix tabs with spaces, either).
As to your actual question: try writing three total functions: one that returns all the negative values, one that returns even values, and one that calls the appropriate function based on option.
def splitlist(myList, option):
if option == 1:
return get_even_elements(myList)
elif option == 0:
return get_negative_elements(myList)
def get_even_elements(myList):
pass # Implementation this method here.
def get_negative_elements(myList):
pass # Implementation this method here.
# Test it out!
alist = [-1, 2, -8, 5]
print splitlist(alist, 0)
print splitlist(alist, 1)
Henry Keiter's comment was correct. Just add one space before newlist.append(myList [i]) and it works just fine.
Alternatively, if your teacher lets you, you could use tabs instead of spaces to avoid this problem altogether (just make sure you don't use both in the same file).
def splitList(myList, option):
return [i for i in myList if i<0] if option==0 else [i for i in myList if i>0]
# test
>>> myList=[2, 3, -1, 4, -7]
>>> splitList(myList, 0)
[-1, -7]
>>> splitList(myList, 1)
[2, 3, 4]
>>>
I tried your code as-is and I did not get any errors when I passed in a list of positive integers, so I don't know why your program is 'crashing', so I suspect something else is interfering with your debugging. (Although, as others have said, you really should use the same number of spaces at every indent level.)
Here's what I entered:
def splitList(myList):
newlist = []
for i in range(len(myList)):
if (myList[i]%2 == 0):
newlist.append(myList [i]) # Only 3-space indent here
return newlist
print splitList([1, 2, 3, 4, 5])
When I run it:
[2, 4]
Can you show how you're invoking the method and the exact error message?
My previous answer was incorrect, and I really should have tested before I opened my mouth... Doh!!! Live and learn...
edit
your traceback is giving you the answer. It is reading the list as an args list. Not sure if there is a super pythonic way to get around it, but you can use named arguments:
splitList(myList=yourList)
OR
splitList(myList=(1,2,3))
OR
splitList(myList=[1,2,3])
But your problem is really probably
splitList(1,2,3,4) # This is not a list as an argument, it is a list literal as your 'args' list
Which can be solved with:
splitList([1,2,3,4])
OR
splitList((1,2,3,4))
Is this the traceback you get?
Traceback (most recent call last):
File "pyTest.py", line 10, in <module>
print splitList(aList,1)
TypeError: splitList() takes exactly 1 argument (2 given)
The error is most likely telling you the issue, this would be that the method only takes one argument, but I tried passing in two arguments like your requirements state.
edit
Can you show the code where you are calling the splitList method?
this was incorrect
myList [i]
is your problem, you can't have a space in there. python is VERY VERY VERY strict about syntax
since people seemed to think they should downvote me, let me explain:
by having that space, you effectively said myList (which is a list), and [i], which is a list literal with the value of 'i' at index 0....
so you are passing two variables (one actual variable and one literal) into the append method, NOT separated by a comma, which will not work.