Python method to remove iteration

Suppose I have a function that can either take an iterative / iterator, or indestructible as an argument. Iterability is checked with try: iter(arg).

Depending on whether the input is iterable or not, the result of the method will be different. Not when I want to convey indestructible as iterable input, it is easy to do: I just wrapped it with a tuple.

What should I do when I want to convey iterability (for example, a string), but I want the function to perceive it as if it were not iterative? For example. what iter(str)does not work.

Change is my original intention:

I wanted to generalize the function zipin that it can zip iterate with non-iterators. The indestructible will then be repeatitself as often as the other iterables havent.

The only general solution for me now seems to be that I should not check inside the function general_zip(due to string problems); but instead, I have to add an iterator repeatto the argument before the call zip. (This actually saves me from creating a function general_zip- although I can still, because with immutable input quality, it will be unambiguous without additional repetition.)

+5
source share
5 answers

, , .

, , :

from itertools import repeat
func(repeat(string_iterable))

func , charaters . , , non-iterable.

+3

! , iterables, iterables noniterables, noniterables iterables noniterables noniterables. , () , , , :

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 :

foo((noniterable,))

PS. , . . , , - . , , , , , .

+2

.

def can_iter(arg):
   if isinstance(arg, str):
     return False
   try:
     ...
0

, , , - ( ), , ( .. 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, .

[P.s.] - :

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

('s' 'arr', , , ) - 'fmt' "(.. 'iter' , 'non-iter' - ). , " " .

0

Do not check iterability. It is a mistake for a function to check elements of its types / capabilities, so that one function performs different tasks. If you want to do two different things, do two different functions.

It looks like you yourself came to that conclusion and provide a consistent API where you do

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

Note that this is almost always useless, as you could just do

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

Unless, of course, you feed it what you already use zip.

0
source

All Articles