2010-11-17 21 views
6

Mi función espera una lista o una tupla como parámetro. Realmente no importa lo que es, todo lo que hace es pasar a otra función que acepta una lista o tupla:Parámetro de función de Python: tuple/list

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

Ahora tengo que modificar ligeramente la función, para procesar un elemento adicional:

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

Desafortunadamente esto no va a funcionar: si arg es tupla, debo decir x + ('a',).

Obviamente, puedo hacerlo funcionar forzando arg a la lista. Pero no es limpio.

¿Hay una mejor manera de hacerlo? No puedo obligar a las personas que llaman a pasar una tupla siempre, por supuesto, ya que simplemente cambia para trabajar para ellos.

+0

Si la otra función acepta, o no, le enviaré una tupla, ya que será más rápido para trabajar con ella. Entonces, ¿qué no es bueno sobre 'tuple (x) + ('a',)'? – aaronasterling

+0

¿Las tuplas son más rápidas en la implementación? – max

+2

construir una tupla de cadenas y literales numéricos es más rápido que construir una lista. Más importante aún, 'tuple (x)' simplemente devuelve 'x' si ya es una tupla, mientras que' list (x) 'copia' x' incluso si ya es una lista. Entonces, al usar una tupla, cortas la mayor parte del trabajo en la mitad de tus casos de entrada. – aaronasterling

Respuesta

7

Si another_func sólo quiere un iterable puede pasar itertools.chain(x,'a') a ella.

+0

+1 Me gusta esto, pero ¿es rápido? – max

+0

@max No se realiza ninguna copia, por lo que es muy rápido. Probablemente sea la solución de Python más eficiente. –

3

¿qué tal:

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

Editar: Releyendo pregunta, creo que esto es más lo que quiere (el uso de arg y x era un poco complicado):

tuple(arg) + ('a',) 

Como han dicho otros, esta probablemente no sea la forma más eficiente, pero está muy clara. Si sus tuplas/listas son pequeñas, podría usar esto sobre soluciones menos claras ya que el rendimiento alcanzado será insignificante. Si sus listas son grandes, use las soluciones más eficientes.

+0

'extend' devuelve' None', ya que muta la lista. – delnan

+0

+1, simple y limpio – slezica

+0

@delnan: ¿qué quieres decir? – max

4

¿Qué hay de cambiar la otra función para aceptar una lista de params en su lugar?

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

¿Qué pasa cuando another_func necesita varios argumentos de lista que se ven afectados por el mismo problema , o si ya tiene un parámetro * x (no relacionado)? – max

+0

+0: bueno pero no está seguro si se pueden cambiar otras funciones – Claudiu

+0

@max: La respuesta es la misma. Arregla la otra función –

2
def f(*args): 
    print args 

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

a(1, 2, 3) 

Salida:

(1, 2, 3, 'a') 
+0

hmm 'f (* (tupla (args) + ('a',))' es mejor – Claudiu

1

Mi sugerencia:

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

Esto no es muy eficiente, sin embargo, que sería mejor pasar las cosas mutables si va a estar , bueno, mutarlos.

+0

¿Podría aclarar por favor? ¿Por qué esto no es eficiente? – max

+0

@max No es tan eficiente porque copia una lista completa solo para agregar un único elemento. –

0

Haga que su función acepte cualquier iterable. Luego use itertools.chain para agregar la secuencia que desee al iterable.

from itertools import chain 

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

Usted puede utilizar el tipo de la iterables pasado a la primera función para construir lo que se pasa a la segunda:

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'] 
2

Si un iterable es suficiente, se puede utilizar itertools.chain, pero tenga en cuenta que si la función A (la primera llamada), también itera sobre el iterable después de llamar al B, entonces puede tener problemas ya que los iterables no pueden rebobinarse.En este caso se debe optar por una secuencia o utilizar iterable.tee para hacer una copia de la 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 

Aunque itertools.tee no es realmente tan eficiente si B consume toda o la mayor parte del iterable, en ese punto, es más simple convertir iterable a tuple o list.

+0

+1 para la aclaración sobre el rebobinado de los iteradores. En mi caso, iterable es suficiente; supongo que para el caso de la secuencia me limitaré a la tupla como lo sugiere @aaronasterling – max

0

yo diría que la respuesta de hacer

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

de Santiago Lezica es la mejor, ya que es el más simple. (no es necesario importar cosas de itertools y usar cadenas de llamadas mucho menos legibles). Pero solo úsela si espera que sea pequeño. Si t puede ser grande, debe usar una de las otras soluciones.

Cuestiones relacionadas