Introduction

12

*Editor's note: This guide is part of a series on useful Python tricks. Read more about the series and find links the other guides here.*

In this guide, we will learn some basic tricks in Python, including the most common advanced Python tricks. Each Python trick is explained in two steps:

- A brief description of the concept and an interactive code example
- Some inspiring examples to enlighten you

If `a`

is the truthy value, return `a`

. Otherwise, return `b`

.

Here is the *falsy values* list from the official document:

- Constants defined to be false:
`None`

and`False`

. - Zero of any numeric type:
`0`

,`0.0`

,`0j`

,`Decimal(0)`

,`Fraction(0, 1)`

. - Empty sequences and collections:
`''`

,`()`

,`[]`

,`{}`

,`set()`

,`range(0)`

.

`1 2 3 4 5 6 7`

`a, b = 0, 42 a or b # output: 42 a, b = '', 0 a or b # output: 0`

python

In a linked list assignment, if at most one of the two candidate nodes is not `None`

, we can use `or`

expression.

`1 2`

`"""connect with a non-empty linked list""" cur.next = l1 or l2`

python

If `a`

is the falsy value, return `a`

. Otherwise, return `b`

.

`1 2 3 4 5 6 7`

`a, b = 1, 2 a and b # output: 2 a, b = '', 'abc' a and b # output: ''`

python

We can use this mechanism to call a function before assignment. Just make sure that the left expression is always `True`

.

`1 2`

`"""add current element to list before assignment""" last = not arr.append(x) and arr[-1]`

python

*Lazy evaluation* is an evaluation strategy that delays the evaluation of an expression until its value is needed.

Here we talk about the lazy evaluation mechanism applied to expression, such as `a or b`

, `a and b`

, `a if condition else b`

. Once the statement is satisfied, the rest of the expression will be skipped. Specific to the following examples, expression `b`

will *not be executed*. We can use this mechanism to do *conditional execution* in an expression. See more information in the "list comprehension with break" example of the Python Tricks - Black Magic guide.

We will further discuss the lazy evaluation technique applied to the **generator** in the Python Tricks - Iterable guide.

Construct a temporary tuple for a specific purpose. Trade memory for more concise code. This can be extended to build other collection types.

`1 2 3 4 5 6 7 8`

`"""build in condition""" if elem in (elem1, elem2): # equals to: if elem == elem1 or elem == elem2 """build result""" return [dp[-1], -1][dp[-1] == float('inf')] # equals to if-else, but more concise """build 4-neighbors as range""" for I, J in (i + 1, j), (i - 1, j), (i, j + 1), (i, j - 1):`

python

`bool`

type is a subclass of `int`

. As an integer, the value of `True`

is 1 and `False`

is 0.

`1 2`

`int(True), int(False) # output: (1, 0)`

python

We can use `bool`

to participate in operations.

Used in `sum`

: count the number of satisfied conditions.

`1 2`

`"""used in sum""" equal_count = sum(a == b for a, b in zip(arr1, arr2))`

python

Used as an index: construct a temporary tuple and use `bool`

expression as an index.

`1 2 3 4 5 6`

`# L236: find the lowest common ancestor in the binary search tree def lowest_common_ancestor(root: TreeNode, p: TreeNode, q: TreeNode) -> TreeNode: while (root.val - p.val) * (root.val - q.val) > 0: """used as index""" root = (root.left, root.right)[p.val > root.val] # equals to if-else, seems more clearly this way return root`

python

Used in list initialization and slice:

`1 2 3 4 5 6 7 8 9 10 11 12`

`# a strobogrammatic number is a number that looks the same when rotated 180 degrees (looked at upside down) # L247: find all strobogrammatic numbers that are of length = n def find_strobogrammatic(n: int) -> List[str]: """used in list initialization""" # if nums is odd, the middle digit must be in '018' nums = n % 2 * list('018') or [''] while n > 1: n -= 2 """used in slice""" # here use to deal with number can not start with '0' nums = [a + num + b for a, b in '00 11 88 69 96'.split()[n < 2:] for num in nums] return nums`

python

In C++ / Java, you can achieve this with the built-in grammar `condition ? true_expression : false_expression`

. Python has several of its own ways to achieve this. A variety of solutions provide different ideas.

