Czy w Pythonie jest sposób, aby zamienić try / except w pojedynczą linię?
coś jak...
b = 'some variable'
a = c | b #try statement goes here
Gdzie b
jest zadeklarowaną zmienną i c
nie jest ... więc c
zgłosi błąd i a
stanie się b
...
Odpowiedzi:
W Pythonie nie ma sposobu, aby skompresować try
/ except
blok do jednej linii.
Poza tym źle jest nie wiedzieć, czy w Pythonie istnieje zmienna, tak jak w innych dynamicznych językach. Bezpieczniejszym sposobem (i dominującym stylem) jest ustawienie na coś wszystkich zmiennych. Jeśli mogą nie zostać ustawione, ustaw je jako None
pierwsze ( 0
lub ''
lub coś, jeśli jest to bardziej odpowiednie).
Jeśli zrobić przypisać wszystkie nazwiska jesteś zainteresowany po pierwsze, masz opcje.
Najlepszą opcją jest instrukcja if.
c = None
b = [1, 2]
if c is None:
a = b
else:
a = c
Opcja jednowierszowa jest wyrażeniem warunkowym.
c = None
b = [1, 2]
a = c if c is not None else b
Niektórzy ludzie nadużywają w tym celu zachowania zwarciowego or
. Jest to podatne na błędy, więc nigdy go nie używam.
c = None
b = [1, 2]
a = c or b
Rozważ następujący przypadek:
c = []
b = [1, 2]
a = c or b
W tym przypadku a
prawdopodobnie powinno być []
, ale dzieje się tak , [1, 2]
ponieważ []
jest fałszywe w kontekście logicznym. Ponieważ istnieje wiele wartości, które mogą być fałszywe, nie używam or
sztuczki. (Jest to ten sam problem, na który napotykają ludzie, kiedy mówią, if foo:
kiedy mają na myśli if foo is not None:
).
try
/ except
. Na szczęście linie są tanie, więc rozwiązanie 4-liniowe powinno działać dla Ciebie. ;-)
get
jeśli nie chcesz wyjątku. Użyj filter
zamiast tego.
To strasznie hackerskie, ale użyłem go w zachęcie, gdy chciałem napisać sekwencję działań do debugowania:
exec "try: some_problematic_thing()\nexcept: problem=sys.exc_info()"
print "The problem is %s" % problem[1]
W większości przypadków w ogóle nie przeszkadza mi ograniczenie bez jednej linii-try-z wyjątkiem, ale kiedy tylko eksperymentuję i chcę, aby readline przypomniało sobie cały fragment kodu naraz w interaktywnym interpreteru, więc że mogę to jakoś dostosować, ta mała sztuczka się przydaje.
W celu, jaki chcesz osiągnąć, możesz spróbować locals().get('c', b)
; Idealnie byłoby lepiej użyć prawdziwego słownika zamiast lokalnego kontekstu lub po prostu przypisać c do Brak przed uruchomieniem tego, co może go ustawić lub nie.
problem[0]
wrócić co zwracającej funkcji?
W pythonie3 możesz użyć contextlib.suppress :
from contextlib import suppress
d = {}
with suppress(KeyError): d['foo']
Innym sposobem jest zdefiniowanie menedżera kontekstu:
class trialContextManager:
def __enter__(self): pass
def __exit__(self, *args): return True
trial = trialContextManager()
Następnie użyj with
instrukcji, aby zignorować błędy w jednym wierszu:
>>> 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
Żaden wyjątek nie zostanie zgłoszony w przypadku błędu w czasie wykonywania. To jest jak try:
bez except:
.
Wersja odpowiedzi poke53280 z ograniczonymi oczekiwanymi wyjątkami.
def try_or(func, default=None, expected_exc=(Exception,)):
try:
return func()
except expected_exc:
return default
i może być używany jako
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
parse_float = lambda x, y=exec("def f(s):\n try:\n return float(s)\n except: return None"): f(x)
Zawsze jest rozwiązanie.
Problem polega na tym, że jest to faktycznie zapytanie model.objects.get django, które próbuję przetestować. .get zwraca błąd, jeśli nie znaleziono żadnych danych ... nie zwraca None (co mnie denerwuje)
Użyj czegoś takiego:
print("result:", try_or(lambda: model.objects.get(), '<n/a>'))
Gdzie try_or to zdefiniowana przez Ciebie funkcja narzędziowa:
def try_or(fn, default):
try:
return fn()
except:
return default
Opcjonalnie można ograniczyć Akceptowane formaty wyjątek NameError
, AttributeError
itp
Można to zrobić, korzystając z dict namespace użyciu vars()
, locals()
lub globals()
, w zależności co jest najbardziej odpowiednie dla danej sytuacji.
>>> b = 'some variable'
>>> a = vars().get('c', b)
Co powiesz na użycie dwóch linii. czy to jest w porządku ?
>>> try: a = 3; b= 0; c = a / b
... except : print('not possible'); print('zero division error')
...
not possible
zero division error
jeśli chcesz faktycznie zarządzać wyjątkami:
(zmodyfikowane na podstawie odpowiedzi 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
>>>
zauważ, że jeśli wyjątek nie jest obsługiwany, zostanie podniesiony zgodnie z oczekiwaniami:
>>> 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'
>>>
również jeśli Exception
zostanie podane, będzie pasować do wszystkiego poniżej.
( BaseException
jest wyższa, więc nie będzie pasować)
>>> try_or( context, {Exception: lambda: print('exception')} )
exception
Działa na Pythonie3, inspirowanym twórczością Waltera Mundta
exec("try:some_problematic_thing()\nexcept:pass")
Dla wielu linii w jedną linię
exec("try:\n\tprint('FirstLineOk')\n\tsome_problematic_thing()\n\tprint('ThirdLineNotTriggerd')\nexcept:pass")
Ps: Exec jest niebezpieczny w przypadku danych, nad którymi nie masz kontroli.