Python: pernyataan try dalam satu baris

97

Apakah ada cara di python untuk mengubah percobaan / kecuali menjadi satu baris?

sesuatu seperti...

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

Di mana bvariabel yang dideklarasikan dan cbukan ... jadi cakan menimbulkan kesalahan dan aakan menjadi b...

Brant
sumber

Jawaban:

63

Tidak ada cara untuk mengompres try/except blok menjadi satu baris dengan Python.

Juga, adalah hal yang buruk untuk tidak mengetahui apakah sebuah variabel ada di Python, seperti yang Anda lakukan di beberapa bahasa dinamis lainnya. Cara yang lebih aman (dan gaya yang berlaku) adalah mengatur semua variabel menjadi sesuatu. Jika mereka mungkin tidak diatur, atur ke Nonepertama (atau 0atau ''atau sesuatu jika lebih dapat diterapkan.)


Jika Anda melakukan assign semua nama yang Anda tertarik pertama, Anda memiliki pilihan.

  • Pilihan terbaik adalah pernyataan if.

    c = None
    b = [1, 2]
    
    if c is None:
        a = b
    else:
        a = c
    
  • Opsi satu baris adalah ekspresi bersyarat.

    c = None
    b = [1, 2]
    a = c if c is not None else b
    
  • Beberapa orang menyalahgunakan perilaku arus pendek oruntuk melakukan ini. Ini rawan kesalahan, jadi saya tidak pernah menggunakannya.

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

    Pertimbangkan kasus berikut:

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

    Dalam hal ini, amungkin harus menjadi [], tetapi [1, 2]karena []adalah palsu dalam konteks boolean. Karena ada banyak nilai yang bisa salah, saya tidak menggunakan ortriknya. (Ini adalah masalah yang sama yang dialami orang-orang ketika mereka mengatakan if foo:ketika mereka bermaksud if foo is not None:.)

Mike Graham
sumber
Terima kasih. Masalahnya adalah bahwa sebenarnya ini adalah kueri model.objects.get django yang saya coba uji. .get mengembalikan kesalahan jika tidak ada data yang ditemukan ... tidak mengembalikan Tidak ada (yang mengganggu saya)
Brant
@Brant, Oke, situasinya sedikit berbeda dari memeriksa apakah suatu variabel disetel (tidak ada variabel yang dideklarasikan dengan Python). Gaya khas dalam Python adalah lebih suka meningkatkan pengecualian daripada mengembalikan kesalahan sebagai nilai, yang sebenarnya disukai banyak dari kita. Harus memeriksa kode pengembalian suatu operasi setiap waktu dan mengalami kesulitan melacak kesalahan jika saya tidak melakukannya adalah sesuatu yang pasti tidak saya lewatkan tentang C saat menulis Python. Bagaimanapun, meskipun telah dibahas, tidak ada sintaks satu baris untuk blok try/ except. Untungnya garis-garis itu murah, jadi solusi 4-garis cocok untuk Anda. ;-)
Mike Graham
Ini adalah bagian dari sekumpulan besar tupel dalam satu perintah ... Saya hanya mencoba mempersingkat sedikit
Brant
2
Jangan gunakan getjika Anda tidak menginginkan pengecualian. Gunakan filtersebagai gantinya.
jcdyer
@MikeGraham Jawaban yang bagus - petunjuk (tautan?) Mengapa hubungan arus pendek rawan kesalahan akan menyenangkan.
kratenko
85

Ini sangat hackish, tetapi saya telah menggunakannya pada prompt ketika saya ingin menulis urutan tindakan untuk debugging:

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

Untuk sebagian besar, saya sama sekali tidak terganggu oleh batasan no-single-line-try-exception, tetapi ketika saya hanya bereksperimen dan saya ingin readline untuk mengingat seluruh potongan kode sekaligus dalam interpreter interaktif jadi bahwa saya bisa menyesuaikannya entah bagaimana, trik kecil ini berguna.

Untuk tujuan sebenarnya yang ingin Anda capai, Anda dapat mencobanya locals().get('c', b) ; idealnya akan lebih baik menggunakan kamus yang sebenarnya daripada konteks lokal, atau cukup tetapkan c ke None sebelum menjalankan pengaturan may-or-may-not apapun.

Walter Mundt
sumber
26
Hei, ini menjawab pertanyaannya! :)
Steve Bennett
4
Suka jawaban ini, sangat berantakan, tapi satu baris, seperti yang saya suka.
Patrick Cook
Inilah jawabannya !! akan problem[0]mengembalikan apa yang dikembalikan fungsi itu?
SIslam
5
Exec adalah bau kode dan harus dihindari kecuali tidak ada yang berhasil. Jika satu kode baris sangat penting maka ini akan berhasil, tetapi Anda perlu bertanya pada diri sendiri mengapa satu baris begitu penting.
Gewthen
4
jelas bukan untuk penggunaan produksi, tapi persis apa yang dibutuhkan untuk sesi debugging yang canggung.
ThorSummoner
54