This section is summarized from Does Python have a ternary conditional operator? and Best way to do ternary conditionals in Python < 2.5 on Stack Overflow. Refer to them if you need.

This is the most direct way, which is supported since version 2.5. The expression syntax is:

`1 2`

`"""conditional operator""" true_expression if condition else false_expression`

python

We can use the ternary operator to find min/max element in pairs or triplets. The alternative is to use the `min`

/`max`

function.

`1 2 3 4 5 6 7 8 9`

`"""find maximum in pairs""" a, b = 10, 20 max_val = a if a > b else b # output: 20 """find mininmum in triplets""" a, b, c = 10, 20, 5 min_val = a if a < b and a < c else (b if b < c else c) # output: 5`

python

For versions prior to 2.5, we can use the *boolean expression* trick that we discussed before:

`1 2 3 4 5 6 7`

`"""correct way by encapsulation with tuples""" """(False,) is truthy value""" (condition and (true_expression,) or (false_expression,))[0] """more concise and faster way with limit""" """should make sure true_expression is never falsy""" condition and true_expression or false_expression`

python

However, this method may create poor readability for some and be slower than before.

This solution uses *value of boolean* and *build tuple* tricks.

`1 2 3 4 5 6 7 8 9`

`"""tuple index""" """for safety we explicitly test for truthiness by bool()""" (false_expression, true_expression)[bool(condition)] """dict index""" {True: true_expression, False: false_expression}[bool(condition)] """lambda version supports lazy evaluation""" (lambda: false_expression, lambda: true_expression)[bool(condition)]()`

python

Note that the first two solutions always evaluate everything, whereas the if/else construct obeys lazy evaluation. They are not equal in the strict sense. The third one uses the `lambda`

technique to solve this problem.

Here is an elegant Pythonic solution. It is packed as a function based on the *boolean index technique* solution. It looks pretty clean and easy to read for the caller.

`1 2 3 4 5 6 7 8 9 10 11 12 13 14 15`

`"""pack as function""" """not not x equals to bool(x)""" def _if(condition): return lambda false_expression: lambda true_expression: \ [delay(true_expression), delay(false_expression)][not not condition]() """unified as callable""" def delay(f): if callable(f): return f else: return lambda: f # example a, b = 10, 20 min_val = _if(a < b) (a) (b) # output: 10`

python

Chained operations make the code more concise and reduce the possibility of errors.

In Python, assignment statements are not expressions and thus do not have a value. Instead, chained assignments are a series of statements with multiple targets for a single expression. The assignments are executed left-to-right.

`1`

`x = y = f()`

python

is equivalent to

`1 2 3`

`temp = f() x = temp # assign from left to right y = temp`

python

They all have the same values when assigning a mutable value.

`1 2 3 4 5 6 7 8 9`

`import random x = y = random.random() x == y # output: True x = random.random() y = random.random() x == y # output: False`

python

A typical use case is for initialization, such as the initialization of a linked list.

`1 2 3`

`"""initialize dummy node and assign to cur""" dummy = ListNode(0) cur = dummy.next = head`

python

Chained Comparison is a nice syntactic sugar in Python to simplify expressions.

`1 2 3 4 5 6 7 8 9 10`

`a = b = 1 a == b == 1 # output: True a == b != 2 # output: True 0 <= a < 4 # output True`

python

`1 2 3 4 5 6 7 8 9 10 11 12 13 14 15`

`"""short for a > 0 and b >= 0""" if a > 0 <= b: """chained comparison in binary search""" if nums[lo] < target < nums[mid]: hi = mid - 1 """check matrix boundary in a unified way""" for i in range(len(matrix)): for j in range(len(matrix[0])): # construct neighbor tuple for I, J in (i + 1, j), (i - 1, j), (i, j + 1), (i, j - 1): # although add some unnecessary checks, expression is more concise if 0 <= I < len(matrix) and 0 <= J < len(matrix[0]): process_neighbor_logic(matrix[I][J])`

python

In this guide, we have learned many basic Python tricks, such as advanced boolean usages, build tuple, ternary operator, and chained operator. I hope some of them will be useful for you.

In Python Tricks - Basic - Part 2, we will continue to learn about other basic Python tricks.

You can also download an example notebook, basic.ipynb, from Github.

This guide is one of a series of Python tricks guides:

I hope you enjoyed it. If you have any questions, you're welcome to contact me at [email protected]

12