2012-07-20 8 views
5

me encontré con una expresión interesante en Ruby:¿Hay alguna expresión en Python que al igual que el rubí del || =

a ||= "new" 

Esto significa que si una no está definido, se le asignará el "nuevo" valor a un; de lo contrario, a será lo mismo que es. Es útil cuando se hace una consulta DB. Si el valor está establecido, no deseo disparar otra consulta DB.

así que traté de la mentalidad similar en Python:

a = a if a is not None else "new" 

Fracasó. Creo que es porque no se puede hacer "a = a" en Python, si a no está definido.

Así que las soluciones que pueden salir mirando locales() y globales(), o el uso de tratar ... excepto la expresión:

myVar = myVar if 'myVar' in locals() and 'myVar' in globals() else "new" 

o

try: 
    myVar 
except NameError: 
    myVar = None 

myVar = myVar if myVar else "new" 

Como podemos ver , las soluciones no son tan elegantes. Entonces me gustaría preguntar, ¿hay alguna forma mejor de hacer esto?

+0

tenga en cuenta que el uso habitual de 'variable || = value' es establecer un valor predeterminado para una variable ya definida, usarlo para definir variables que pueden o no existir es una práctica humilde en mi humilde opinión. – tokland

+1

La solución try-except es, creo, la más pitonica. Claro, no es tan conciso como un solo operador, pero es claro y legible. –

+0

'myVar = myVar if myVar else" nuevo "' - tenga en cuenta que esto es python y no ruby, y muchas cosas se consideran falsas en un contexto booleano –

Respuesta

3

¿Qué tal?

try: 
    a = a 
except NameError: 
    a = "new" 

No es muy corto pero explica claramente (al menos para mí) la intención del código.

+0

¿No se muestra el mismo código en la pregunta? –

+1

No del todo. En la pregunta, a se establece en Ninguno, y luego se usa una expresión ternaria para establecer a a "nuevo". Y la expresión ternaria tal como está escrita fallará si a es [] o cualquier otra cosa que se evalúe como Falso. Como se mencionó anteriormente, debe hacer 'a is not None'. – casevh

+0

Tienes razón, leí la pregunta equivocada, de ahí mi comentario al respecto, donde digo que esa parte es una buena solución :) –

5

Usar una variable indefinida como "predeterminado" es un poco olor a código. Como descubrió, falla porque no puede hacer a = a si todavía no existe. Es mejor inicializar su variable con algún valor predeterminado (como Ninguno) y luego verificar eso. Así que prácticamente encontraste la solución. Lo único es que, en lugar de dejar su variable no activada e intentar usar "no existe" como el valor "faltante", debe inicializarla de manera explícita. Así, en lugar de hacer esto:

# code with no initialization. . . 
a ||= blah 

hacer esto:

a = None 
# code 
if a is None: 
    a = blah 
+0

La ventaja de 'a || = blah' es que no tiene que preparar el valor de antemano y es simple y breve. Eso es algo bueno. Pero supongo que tienes razón. Esta es la forma más simple de hacer esto en Python. – Conan

+0

Puedes acortar las últimas líneas a: 'a = a si a no es None else blah', o si sabes que' a' será verdadero 'a = a o blah'. –

1

Si realmente quería este comportamiento que estaría mejor fuera en Python usando un dict, por ejemplo: d.get('a', 'new'). Lo que significa que puede ensuciar con globals()/locals(). get('a', 'new'), pero esa no es, en general, la forma de hacer las cosas en Python: cada enlace de nombre debe tener un valor inicial, incluso si se trata de algún tipo de valor centinela (como None).

horrible ejemplo con variables globales() y utilizando setdefault()

>>> a 
Traceback (most recent call last): 
    File "<pyshell#66>", line 1, in <module> 
    a 
NameError: name 'a' is not defined 
>>> globals().setdefault('a', 'new') 
'new' 
>>> a 
'new' 
>>> a = 'old' 
>>> globals().setdefault('a', 'new') 
'old' 
>>> a 
'old' 
+0

concedido, es un hipotético, pero probablemente 'd.setdefault ('a', 'new')' sería una mejor opción. –

+0

Creo que get() no puede funcionar con globals() y locals(). Después de hacerlo, a todavía no está definido. – Conan

+0

@conan y el horrible ejemplo que he agregado parece funcionar (solo probado con tipear cosas, aunque IDLE) –

1

Pythonic es que debes saberlo antes de usarlo especialmente en vars locales/globales en lugar de adivinar dónde está. Puede escribir el código, pero no es Pythonic

a = None 
# other codes 
a = a or 'new' 

es bien

1

considerar el uso de memoization, que es bastante Pythonic.He aquí algunos de Python 2 Código:

# Backport of Python 3's lru_cache 
# pip install functools32 
from functools32 import lru_cache 

@lru_cache() 
def expensive_db_query(arg): 
    print "Running expensive db query for", arg 
    return arg[::-1] 

expensive_db_query("spam") # prints "Running expensive db query for spam" 
expensive_db_query("spam") # No output 
expensive_db_query("eggs") # prints "Running expensive db query for eggs" 

Si usted quiere tener la caché olvide valores después de que haya transcurrido el tiempo suficiente y consultar la base de datos de nuevo, echa un vistazo a Ilialuk's lru cache.

0

Aquí es una variante inspirada en this answer sobre la manera de comprobar si se define una variable:

a = a if "a" in vars() or "a" in globals() else "new" 

No es tan corto, pero es al menos una línea.

In [1]: a 
--------------------------------------------------------------------------- 
NameError         Traceback (most recent call last) 
<ipython-input-1-60b725f10c9c> in <module>() 
----> 1 a 

NameError: name 'a' is not defined 

In [2]: a = a if "a" in vars() or "a" in globals() else "new" 

In [3]: a 
Out[3]: 'new' 

In [4]: a = "A exists!" 

In [5]: a = a if "a" in vars() or "a" in globals() else "new" 

In [6]: a 
Out[6]: 'A exists!' 

Dicho esto, estoy de acuerdo con BrenBarn que se debe evitar el problema con una variable no definida con sólo declarar con a=None antes del bloque, donde es posible que no configurarlo.

Cuestiones relacionadas