Конвейеры в Python

Конвейер позволяет передавать результат выполнения выражения первым параметром в другое выражение. Хорошо знаком системным администратором — помогает передать вывод предыдущей команды на ввод следующей или на вход командного интерпретатора. В Python конвейеры реализуются довольно сложно и вообще поощряется более императивный подход с промежуточными переменными. Но есть интересные эксперименты на эту тему.

Робин Шроер в своем блоге предложил довольно гибкое и расширяемое решение с использованием простой функции:

def pype(x, *fs):
    """
    Pipe function. Takes an initial value and any number of functions/methods.
    Methods as strings. Additional args are supported for functions & methods
    by suppling a step as a tuple/list with function/method as the first
    element and the args as the rest. The pipe input is used as the last
    argument in this case. Currently no kwargs.
    """
    while fs:
        f = fs[0]
        args = []
        if isinstance(f, (list, tuple)):
            args = list(f[1:])
            f = f[0]
        if isinstance(f, str):
            if f.startswith('.'):
                x = getattr(x, f[1:])(*args)
            else:
                x = x[f]
        elif isinstance(f, int):
            x = x[f]
        else:
            x = f(*args + [x])
        fs = fs[1:]
    return x

Пример использования:

from pype import pype

def add_suffix(number, s):
    return '{} is {} cool!'.format(
        s,
        ' '.join('very' for _ in range(number))
    )

pype(
    '   abc: {}   ',
    '.strip',
    ('.format', 3),
    (add_suffix, 2),
    '.upper',
)

# 'ABC: 3 IS VERY VERY COOL!'

Пример не поддерживает именованные аргументы, нельзя также указать, в каком месте передать входной аргумент, он всегда занимает последнюю позицию. Тем не менее, идея любопытная и может пригодиться в каком-нибудь проекте.


Посмотрите также реализацию оператора конвейера с использованием абстрактного синтаксического дерева. Правда, такой вариант сложнее анализировать и расширять, если вы не знакомы с манипулированием AST в Python.