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

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:.)


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.


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


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


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

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.


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


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

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)

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.


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.


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

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

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
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.