Skip to content

Contact sales

By filling out this form and clicking submit, you acknowledge our privacy policy.

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:

  1. A brief description of the concept and an interactive code example
  2. 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:

I hope you enjoyed it. If you have any questions, you're welcome to contact me at recnac@foxmail.com.