Метод Python для удаления итерации - PullRequest
5 голосов
/ 20 марта 2010

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

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

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

Изменить - мое первоначальное намерение:

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

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

Ответы [ 5 ]

3 голосов
/ 20 марта 2010

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

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

from itertools import repeat
func(repeat(string_iterable))

func все еще видит итерацию, но она не будет проходить итерацию самой строки. И по сути, аргумент работает так, как если бы он был константой без итераций.

2 голосов
/ 20 марта 2010

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

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

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

Применитьfoo к итерируемому

foo(iterable)

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

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

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

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

Применить foo к noniterable как итерируемое:

foo((noniterable,))

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

0 голосов
/ 20 марта 2010

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

Похоже, вы сами пришли к такому выводу и предоставляете непротиворечивый 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 голосов
/ 20 марта 2010

Что ж, один из способов сообщить функции о том, как бы вы хотели обработать ее аргументы, - это иметь разумные значения по умолчанию (заставляя функцию обрабатывать все по своему первоначальному типу по умолчанию), в то же время имея возможность указать любые настройки, которые вам нравятся (то есть с короткой и отсутствующей по умолчанию 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' "type-hints" (т. Е. 'iter' делает аргумент, рассматриваемый как итеративный, и 'non-iter' как не повторяемый).Этот подход, конечно, может быть объединен с вышеупомянутым «типом переключения».

0 голосов
/ 20 марта 2010

Специализируйся.

def can_iter(arg):
   if isinstance(arg, str):
     return False
   try:
     ...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...