Метод Python для удаления iterability

Предположим, что у меня есть функция, которая может или взять повторяемое / итератор или неповторяемое как аргумент. С Iterability согласовывают try: iter(arg).

Завися, является ли вход повторяемым или нет, результат метода будет отличаться. Не, когда я хочу передать неповторяемое как повторяемый вход, легко сделать: я просто перенесу его с кортежем.

Что я делаю, когда я хочу передать повторяемое (строка, например), но хотеть, чтобы функция взяла его, как будто это неповторяемо? Например, сделайте это iter(str) сбои.

Редактирование – мое исходное намерение:

Я хотел сделать вывод zip функция в этом это может архивировать iterables с non-iterables. Неповторяемое было бы затем repeat самостоятельно так же часто, как другие iterables не заканчивались.

Единственное общее решение fo меня, кажется, теперь, который я не должен проверять в general_zip функция (из-за строковых проблем); но это вместо этого я должен буду добавить repeat итератор к аргументу перед вызовом zip. (Это на самом деле сохраняет меня от изобретения general_zip функция — хотя я все еще мог бы, потому что с неповторяемым как вход это будет однозначно без дополнительного повторения.)

5
задан Debilski 20 March 2010 в 13:17
поделиться

5 ответов

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

Однако, в зависимости от цели функции, один из способов ее обработки может быть следующим:

from itertools import repeat
func(repeat(string_iterable))

func по-прежнему видит итерацию, но не выполняет итерацию по символам самой строки. Фактически, аргумент работает так, как если бы он не повторялся.

3
ответ дан 14 December 2019 в 19:09
поделиться

Специализируйтесь на нем.

def can_iter(arg):
   if isinstance(arg, str):
     return False
   try:
     ...
0
ответ дан 14 December 2019 в 19:09
поделиться

Не проверять итеративность. Ошибочно иметь функцию, которая проверяет типы / возможности ее элементов, чтобы одна функция выполняла разные задачи. Если вы хотите делать две разные вещи, сделайте две разные функции.

Похоже, вы сами пришли к такому выводу и предоставляете согласованный API, где вы и делаете

from itertools import repeat
zip([1, 2, 3], repeat(5), "bar")

Обратите внимание, что это почти всегда бесполезно, так как вы можете просто сделать

five = 5
for number, letter in zip([1, 2, 3], "bar")
    # Just use five here since it never changes

Если, конечно, вы не скармливаете это к чему-то, что уже использует zip .

0
ответ дан 14 December 2019 в 19:09
поделиться

Ого! Похоже, вы хотите иметь возможность передавать итерируемые элементы как итерируемые, итерируемые элементы как не повторяющиеся, а не повторяющиеся как итерируемые, и не повторяющиеся как не повторяющиеся. Поскольку вы хотите иметь возможность обрабатывать все возможности, а компьютер (пока) не может читать мысли, вам придется указать функции, как вы хотите обрабатывать аргумент:

def foo_iterable(iterable):
    ...
def foo_noniterable(noniterable):
    ...

def foo(thing,isiterable=True):
    if isiterable:
        foo_iterable(thing)
    else:
        foo_noniterable(thing)

Apply foo к итерируемому

foo(iterable)

Применить foo к итерируемому как не повторяемому:

foo_noniterable(iterable)       # or
foo(iterable, isiterable=False)

Применить foo к непередаваемому как непередаваемому:

foo_noniterable(noniterable)       # or
foo(noniterable,isiterable=False)

Применить foo к непередаваемому как итерируемому:

foo((noniterable,))

PS. Я верю в небольшие функции, которые хорошо выполняют одну работу. Их легче отлаживать и тестировать. В общем, я бы посоветовал избегать монолитных функций, которые ведут себя по-разному в зависимости от типа.Да, это накладывает небольшое дополнительное бремя на разработчика, вызывая именно ту функцию, которая предназначена, но я думаю, что преимущества с точки зрения отладки и модульного тестирования с лихвой компенсируют это.

2
ответ дан 14 December 2019 в 19:09
поделиться

Итак, один из способов сообщить функции, как вы хотели бы обращаться с ее аргументами, - это иметь разумные значения по умолчанию (заставляя функцию обрабатывать все по исходному типу по умолчанию), при этом имея возможность указать любые настройки, которые вам нравятся, с комфортом ( т.е. с короткой и отсутствующей по умолчанию строкой fmt ), например:

def smart_func(*args, **kw):
    """If 'kw' contains an 'fmt' parameter,
    it must be a list containing positions of arguments,
    that should be treated as if they were of opposite 'kind'
    (i.e. iterables will be treated as non-iterables and vise-versa)

    The 'kind' of a positional argument (i.e. whether it as an iterable)
    is inferred by trying to call 'iter()' on the argument.
    """

    fmt = kw.get('fmt', [])

    def is_iter(it):
        try:
            iter(it)
            return True
        except TypeError:
            return False

    for i,arg in enumerate(args):
        arg_is_iterable = is_iter(arg)
        treat_arg_as_iterable = ((not arg_is_iterable)
                                 if (i in fmt) else arg_is_iterable)
        print arg, arg_is_iterable, treat_arg_as_iterable

Это дает:

>>> smart_func()
>>> smart_func(1, 2, [])
1 False False
2 False False
[] True True
>>> smart_func(1, 2, [], fmt=[])
1 False False
2 False False
[] True True
>>> smart_func(1, 2, [], fmt=[0])
1 False True
2 False False
[] True True
>>> smart_func(1, 2, [], fmt=[0,2])
1 False True
2 False False
[] True False

Расширяя эту функцию (нахождение длины самой длинной итерации и т. д.), можно построить smart-zip , о котором вы говорите.

[Ps] Другой способ - вызвать функцию следующим образом:

smart_func(s='abc', 1, arr=[0,1], [1,2], fmt={'s':'non-iter','some_arr':'iter'})

и получить функцию совпадают с указанными вами именами аргументов ( 's' и 'arr' , примечание, в сигнатуре функций таких имен нет, так как они такие же, как указано выше ]) к 'fmt' «подсказки типа» (то есть «iter» делает аргумент итеративным, а «non-iter» как неповторяемый). Этот подход, конечно, можно комбинировать с вышеупомянутым «тумблерным» подходом.

0
ответ дан 14 December 2019 в 19:09
поделиться
Другие вопросы по тегам:

Похожие вопросы: