I don’t really know what I am going to do on this page. But I have some notes about the Python standard library that I want to save for my future self.

.islower() (and .isupper())

Return True if all cased characters in the string are lowercase and there is at least one cased character, False otherwise.

Cased characters are those with the Unicode general category property being one of “Lu” (Letter, uppercase), “Ll” (Letter, lowercase), or “Lt” (Letter, titlecase). This means that the method checks for characters that are specifically recognized as letters in their uppercase, lowercase, or titlecase forms.

print('a'.islower())   # True
print('A'.islower())   # False
print('1'.islower())   # False
print('a1'.islower())  # True
print('á'.islower())   # True
print('Á'.islower())   # False
print(''.islower())  # False  # Chinese character, not cased
print('ß'.islower())   # True  # German sharp s, considered lowercase

See more:

Dictionary Ordering

As of Python 3.6 in CPython and 3.7 in all implementations , dictionaries are iterated in the insertion order of keys.

d = {}

d[1] = True
d[2] = True
d[3] = True

print(d)  # {1: True, 2: True, 3: True}

d[2] = False
print(d)  # {1: True, 2: False, 3: True}

del d[2]
d[2] = True
print(d)  # {1: True, 3: True, 2: True}

OrderedDict

OrderedDict can be used if you want to explicitly state the importance of the order or if you want to use methods like .move_to_end() or .popitem().

See more:

Default Value for max() (and min())

If max() is given an sequence, it will raise a ValueError. As of Python 3.4, the max() function supports a default parameter, which is returned if the provided sequence is empty.

This is helpful when dealing with sequences of unknown length that could be empty.

print(max([], default=0))  # 0

See more:

Get Python Version

import sys

print(sys.version)  # '3.9.6 (default, Jul 27 2021, 07:03:06) [GCC 8.3.0]'

See more:

dict.get()

The dict.get() method is a safe way to retrieve values from a dictionary without raising a KeyError if the key doesn’t exist.

dict.get(key, default=None)

This method returns the value for key if key is in the dictionary, else default. If default is not given, it defaults to None, so that this method never raises a KeyError.

d = {'a': 1, 'b': 2}

print(d.get('a'))      # 1
print(d.get('c'))      # None
print(d.get('c', 0))   # 0

# Contrast with direct key access:
print(d['a'])          # 1
# print(d['c'])        # Raises KeyError

Useful when you want to handle missing keys without using a try-except block.

See more:

itertools.islice()

itertools.islice() returns an iterator with selected elements using sequence slicing.

itertools.islice(iterable, stop)
itertools.islice(iterable, start, stop[, step])

The step argument must be positive, as iterators can be infinite.

print(list(itertools.islice(range(10), 2, 8, 2)))  # [2, 4, 6]

See more:

Walrus Operator (:=)

The walrus operator (:=), introduced in Python 3.8, allows assignment in expressions.

# Assume expensive_function() is costly to compute
if (result := expensive_function()) > 100:
    print(f"Result {result} is large")
else:
    print(f"Result {result} is small")

Parentheses are sometimes required around the assignment expression, depending on context:

# Parentheses required here
if (n := len(a)) > 10:
    print(f"List is too long ({n} elements, expected <= 10)")

# Parentheses not required here
while chunk := file.read(8192):
    process(chunk)

See more:

Pinning Dependencies in Pipfile

Latest Version

[packages]
requests = "*"
beautifulsoup4 = "*"

Pin Specific Versions

[packages]
requests = "==2.25.1"
beautifulsoup4 = "4.12.3"

Pin in GitHub Dependabot

version: 2
updates:
  - package-ecosystem: "pip"
    directory: "/"
    schedule:
      interval: "daily"
    ignore:
      - dependency-name: "requests"
      - dependency-name: "beautifulsoup4"

Timsort Space Complexity

Timsort sort has space complexity of O(N):

Timsort can require a temp array containing as many as N//2 pointers, which means as many as 2*N extra bytes on 32-bit boxes. It can be expected to require a temp array this large when sorting random data; on data with significant structure, it may get away without using any extra heap memory. This appears to be the strongest argument against it, but compared to the size of an object, 2 temp bytes worst-case (also expected- case for random data) doesn’t scare me much.

Source: Python/cpython - Objects/listsort.txt

Range

range(stop)
range(start, stop[, step])
  • start defaults to 0 if omitted.
  • step defaults to 1 if omitted.
  • step can be negative, creating a descending sequence.

Features and Operations

  • Indexing: r[i]
  • Length: len(r)
  • Containment: x in r
  • Iteration: Supports i in r and reversed(r)
  • index(value): Returns index of value. Very efficient.
  • count(value): Returns occurrences of value.
  • Comparable: Supports == and != (Note: <, <=, >, >= are not supported)

Examples

r = range(0, 10, 2)
print(list(r))         # [0, 2, 4, 6, 8]
print(r[2])            # 4
print(6 in r)          # True
print(r.index(6))      # 3
print(len(r))          # 5

# Negative step
r_neg = range(10, 0, -2)
print(list(r_neg))     # [10, 8, 6, 4, 2]

# Reverse iteration
print(list(reversed(r)))  # [8, 6, 4, 2, 0]

As of 3.2: Implement the Sequence ABC. Support slicing and negative indices. Test int objects for membership in constant time instead of iterating through all items.

As of 3.3: Define ‘==’ and ‘!=’ to compare range objects based on the sequence of values they define (instead of comparing based on object identity).