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