Di python3 Anda bisa menggunakan contextlib.suppress :

from contextlib import suppress

d = {}
with suppress(KeyError): d['foo']
dset0x
sumber
8
ini seharusnya menjadi jawaban standar
Sphynx-HenryAY
13

Cara lain adalah dengan mendefinisikan pengelola konteks:

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

Kemudian gunakan withpernyataan tersebut untuk mengabaikan kesalahan dalam satu baris:

>>> 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

Tidak ada pengecualian yang akan dimunculkan jika terjadi error runtime. Ini seperti try:tanpa except:.

bitagoras
sumber
1
Ini bagus! Karena tidak ada percobaan / pengecualian eksplisit, dapatkah Anda menjelaskan secara singkat bagaimana pengelola konteks menangani kesalahan?
Patrick
10

Versi jawaban poke53280 dengan pengecualian yang diharapkan terbatas.

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

dan itu bisa digunakan sebagai

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
sumber
Untuk apa koma di "expected_exc = (Exception,)"? Bisakah Anda menjelaskan?
ibilgen
1
@ibilgen Koma mengubah ekspresi menjadi tupel . Menulis (Exception)sama dengan mengosongkan tanda kurung. (Exception, )memberitahu penerjemah bahwa ini adalah tupel (seperti daftar) dengan satu entri. Dalam contoh ini, ini digunakan sehingga expected_excbisa ada lebih dari satu pengecualian.
miile7
7
parse_float = lambda x, y=exec("def f(s):\n try:\n  return float(s)\n except:  return None"): f(x)

Selalu ada solusi.

Miklos Horvath
sumber
5

Masalahnya adalah bahwa sebenarnya ini adalah kueri model.objects.get django yang saya coba uji. .get mengembalikan kesalahan jika tidak ada data yang ditemukan ... tidak mengembalikan Tidak ada (yang mengganggu saya)

Gunakan sesuatu seperti ini:

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

Di mana try_or adalah fungsi utilitas yang ditentukan oleh Anda:

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

Opsional Anda dapat membatasi jenis pengecualian diterima untuk NameError, AttributeError, dll

poke53280.dll
sumber
5

Bagaimana kalau menggunakan dua baris. apakah itu baik-baik saja

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

Anda dapat melakukannya dengan mengakses dict namespace menggunakan vars(), locals()atau globals(), mana yang paling sesuai untuk situasi Anda.

>>> b = 'some variable'
>>> a = vars().get('c', b)
jcdyer
sumber
3
Ini tidak bekerja persis sama dengan memeriksa apakah suatu variabel disetel (meskipun itu berfungsi jika Anda tertarik pada ruang lingkup tertentu.) Juga, ewwwwwwww .....
Mike Graham
2

Anda menyebutkan bahwa Anda menggunakan django. Jika masuk akal untuk apa yang Anda lakukan, Anda mungkin ingin menggunakan:

my_instance, created = MyModel.objects.get_or_create()

createdakan menjadi Benar atau Salah. Mungkin ini akan membantu Anda.

blokeley
sumber
2

Bekerja pada Python3, terinspirasi oleh Walter Mundt

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

Untuk garis mulitiples menjadi satu baris

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

NB: Exec tidak aman untuk digunakan pada data yang tidak dapat Anda kendalikan.

Punnerud
sumber
1

jika Anda benar-benar perlu mengelola pengecualian:
(dimodifikasi dari jawaban 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
>>> 

perhatikan bahwa jika pengecualian tidak didukung, itu akan muncul seperti yang diharapkan:

>>> 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'
>>> 

juga jika Exceptiondiberikan, itu akan cocok dengan apapun di bawah ini.
( BaseExceptionlebih tinggi, jadi tidak akan cocok)

>>> try_or( context, {Exception: lambda: print('exception')} )
exception
Tcll
sumber
0

Ini adalah versi sederhana dari jawaban yang diberikan oleh @surendra_ben

a = "apple"try: a.something_that_definitely_doesnt_exist
except: print("nope")

...

nope
HashRocketSyntax
sumber
0

Gunakan withsintaks dalam satu baris:

class OK(): __init__ = lambda self, *isok: setattr(self, 'isok', isok); __enter__ = lambda self: None; __exit__ = lambda self, exc_type, exc_value, traceback: (True if not self.isok or issubclass(exc_type, self.isok) else None) if exc_type else None

Abaikan kesalahan apa pun:

with OK(): 1/0

Abaikan kesalahan tertentu:

with OK(ZeroDivisionError, NameError): 1/0
Sakuya
sumber