简体   繁体   中英

Ternary operator in Python raises TypeError when using * operator on empty list?

I want to print the contents of a list a if len(a) > 0 , but otherwise I want to print -1 . This seems to be pretty simple, but it's raising a TypeError , stating that a is an int, not a sequence, only when a is an empty list:

>>> a = [2]
>>> print(*a if len(a) > 0 else -1)
2 # as expected
>>> a = []
>>> print(*a)

>>> # It has no trouble evaluating *a when a is empty
... ### HERE IS THE ERROR:
...
>>> print(*a if len(a) > 0 else -1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: print() argument after * must be a sequence, not int
>>> ### But this works fine:
...
>>> if len(a) > 0:
...     print(*a)
... else:
...     print(-1)
...
-1

Why is this the case?

According to the Python Documentation :

The expression x if C else y first evaluates the condition, C rather than x . If C is true, x is evaluated and its value is returned; otherwise, y is evaluated and its value is returned.

So *a shouldn't be getting evaluated at all, and yet it's causing a TypeError?

I'm using Python 3.5

I'm not an expert, but looking at PEP 448 it looks like this * syntax isn't part of the general expression syntax, but it's specific to function callsites (and other things like tuple and dictionary displays). (It's a bit of a hack.)

The PEP explicitly calls out some similar syntax that they've forbidden because they didn't know what it should do. It doesn't look like your code has been particularly considered though.

Unbracketed comprehensions in function calls, such as f(x for x in it), are already valid. These could be extended to:

f(*x for x in it) == f((*x for x in it))

f(**x for x in it) == f({**x for x in it})

However, it wasn't clear if this was the best behaviour or if it should unpack into the arguments of the call to f. Since this is likely to be confusing and is of only very marginal utility, it is not included in this PEP. Instead, these will throw a SyntaxError and comprehensions with explicit brackets should be used instead.

I think your code is effectively parsing as print(*(a if len(a) > 0 else -1)) , which is why you then get the error TypeError: print() argument after * must be a sequence, not int . By comparison, this works:

>>> print(*a if len(a) > 0 else ['nothing'])
nothing

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM