Pythonic способ сделать функцию, которая может принимать итеративный или любое количество аргументов? - PullRequest
2 голосов
/ 03 апреля 2019

Действительно ли это самый Pythonic способ создать функцию, которая может принимать итеративное или любое количество аргументов и что-то делать с каждым из них?

from collections.abc import Iterable


def for_each(*args):
    """Take any number of arguments or an iterable and do something with them.
    Shouldn't throw an error or print anything when no arguments are given.
    """
    if (len(args) == 1
            and isinstance(args[0], Iterable)
            and not isinstance(args[0], str)):
        # Is this really the most Pythonic way to do this?
        args = args[0]

    for arg in args:
        # heavily simplified
        print("done", arg)


for_each(1, 2)
for_each(['foo', 'bar'])
for_each((3, 4, 5))
for_each()  # does essentially nothing, like it should
for_each("string")  # don't loop over the characters
for_each(6)

Выход:

done 1
done 2
done foo
done bar
done 3
done 4
done 5
done string
done 6

Я получил этот рабочий ответ отсюда , но поскольку я действительно искал более чистый способ сделать это, я задал этот новый вопрос.

Это работает, но, на мой взгляд, проверка довольно уродлива, и Я надеялся, что будет более простой и чистый способ добиться этого . Выходной сигнал должен оставаться неизменным.

1 Ответ

6 голосов
/ 03 апреля 2019

Питонский путь - не . Выберите один и позвольте вызывающей стороне предоставить правильный аргумент (ы):

# Iterable only: caller wraps the arguments
def for_each(iterable=None):
    if iterable is None:
        iterable = ()
        # or just return now, if that's an option

    for arg in iterable:
        ...

foreach((1,2,3))

# separate args: caller unpacks the arguments
def for_each(*args):
    for arg in args:
        ...

x = [1,2,3]
for_each(*x)

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

Если это нужно сделать так, как вы хотите, ваш исходный пример будет настолько хорош, насколько вы можете, но он все еще несовершенен. Предположим, пользователь хочет обработать строку как в итерируемой; ваш подход все еще требует, чтобы они написали for_each (["foo"]), и в этом случае, зачем усложнять реализацию вашей функции без причины.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...