2011-11-01 14 views
5

A lo largo de los años he notado la variable 'comodín' en varias partes de Python que he encontrado. Supuse que funcionaba como Haskell: permitiéndole poner una variable donde se requería uno en los parámetros formales, pero sin vincularlo.Comodines en Python?

Lo he usado, por ejemplo, en el lado izquierdo de una asignación de tupla-desembalaje cuando no necesito una de las variables.

Por ejemplo:

_, extension = os.path.splitext(filename) 

Así que cuando escribí algo similar a esto hoy:

(lambda (x,_,_): x)((1,2,3)) 

POR EJEMPLO Traté de unir el guión bajo dos veces, recibí un error de sintaxis. Me sorprendió ver que _ es de hecho una variable real:

(lambda (x,_,z): _)((1,2,3)) 
> 2 

Parece que _ es sólo un nombre de variable como cualquier otro.

¿Existe una variable de comodín de buena fe que pueda usar como me gustaría (es decir, que pueda usar más de una en una asignación de desempaquetado de tuplas), según el primer ejemplo?

Respuesta

4

No hay una variable comodín en Python.

Intento disuadir a las personas de usar _ como nombre de variable desde hace bastante tiempo. No es la primera persona que confunde _ como una especie de sintaxis especial, por lo que es mejor no usar _ como nombre de variable para evitar este tipo de confusión. Si alguna vez hubo una "convención" para usar _ como un nombre de variable descartable, esta convención fue errónea.

Hay más problemas que solo la confusión que causa. Por ejemplo, _ choca con _ en el intérprete interactivo y el alias gettext común.

En cuanto a la expresión lambda, solo usaría lambda x, *args: ... para ignorar todos los argumentos excepto el primero. En otros casos, usaría los nombres explícitamente diciendo que no quiero usarlos, como dummy. En el caso de los bucles de range() s, generalmente uso for i in range(n) y simplemente no uso i.

Editar: Acabo de notar (mirando a las otras respuestas) que se utilizan tupla desembalaje en la lista de argumentos, por lo lambda x, *args: ... no resuelve su problema. El desempaquetado de Tuple en las listas de parámetros se ha eliminado en Python 3.x porque se consideraba una característica demasiado oscura. Mejor ir con mipadi's answer en su lugar.

3

No, Python no tiene ningún equivalente a Haskell's _. La convención en Python es usar _ para variables "desechables", pero es un nombre de variable real, y como usted encontró, no puede usarlo dos veces en el mismo contexto (como una lista de parámetros lambda).

En los ejemplos que diste, yo sólo tiene que utilizar la indexación:

lambda tup: tup[0] 

o

lambda tup: tup[1] 

No es tan bonita, pero una de las mejores maneras de hacerlo.

1

La respuesta corta es no. Podría simplemente seguir su convención existente. Eso es

(lambda (x, _1, _2): x)((1,2,3)) 
3

Realmente no. Python no es Haskell. Map, apply, reduce y lambda son ciudadanos de segunda clase, aunque hay algunas cosas interesantes en itertools.

A menos que tenga alguna necesidad de utilizar lambdas de una sola línea, la forma correcta es la siguiente:

def f(x, *args, **kwargs): 
    return x 

El argumento *args le permite utilizar cualquier número de argumentos sin nombre (que estará disponible como una tupla llamada args) Los argumentos adicionales se encontrarán en un diccionario llamado kwargs.

No creo que haya ninguna manera de hacer esto en una lambda, pero generalmente no hay necesidad. Una declaración de función puede ir a cualquier parte.Tenga en cuenta, que haces cosas interesantes/mal si se pone la definición de función dentro de otra función (o circular):

def make_func(s): 
    def f(*trash, **more_trash): 
     print s 
    return f 

f1 = make_func('hello') 
f2 = make_func('world') 
f1(1,2,'ham','spam') 
f2(1,2,a=1,b=2) 

la Salida:

>>> hello 
>>> world 

Como @rplnt señaló, esto no será lo mismo para los bucles de salida:

funcs = [] 
for s in ('hello','world'): 
    def f(): 
     print s 
    funcs.append(f) 

for f in funcs: 
    f() 

voluntad:

>>> world 
>>> world 

porque los bucles solo tienen un espacio de nombre.

+1

En python 3 esto también funciona en el desembalaje, por ejemplo: '(a, * rest, b) = [1,2,3,4]' – rplnt

+1

Además, los bucles no deberían ser un problema ya que no tienen su propio espacio de nombres. – rplnt

+0

Además, puedes usar '*' y '**' con lambdas. – kindall

2

Es posible, con un pequeño truco:

class _: 
    def __eq__(x,y): return true 
_=_() #always create a new _ instance if used, the class name itself is not needed anymore 

[(a,b) for (a,_,_,b) in [(1,2,3,4),(5,6,7,8)]] 

da

[(1, 4), (5, 8)] 

lo estoy usando con frecuencia, ya que hace que el código sea más elegante, una parte de Haskell belleza en Python .