Параметр функции Python: кортеж/список

моя функция ожидает список или кортеж в качестве параметра. Его не волнует, что это все она делает, это передать его в другую функцию, которая принимает список или кортеж:

def func(arg): # arg is tuple or list
  another_func(x)
  # do other stuff here

Теперь мне нужно немного изменить функцию, чтобы обработать дополнительный элемент:

def func(arg): #arg is tuple or list
  another_func(x + ['a'])
  # etc

к сожалению, это не сработает: если arg-кортеж, я должен сказать x + ('a',).

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

есть ли лучший способ сделать это? Конечно, я не могу заставить абонентов всегда передавать Кортеж, так как он просто переходит к ним.

9 ответов


Если another_func просто хочет iterable вы можете пройти itertools.chain(x,'a') к нему.


Как насчет изменения другой функции, чтобы принять список параметров вместо этого ?

def func(arg): # arg is tuple or list
  another_func('a', *x)

как насчет:

l = ['a']
l.extend(x)

изменить: Перечитывая вопрос, я думаю, это больше того, что вы хотите (использование arg и x было немного запутанно):

tuple(arg) + ('a',)

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


def f(*args):
    print args

def a(*args):
    k = list(args)
    k.append('a')
    f(*k)

a(1, 2, 3)

выход:

(1, 2, 3, 'a')

если достаточно iterable, вы можете использовать itertools.chain, но имейте в виду, что если функция A (первый вызываемый), также выполняет итерацию по iterable после вызова B, тогда у вас могут возникнуть проблемы, так как iterables нельзя перемотать. В этом случае вы должны выбрать последовательность или использовать iterable.tee чтобы сделать копию iterable:

import itertools as it

def A(iterable):
    iterable, backup = it.tee(iterable)
    res = B(it.chain(iterable, 'a'))
    #do something with res
    for elem in backup:
        #do something with elem

def B(iterable):
   for elem in iterable:
       #do something with elem

хотя itertools.tee не эффективным, если B потребляет все или большинство из iterable, в этот момент проще просто преобразовать iterable до tuple или list.


мое предложение:

def foo(t):
    bar(list(t) + [other])

Это не очень эффективно, хотя, вам было бы лучше передавать изменчивые вещи, если вы собираетесь, ну, мутировать их.


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

from itertools import chain

def func(iterable):
    it = iter(iterable)
    another_func(type(iterable)(chain(it, ('a',))))

def another_func(arg):
    print arg

func((1,2))
# (1, 2, 'a')
func([1,2])
# [1, 2, 'a']

пусть ваша функция принимает любую итерацию. Тогда используйте itertools.chain чтобы добавить любую последовательность, которую вы хотите к iterable.

from itertools import chain

def func(iterable):
    another_func(chain(iterable, ('a',)))

Я бы сказал, что ответ Сантьяго Lezica делать

def foo(t):
    bar(list(t) + [other])

является лучшим, потому что это самый простой. (нет необходимости импортировать материал itertools и использовать гораздо менее читаемые цепные вызовы). Но используйте его, только если вы ожидаете, что t будет маленьким. Если t может быть большим, вы должны использовать одно из других решений.