Python: declaración try en una sola línea

89

¿Hay alguna forma en Python de convertir un try / except en una sola línea?

algo como...

b = 'some variable'
a = c | b #try statement goes here

Donde bes una variable declarada y cno lo es ... entonces carrojaría un error y ase convertiría en b...

Brant
fuente

Respuestas:

60

No hay forma de comprimir un bloque try/ excepten una sola línea en Python.

Además, es malo no saber si una variable existe en Python, como lo haría en otros lenguajes dinámicos. La forma más segura (y el estilo predominante) es establecer todas las variables en algo. Si es posible que no se establezcan, configúrelos en Noneprimero (o 0o ''o algo si es más aplicable).


Si haces asignar todos los nombres que están interesados en primer lugar, usted tiene opciones.

  • La mejor opción es una declaración if.

    c = None
    b = [1, 2]
    
    if c is None:
        a = b
    else:
        a = c
    
  • La opción de una sola línea es una expresión condicional.

    c = None
    b = [1, 2]
    a = c if c is not None else b
    
  • Algunas personas abusan del comportamiento de cortocircuito de orpara hacer esto. Esto es propenso a errores, por lo que nunca lo uso.

    c = None
    b = [1, 2]
    a = c or b
    

    Considere el siguiente caso:

    c = []
    b = [1, 2]
    a = c or b
    

    En este caso, aprobablemente debería serlo [], pero es [1, 2]porque []es falso en un contexto booleano. Debido a que hay muchos valores que pueden ser falsos, no utilizo el ortruco. (Este es el mismo problema con el que se encuentran las personas cuando dicen lo if foo:que quieren decir if foo is not None:).

Mike Graham
fuente
Gracias. El problema es que en realidad es una consulta django model.objects.get que estoy tratando de probar. el .get devuelve un error si no se encuentran datos ... no devuelve Ninguno (lo que me molesta)
Brant
@Brant, está bien, esa situación es un poco diferente a verificar si una variable está configurada (no se declaran variables en Python). El estilo típico en Python es preferir generar excepciones a devolver errores como valores, lo que a muchos de nosotros nos encanta. Tener que verificar el código de retorno de una operación cada vez y tener dificultades para rastrear errores si no lo hago es algo que definitivamente no extraño de C cuando escribo Python. En cualquier caso, aunque se ha discutido, no existe una sintaxis de una línea para un bloque try/ except. Afortunadamente, las líneas son baratas, por lo que la solución de 4 líneas debería funcionar para usted. ;-)
Mike Graham
Es parte de un gran conjunto de tuplas dentro de un dictado ... Solo estaba tratando de acortar un poco las cosas
Brant
2
No lo use getsi no desea una excepción. Úselo en su filterlugar.
jcdyer
@MikeGraham Buena respuesta: una pista (¿enlace?) De por qué el cortocircuito es propenso a errores sería bueno.
kratenko
83

Esto es terriblemente hackeo, pero lo he usado en el indicador cuando quería escribir una secuencia de acciones para depurar:

exec "try: some_problematic_thing()\nexcept: problem=sys.exc_info()"
print "The problem is %s" % problem[1]

En su mayor parte, no me molesta en absoluto la restricción de no probar una sola línea excepto, pero cuando solo estoy experimentando y quiero que readline recuerde una parte completa de código a la vez en el intérprete interactivo, que puedo ajustarlo de alguna manera, este pequeño truco es útil.

Para el propósito real que está tratando de lograr, puede intentarlo locals().get('c', b); idealmente sería mejor usar un diccionario real en lugar del contexto local, o simplemente asignar c a Ninguno antes de ejecutar lo que sea que pueda-o-no-establecer.

Walter Mundt
fuente
26
¡Oye, esto responde la pregunta! :)
Steve Bennett
4
Amo esta respuesta, súper desordenada, pero una línea, tal como me gusta.
Patrick Cook
¡¡Esta es la respuesta!! será problem[0]devolver lo que devuelve la función?
SIslam
4
Exec es un olor a código y debe evitarse a menos que nada más funcione. Si un código de línea es tan importante, esto funcionará, pero debe preguntarse por qué una línea es tan importante.
Gewthen el
4
claramente no para uso de producción, sino exactamente lo que se necesita para una sesión de depuración incómoda.
ThorSummoner
46

En python3 puede usar contextlib.suppress :

from contextlib import suppress

d = {}
with suppress(KeyError): d['foo']
dset0x
fuente
8
esta debería ser la respuesta estándar
Sphynx-HenryAY
13

Otra forma es definir un administrador de contexto:

class trialContextManager:
    def __enter__(self): pass
    def __exit__(self, *args): return True
trial = trialContextManager()

Luego use la withdeclaración para ignorar los errores en una sola línea:

