2009-04-20 12 views
14

En Perl, a menudo es bueno poder asignar un objeto, pero especifique algún valor de recuperación si la variable que se asigna es 'undef'. Por ejemplo:¿Cuál es la forma más pitonica de proporcionar un valor de retroceso en una tarea?

my $x = undef; 
my $y = 2; 
my $a = $x || $y; 

Después de esto,

$a == 2 

¿Hay una manera concisa para lograr esto en Python si el valor de x es Ninguno, o haría un completo en ...

if x is not None 
    a = x 
else 
    a = y 

... ¿ser la forma más pitonica de lograr esto?

EDIT: Disculpas, como han señalado varios comentaristas, realmente no estaba hablando de que el valor sea indefinido, sino "indefinido" en Perl, que no es realmente lo mismo. Pero la pregunta tal como estaba redactada originalmente no lo dejó en claro.

+2

Tenga en cuenta que "si la variable asignada desde está indefinida" es INCORRECTA. "si la variable que se le asigna es falsa" está mucho más cerca de la verdad. – innaM

+1

Para seguir el comentario de Manni: es mejor usar el operador definido "u" si puede confiar en Perl 5.10 o posterior. (Esto no tiene ninguna relación con la forma en que lo haría en Python.) –

Respuesta

26

Desde 2.5:

Si desea recuperar única en Ninguno:

a = x if x is not None else y 

Si desea volver a caer también en la cadena vacía, false, 0 etc .:

a = x if x else y 

o

a = x or y 

En cuanto a indefinido (como nunca definido, alias no esté obligado):

try: 
    a = x 
except NameError: 
    a = y 

o un poco más hacker (no realmente recomiendo que, pero es corto):

a = vars().get('x',y) 
+0

Mucho mejor que el mío ... – Greg

+0

hm, entonces x se define después de todo:/ – SilentGhost

+0

@greg: no es mejor que el tuyo pero es igualmente erróneo – SilentGhost

1

Hay operación ternaria de pitón:

a = x if x is not None else y 

Disponible en 2.5 y más.

-1

Si se trata de un argumento a una función que puede hacer esto:

def MyFunc(a=2): 
    print "a is %d"%a 

>>> MyFunc() 
...a is 2 
>>> MyFunc(5) 
...a is 5 

[Editar] Para los downvoters .. if/bit demás es innecesario para la solución - acaba de agregar para que los resultados claro. ¿Editado para eliminar la declaración if si eso lo hace más claro?

+0

No tengo idea de qué lo forzó a agregar el if else en MyFunc. Si matas el bloque if, else y else, todo sigue igual. –

+0

Por supuesto que sí - ¡Solo intentaba ilustrar los resultados! –

+0

+1 para neutralizar desde que corrigió. :) –

5

En primer lugar puede hacer su lleno-en con un ternario:

a = y if x is None else x 

pero no resuelve su problema.lo que quiere hacer es más estrechamente implementado con:

try: 
    a = x 
except: 
    a = y 
+0

Disculpe, sí, esto no fue lo que estaba buscando, ¡pero es una buena respuesta a la pregunta que realmente hice! – maxaposteriori

+0

@Andy: lea los comentarios más votados a la respuesta aceptada para ver por qué no responde su pregunta en realidad – SilentGhost

+0

Esta solución parece ser la forma correcta de hacerlo. Puede hacerlo más conciso simplemente haciendo: try: a = x excepto: a = y – randlet

0

La mayor parte de las soluciones que dependen de si las declaraciones no funcionan para el caso en que x es 0 o negativo.

>>> x = 0 
>>> y = 2 
>>> a = x or y 
>>> a 
2 
>>> 

Si sabía el nombre de la variable antes de tiempo podría buscar de esta manera:

if 'x' in dir(): 
    a = x 
except: 
    a =y 

Sin embargo parece que la solución tipo de descuidado a mí. Creo que el mejor método es usar una oportunidad a excepción de bloque de esta manera:

try: 
    a = x 
else: 
    a = y 
3

Estoy totalmente convencido de que no hay manera 'Pythonic' para hacer esto, porque esto no es un patrón que es Pythonic. El control no debe alcanzar una referencia de variable indefinida en un código elegante. Hay ideas similares que son pitónicas. El más obvio:

def myRange(start, stop=None): 
    start, stop = (0, start) if stop is None else (start, stop) 
    ... 

Lo que es importante es que stop se define en su alcance, pero la persona que llama no tenían que pasar explícitamente, sólo que se ha tomado su valor por defecto, la alteración de la semántica de los argumentos que, a su efecto hace que el primer argumento sea opcional en lugar del segundo, incluso cuando el lenguaje no lo permite sin este ingenioso truco.

Dicho esto, algo como esto podría seguir la premisa sin usar un bloque try-catch.

a = locals().get('x', y) 
+0

+1 De acuerdo al 100% cuando dices "porque este no es un patrón que es pitónico" –

4

Sólo un poco quisquilloso con su ejemplo Perl:

my $x = undef; 

Este código redundante se puede acortar a:

my $x; 

Y el siguiente código no hace lo que dice que hace :

my $a = $x || $y; 

Th en realidad le asigna $ y a $ a cuando $ x es falso. Los valores falsos incluyen cosas como undef, cero y la cadena vacía. Para única prueba para definedness, se puede hacer lo siguiente (a partir de Perl 5.10):

my $a = $x // $y; 
0

Una forma de volver a escribir ...

if x is not None 
    a = x 
else 
    a = y 

..es:

x = myfunction() 

if x is None: 
    x = y 

print x 

O bien, el uso de excepciones (posiblemente más Python'y, dependiendo del lo que el código está haciendo - si devuelve Ninguno porque no había un error, utilizando una excepción es probablemente la manera correcta):

try: 
    x = myfunction() 
except AnException: 
    x = "fallback" 

print x 

dicho todo esto, en realidad no hay nada de malo en que código original:

if x is not None 
    a = x 
else 
    a = y 

es largo, pero me parece que mucho más fácil de leer (y mucho más Pythonic) que cualquiera de los follo wing one-liners:

a = x if x is not None else y 
a = x or y 
Cuestiones relacionadas