Neden bir yan tümce içinde `ya da` kullanmak SyntaxError'a neden olmaz? Bunun için geçerli bir kullanım var mı?


11

İş exceptyerinde, bir oroperatörle bir maddeye rastladım :

try:
    # Do something.
except IndexError or KeyError:
    # ErrorHandling

İstisna sınıflarının bir demet olarak geçmesi gerektiğini biliyorum, ama bunun bir neden bile olmayacağı beni rahatsız etti SyntaxError.

İlk olarak gerçekten işe yarayıp yaramadığını araştırmak istedim. Ve öyle değil.

>>> def with_or_raise(exc):
...     try:
...         raise exc()
...     except IndexError or KeyError:
...         print('Got ya!')
...

>>> with_or_raise(IndexError)
Got ya!

>>> with_or_raise(KeyError)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in with_or_raise
KeyError

Bu yüzden ikinci istisnayı yakalamadı ve bayt koduna baktığımızda, neden daha açık hale geliyor:

>>> import dis
>>> dis.dis(with_or_raise)
  2           0 SETUP_EXCEPT            10 (to 12)

  3           2 LOAD_FAST                0 (exc)
              4 CALL_FUNCTION            0
              6 RAISE_VARARGS            1
              8 POP_BLOCK
             10 JUMP_FORWARD            32 (to 44)

  4     >>   12 DUP_TOP
             14 LOAD_GLOBAL              0 (IndexError)
             16 JUMP_IF_TRUE_OR_POP     20
             18 LOAD_GLOBAL              1 (KeyError)
        >>   20 COMPARE_OP              10 (exception match)
             22 POP_JUMP_IF_FALSE       42
             24 POP_TOP
             26 POP_TOP
             28 POP_TOP

  5          30 LOAD_GLOBAL              2 (print)
             32 LOAD_CONST               1 ('Got ya!')
             34 CALL_FUNCTION            1
             36 POP_TOP
             38 POP_EXCEPT
             40 JUMP_FORWARD             2 (to 44)
        >>   42 END_FINALLY
        >>   44 LOAD_CONST               0 (None)
             46 RETURN_VALUE

Gördüğümüz gibi, talimat 14 önce IndexErrorsınıfı yığına yükler . Daha sonra bu değerin TruePython gerçeği nedeniyle olup olmadığını kontrol eder ve nihayet doğrudan exception matchyapıldığı talimat 20'ye atlar . Talimat 18 atlandığından, KeyErrorasla yığına yüklenmedi ve bu nedenle eşleşmiyor.

Aynı sonucu Python 2.7 ve 3.6 ile denedim.

Peki, neden geçerli bir sözdizimi? Aşağıdakilerden biri olduğunu hayal ediyorum:

  1. Python'un gerçekten eski bir versiyonundan gelen bir eser.
  2. Aslında orbir exceptcümle içinde kullanmak için geçerli bir kullanım durumu vardır .
  3. Python ayrıştırıcısının, exceptanahtar kelimeden sonra herhangi bir ifadeyi kabul etmesi gerekebilecek bir sınırlamasıdır .

Benim oyum 3 (Python için yeni bir ayrıştırıcı hakkında bazı tartışmalar gördüm verilen) ancak birisinin bu hipotezi doğrulayabileceğini umuyorum. Çünkü mesela 2 ise, bu kullanım durumunu bilmek istiyorum!

Ayrıca, bu araştırmaya nasıl devam edeceğim konusunda da biraz fikrim yok. CPython ayrıştırıcısının kaynak kodunu kazmak zorunda kalacağımı hayal ediyorum ama idk'i nerede bulabilirim ve belki daha kolay bir yol var mı?

Yanıtlar:


7

İçinde except e, egeçerli herhangi bir Python ifadesi olabilir:

try1_stmt ::=  "try" ":" suite
               ("except" [expression ["as" identifier]] ":" suite)+
               ...

[..] İfadeli bir exceptcümle için bu ifade değerlendirilir ve sonuçta ortaya çıkan nesne istisna ile "uyumlu" ise, fıkra istisna ile eşleşir. Bir nesne, istisna nesnesinin sınıfı veya temel sınıfı veya istisna ile uyumlu bir öğe içeren bir demetse istisna ile uyumludur.

https://docs.python.org/3/reference/compound_stmts.html#the-try-statement

İfade IndexError or KeyErrordeğeri verir IndexError. Yani bu şuna eşittir:

except IndexError:
   ...

Bu hızlı aydınlatma cevabı için teşekkürler! Bazı şeyleri çok fazla kısıtlamamak için ayrıştırıcının bir sınırlaması (yani yalnızca daha spesifik bir ifade yerine herhangi bir ifadeyi kabul edebilmek) veya kasıtlı bir seçim olarak düşünebilir miyiz?
Loïc Teixeira

1
Bana göre daha basit olmanın temel Python prensiplerine bağlı kalıyorum. Herhangi bir ifadeyi kabul ederken, sadece sınırlayıcı olabilecek yeni kurallar neden yeni özel durumlar olmadan tam özgürlük anlamına gelir?
deceze

Dinamik olarak yakalamak için bir grup istisna oluşturmaya izin veren ve bir exceptifadede böyle bir değer kullanarak kasıtlı bir seçimdir .
user4815162342

Olasılıkları sınırlamanın sebebi, geliştiricilerin amaçladıkları şeyi yapmayan kod yazmalarını engellemektir. Sonuçta, except IndexError or KeyErroryazmak yazmak için iyi bir şey gibi görünüyor. Bununla birlikte, Python'un saygı duymaya çalıştığı diğer bazı değerlere karşı olacağını kabul ediyorum.
Loïc Teixeira

Ayrıca var == 1 or 2, python'un eğitimsiz göze "yazmak için iyi bir şey gibi" de izin verdiğini unutmayın .
Eric

-2

Mantıksal ifade yerine (yalnızca ilk yanlış olmayan öğeyi döndüren) bir n-tuple türü kullanmalısınız:

def with_or_raise(exc):
  try:
    raise exc()
  except (IndexError,KeyError):
    print('Got ya!')

Soruda belirtildiği gibi, istisna sınıflarının bir demet olarak geçmesi gerektiğini biliyorum ama neden orhala geçerli Python olduğunu merak ediyordum .
Loïc Teixeira
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.