>>> with trial: a = 5      # will be executed normally
>>> with trial: a = 1 / 0  # will be not executed and no exception is raised
>>> print a
5

No se generará ninguna excepción en caso de un error de tiempo de ejecución. Es como try:sin el except:.

bitagoras
fuente
1
¡Esto es genial! Dado que no hay un intento / excepción explícito, ¿podría explicar brevemente cómo el administrador de contexto maneja los errores?
Patrick
8

Versión de la respuesta poke53280 con limitadas excepciones esperadas.

def try_or(func, default=None, expected_exc=(Exception,)):
    try:
        return func()
    except expected_exc:
        return default

y podría usarse como

In [2]: try_or(lambda: 1/2, default=float('nan'))
Out[2]: 0.5

In [3]: try_or(lambda: 1/0, default=float('nan'), expected_exc=(ArithmeticError,))
Out[3]: nan

In [4]: try_or(lambda: "1"/0, default=float('nan'), expected_exc=(ArithmeticError,))
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
[your traceback here]
TypeError: unsupported operand type(s) for /: 'str' and 'int'

In [5]: try_or(lambda: "1"/0, default=float('nan'), expected_exc=(ArithmeticError, TypeError))
Out[5]: nan
Pavlo Pravdiukov
fuente
¿Para qué sirve la coma en "espera_exc = (excepción,)"? ¿Puedes explicarme, por favor?
ibilgen
7
parse_float = lambda x, y=exec("def f(s):\n try:\n  return float(s)\n except:  return None"): f(x)

Siempre hay una solucion.

Miklos Horvath
fuente
5

El problema es que en realidad es una consulta django model.objects.get que estoy tratando de probar. el .get devuelve un error si no se encuentran datos ... no devuelve Ninguno (lo que me molesta)

Usa algo como esto:

print("result:", try_or(lambda: model.objects.get(), '<n/a>'))

Donde try_or es una función de utilidad definida por usted:

def try_or(fn, default):
    try:
        return fn()
    except:
        return default

Opcionalmente se puede restringir los tipos de excepciones aceptadas a NameError, AttributeError, etc.

poke53280
fuente
4

Puede hacerlo mediante el acceso al espacio de nombres utilizando dict vars(), locals()o globals(), lo que sea más adecuado para su situación.

>>> b = 'some variable'
>>> a = vars().get('c', b)
jcdyer
fuente
3
Esto no funciona exactamente igual que verificar si una variable está configurada (aunque lo hace si está interesado en un ámbito en particular). Además, ewwwwwwww .....
Mike Graham
4

¿Qué tal si usamos dos líneas? está bien ?

>>> try: a = 3; b= 0; c = a / b
... except : print('not possible'); print('zero division error')
...
not possible
zero division error
surendra ben
fuente
2

Mencionaste que estás usando django. Si tiene sentido para lo que está haciendo, es posible que desee utilizar:

my_instance, created = MyModel.objects.get_or_create()

createdserá Verdadero o Falso. Quizás esto te ayude.

blokeley
fuente
1

si realmente necesita administrar las excepciones:
(modificado de la respuesta de poke53280)

>>> def try_or(fn, exceptions: dict = {}):
    try:
        return fn()
    except Exception as ei:
        for e in ei.__class__.__mro__[:-1]:
            if e in exceptions: return exceptions[e]()
        else:
            raise


>>> def context():
    return 1 + None

>>> try_or( context, {TypeError: lambda: print('TypeError exception')} )
TypeError exception
>>> 

tenga en cuenta que si la excepción no es compatible, se generará como se esperaba:

>>> try_or( context, {ValueError: lambda: print('ValueError exception')} )
Traceback (most recent call last):
  File "<pyshell#57>", line 1, in <module>
    try_or( context, {ValueError: lambda: print('ValueError exception')} )
  File "<pyshell#38>", line 3, in try_or
    return fn()
  File "<pyshell#56>", line 2, in context
    return 1 + None
TypeError: unsupported operand type(s) for +: 'int' and 'NoneType'
>>> 

Además, si Exceptionse proporciona, coincidirá con cualquier valor que se muestra a continuación.
( BaseExceptiones más alto, por lo que no coincidirá)

>>> try_or( context, {Exception: lambda: print('exception')} )
exception
Tcll
fuente
1

Funciona en Python3, inspirado por Walter Mundt

exec("try:some_problematic_thing()\nexcept:pass")

Para múltiples líneas en una sola línea

exec("try:\n\tprint('FirstLineOk')\n\tsome_problematic_thing()\n\tprint('ThirdLineNotTriggerd')\nexcept:pass")

Ps: Exec no es seguro para usar en datos sobre los que no tiene control.

Punnerud
fuente