Python Tricks - Basic - Part 1
Feb 26, 2020 • 11 Minute Read
Introduction
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
Boolean Expressions
a or b
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).
a, b = 0, 42
a or b
# output: 42
a, b = '', 0
a or b
# output: 0
Inspiring Example
In a linked list assignment, if at most one of the two candidate nodes is not None, we can use or expression.
"""connect with a non-empty linked list"""
cur.next = l1 or l2
a and b
If a is the falsy value, return a. Otherwise, return b.
a, b = 1, 2
a and b
# output: 2
a, b = '', 'abc'
a and b
# output: ''
Inspiring Example
We can use this mechanism to call a function before assignment. Just make sure that the left expression is always True.
"""add current element to list before assignment"""
last = not arr.append(x) and arr[-1]
Extended Knowledge: Lazy Evaluation
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 - Part 2 guide.
We will further discuss the lazy evaluation technique applied to the generator in the Python Tricks - Iterable guide.
Build Tuple
Construct a temporary tuple for a specific purpose. Trade memory for more concise code. This can be extended to build other collection types.
Inspiring Examples
"""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):
Value of Boolean
bool type is a subclass of int. As an integer, the value of True is 1 and False is 0.
int(True), int(False)
# output: (1, 0)
We can use bool to participate in operations.
Inspiring Examples
Used in sum: count the number of satisfied conditions.
"""used in sum"""
equal_count = sum(a == b for a, b in zip(arr1, arr2))
Used as an index: construct a temporary tuple and use bool expression as an index.
# 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
Used in list initialization and slice:
# 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
Ternary Operator
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.
Built-in Grammar
This is the most direct way, which is supported since version 2.5. The expression syntax is:
"""conditional operator"""
true_expression if condition else false_expression
Inspiring Examples
We can use the ternary operator to find min/max element in pairs or triplets. The alternative is to use the min/max function.
"""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
Boolean Expression Technique
For versions prior to 2.5, we can use the boolean expression trick that we discussed before:
"""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
However, this method may create poor readability for some and be slower than before.
Boolean Index Technique
This solution uses value of boolean and build tuple tricks.
"""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)]()
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.
Pack with Boolean Index
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.
"""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
Chained Operations
Chained operations make the code more concise and reduce the possibility of errors.
Chained Assignment
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.
x = y = f()
is equivalent to
temp = f()
x = temp # assign from left to right
y = temp
They all have the same values when assigning a mutable value.
import random
x = y = random.random()
x == y
# output: True
x = random.random()
y = random.random()
x == y
# output: False
Inspiring Example
A typical use case is for initialization, such as the initialization of a linked list.
"""initialize dummy node and assign to cur"""
dummy = ListNode(0)
cur = dummy.next = head
Chained Comparison
Chained Comparison is a nice syntactic sugar in Python to simplify expressions.
a = b = 1
a == b == 1
# output: True
a == b != 2
# output: True
0 <= a < 4
# output True
Inspiring Examples
"""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])
Conclusion
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:
- Python Tricks - Introduction
- Python Tricks - Basic - Part 1
- Python Tricks - Basic - Part 2
- Python Tricks - Iterable - Part 1
- Python Tricks - Iterable - Part 2
- Python Tricks - Black Magic - Part 1
- Python Tricks - Black Magic - Part 2
I hope you enjoyed it. If you have any questions, you're welcome to contact me at recnac@foxmail.com.