[Python tricks] 5 minor but useful Python tricks

I would like to introduce a Python coding technique that I haven't seen much. I'm sorry if it was unexpectedly major. I would like to include as much sample code as possible to show how it actually works. Since it summarizes niche technologies, it is assumed that you can write Python to some extent.

functools.partial You can use this to ** create a function with fixed arguments ** for a function. I think it's faster to look at the code.

import functools

def add(x, y):
    return x + y

add_fixed_y = functools.partial(add, y=5)
print(add_fixed_y(2)) # 7

I don't know what this alone will be useful for, so I would like to introduce my own usage. I use it for the ** ʻopen` function ** of the file.

open_utf_8 = functools.partial(open, encoding="utf-8")
r_open_utf_8 = functools.partial(open_utf_8, mode="r")
w_open_utf_8 = functools.partial(open_utf_8, mode="w")

with w_open_utf_8("something_great.txt") as wf:
    wf.write("Hello World!")

By doing this, you can reduce the constants from within the code and prevent typographical errors in the ʻencoding` part.

next and generator

The expressions inside the list comprehension can be used for generator expressions, and creating generator objects has been introduced in other articles.

gen = (i ** 2 for i in range(10))
print(gen) # <generator object <genexpr> at 0x~~>

How is this useful in actual coding? I use it to find the first index ** that meets the ** criteria. It is used for the process of ** rounding the character string to the specified number of bytes or less **.

from itertools import accumulate

def str_clamp_bytes(value: str, max_bytes: int) -> str:
    byte_count = (len(s.encode("utf-8")) for s in value)
    try:
        end_slice = next(i for i, v in enumerate(accumulate(byte_count)) if v > max_bytes)
    except StopIteration:
        return value
    return value[:end_slice]

(i for i, v in enumerate (accumulate (byte_count)) if v> max_bytes) is the generator and ʻif v> max_bytes is the conditional expression. ʻEnd_slice is assigned the first index that satisfies v> max_bytes. If there is no index that meets the conditions, a StopIteration exception will occur, so catch it and return the original string. The generator is sufficient because byte_count is only used for ʻaccumulate`.

Global variable __debug__

This variable becomes False when the -O (not zero) option is added at startup. If you add the -O option, the ʻassert` statement becomes invalid and you can speed up the program, so you can add it in the product version without any problem. I use it for the process of ** delivering only the product version **.

def broadcast_debug():
    pass

def broadcast_prod():
    pass

(broadcast_debug if __debug__ else broadcast_prod)()

lru_cache decorator

By remembering the function argument / return value pair in the dictionary, if the argument was passed before, the previous return value will be returned without processing.

from functools import lru_cache

@lru_cache
def fib(n):
    if n < 2:
        return n
    return fib(n - 1) + fib(n - 2)

print(fib(10))

Since it is a dictionary, the access speed is inferior to pure memoization, but the ease of use is great. After that, it can be handled even if ** character strings etc. are used as arguments **, which cannot be handled by memoization.

inspect.getmembers You can ** get all members from the module **. You can specify the member type with the second argument.

import inspect
import copy

print(inspect.getmembers(copy, inspect.isclass))
# >> [('Error', <class 'copy.Error'>), ('error', <class 'copy.Error'>)]

** You can extract all the classes from the module **, so you can get them all at once without the hassle of loaded_classes = [class_A, class_B, ...]. And you don't have to worry about forgetting to add it. The class object has a __bases__ member, and all the inherited class objects are included as tuples, so I think you can use this area to filter.

Finally

I introduced a trick that I think is "convenient but I don't see much". Please let me know if you have any typos or mistakes.

Recommended Posts

[Python tricks] 5 minor but useful Python tricks
[Python] Pre-processing tricks
[Python] Super useful debugging
3 Jupyter notebook (Python) tricks
python useful memo links
Python is painful. But use
Useful tricks related to list and for statements in Python
Install Python 3.7 Anaconda on MAC, but Python 2
Easy visualization using Python but PixieDust