Existe-t-il un moyen en python de transformer un essai/sauf en une seule ligne?
quelque chose comme...
b = 'some variable'
a = c | b #try statement goes here
Où b
est une variable déclarée et c
n'est pas ... alors c
renvoie une erreur et a
devient b
...
Il n’existe aucun moyen de compresser un bloc try
except
sur une seule ligne en Python.
De plus, il est mauvais de ne pas savoir si une variable existe en Python, comme vous le feriez dans d'autres langages dynamiques. La manière la plus sûre (et le style dominant) est de définir toutes les variables sur quelque chose. Si elles ne sont pas configurées, définissez-les d'abord sur None
(ou 0
ou ''
ou quelque chose si cela s'applique mieux).
Si vous faites assignez d’abord tous les noms qui vous intéressent, vous avez des options.
La meilleure option est une instruction if.
c = None
b = [1, 2]
if c is None:
a = b
else:
a = c
L'option one-liner est une expression conditionnelle.
c = None
b = [1, 2]
a = c if c is not None else b
Certaines personnes abusent du comportement de or
en court-circuitant. C'est sujet aux erreurs, donc je ne l'utilise jamais.
c = None
b = [1, 2]
a = c or b
Considérons le cas suivant:
c = []
b = [1, 2]
a = c or b
Dans ce cas, a
probablement _/devrait être []
, mais il s'agit de [1, 2]
car []
est faux dans un contexte booléen. Parce qu'il y a beaucoup de valeurs qui peuvent être fausses, je n'utilise pas l'astuce or
. (C'est le même problème que les gens rencontrent quand ils disent if foo:
quand ils veulent dire if foo is not None:
.)
C'est terriblement bidon, mais je l'ai utilisé à l'invite lorsque je voulais écrire une séquence d'actions pour le débogage:
exec "try: some_problematic_thing()\nexcept: problem=sys.exc_info()"
print "The problem is %s" % problem[1]
Pour la plupart, je ne suis pas du tout gêné par la restriction no-line-line-try-except, mais lorsque je fais des essais et que je veux que readline rappelle un morceau de code à la fois dans l'interpréteur interactif que je puisse l’ajuster d’une manière ou d’une autre, cette petite astuce est très utile.
Pour le but réel que vous essayez d’atteindre, vous pouvez essayer locals().get('c', b)
; Dans l’idéal, il serait préférable d’utiliser un dictionnaire réel plutôt que le contexte local ou d’attribuer simplement c à Aucun avant d’exécuter ce que vous voulez ou non.
Une autre façon consiste à définir un gestionnaire de contexte:
class trialContextManager:
def __enter__(self): pass
def __exit__(self, *args): return True
trial = trialContextManager()
Utilisez ensuite l'instruction with
pour ignorer les erreurs sur une seule ligne:
>>> 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
Aucune exception ne sera déclenchée en cas d'erreur d'exécution. C'est comme un try:
sans le except:
.
Vous pouvez le faire en accédant à l'espace de noms en utilisant vars()
, locals()
ou globals()
, selon ce qui convient le mieux à votre situation.
>>> b = 'some variable'
>>> a = vars().get('c', b)
Le problème est que c'est en fait une requête Django model.objects.get que j'essaie de tester. le .get renvoie une erreur si aucune donnée n'est trouvée ... il ne renvoie aucun (ce qui m'énerve)
Utilisez quelque chose comme ceci:
print("result:", try_or(lambda: model.objects.get(), '<n/a>'))
Où try_or est une fonction utilitaire définie par vous:
def try_or(fn, default):
try:
return fn()
except:
return default
Vous pouvez éventuellement limiter les types d’exception acceptés à NameError
, AttributeError
, etc.
Vous avez mentionné que vous utilisez Django. Si cela vous semble judicieux, vous voudrez peut-être utiliser:
my_instance, created = MyModel.objects.get_or_create()
created
sera vrai ou faux. Peut-être que cela vous aidera.
parse_float = lambda x, y=exec("def f(s):\n try:\n return float(s)\n except: return None"): f(x)
Il y a toujours une solution.
En python3, vous pouvez utiliser contextlib.suppress :
from contextlib import suppress
d = {}
with suppress(KeyError): d['foo']
Version de poke53280 avec un nombre limité d’exceptions attendues.
def try_or(func, default=None, expected_exc=(Exception,)):
try:
return func()
except expected_exc:
return default
et il pourrait être utilisé comme
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
si vous avez réellement besoin de gérer des exceptions:
(modifié de la réponse 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
>>>
notez que si l'exception n'est pas prise en charge, elle déclenchera comme prévu:
>>> 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'
>>>
de plus, si Exception
est donné, cela correspondra à tout.
(BaseException
est plus élevé, donc il ne correspondra pas)
>>> try_or( context, {Exception: lambda: print('exception')} )
exception