While playing around with pyautogui
I decided to make a method to limit the position of my cursor depending on the size of my monitor, since I was moving my cursor randomy.
This is what my first attempt looked like.
max_x = 10
max_y = 40
def limitXandY(x_arg, y_arg):
# expected to outputs a tuple of integers with length 2
return x_arg, y_arg if x_arg < max_x and y_arg < max_y else max_x, max_y
When running the code I did not get the expected output.
print(limitXandY(5, 19)) # (5, 19, 40) => (x_arg, y_arg, max_y)
x, y = limitXandY(5, 19) # ValueError: too many values to unpack (expected 2)
print(limitXandY(50, 100)) # (50, 10, 40) => (x_arg, max_x, max_y)
x, y = limitXandY(50, 100) # ValueError: too many values to unpack (expected 2)
As you can see above, my method returns a tuple of length 3 instead of 2. If the ternary operator goes in the if statement, I get the desired output plus last value of the else statement and if the operator returns in the else statement, I get the first value of the if statement as the first value of the methods output tuple.
I have found a work around using parentheses, but this doesn't really satisfy me and I would like to understand why this ternary operator acts like this.
def correctedLimitXandY(x_arg, y_arg):
# expected to output a tuple of tuple with length 1
# inner tuple should containt integers of length 2
return (x_arg, y_arg) if x_arg < max_x and y_arg < max_y else (max_x, max_y)
print(correctedLimitXandY(5, 19)) # (5, 19) => (x_arg, y_arg)
x, y = correctedLimitXandY(5, 19) # no error
print(correctedLimitXandY(50, 100)) # (10, 40) => (max_x, max_y)
x, y = correctedLimitXandY(50, 100) # no error
Any explanations would be a help!
Any explanations would be a help!
While ternaries have a fairly low precedence, they're still considered an operator and thus binding "tighter" than tuple literal, much like e.g.
a+b,c+d
is interpreted as
(a + b), (c + d)
not
a + (b, c) + d
When you write
x_arg, y_arg if x_arg < max_x and y_arg < max_y else max_x, max_y
Python will first "resolve" <
, then and
, then if/else
, and only after that does it resolve the tuples, so the result is:
x_arg, (y_arg if ((x_arg < max_x) and (y_arg < max_y)) else max_x), max_y
You can infer this from the full language grammar, specifically:
expressions:
| expression (',' expression )+ [',']
| expression ','
| expression
expression:
| disjunction 'if' disjunction 'else' expression
| disjunction
| lambdef
Here you can see that an expressions
is a comma-separated sequence of expression
, and each expression
can be a ternary (if/else
), therefore the language "resolves" ternaries (the inner structure) first.