Python: ifadeyi tek bir satırda dene


97

Python'da bir dene / hariç'i tek bir satıra dönüştürmenin bir yolu var mı?

gibi bir şey...

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

Nerede bbir ilan değişkendir ve cbu yüzden ... değil cbir hata atmak istiyorum ve aolacak b...

Yanıtlar:


63

Python'da a try/ exceptbloğu tek bir satıra sıkıştırmanın bir yolu yoktur .

Ayrıca, diğer bazı dinamik dillerde olduğu gibi Python'da bir değişkenin var olup olmadığını bilmemek kötü bir şeydir. Daha güvenli yol (ve geçerli stil), tüm değişkenleri bir şeye ayarlamaktır. Onlar set almayabilir Eğer bunları ayarlamak Noneilk (ya da 0ya da ''ya da daha uygulanabilir ise bir şey.)


Eğer varsa bunu öncelikle ilgilenen tüm isimleri atama, seçeneklerin var.

  • En iyi seçenek bir if ifadesidir.

    c = None
    b = [1, 2]
    
    if c is None:
        a = b
    else:
        a = c
    
  • Tek satırlık seçenek, koşullu bir ifadedir.

    c = None
    b = [1, 2]
    a = c if c is not None else b
    
  • Bazı insanlar orbunu yapmak için kısa devre yapma davranışını kötüye kullanırlar. Bu hataya meyillidir, bu yüzden asla kullanmam.

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

    Şu durumu düşünün:

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

    Bu durumda, amuhtemelen gerektiğini olmak [], ama öyle [1, 2]çünkü []bir boolean bağlamda yanlıştır. Yanlış olabilecek pek çok değer olduğu için orhile kullanmıyorum . (Bu, insanların demek istediklerini söylediklerinde if foo:karşılaştıkları problemin aynısıdır if foo is not None:.)


Teşekkürler. Sorun şu ki, test etmeye çalıştığım aslında bir django model.objects.get sorgusu. .get veri bulunmazsa bir hata döndürür ... Hiçbiri döndürmez (bu beni rahatsız eder)
Brant

@Brant, Tamam, bu durum bir değişken ayarlanıp ayarlanmadığını kontrol etmekten biraz farklı (Python'da hiçbir değişken bildirilmez). Python'daki tipik stil, istisnaları yükseltmeyi, çoğumuzun gerçekten sevdiği hataları değerler olarak döndürmeye tercih etmektir. Bir işlemin dönüş kodunu her seferinde kontrol etmek zorunda kalmak ve eğer yapmazsam hataları takip etmekte zorlanmak Python yazarken C'yi kesinlikle kaçırmadığım bir şeydir. Her halükarda, tartışılmış olmasına rağmen, a try/ exceptblok için tek satırlık sözdizimi yoktur . Neyse ki hatlar ucuz, bu nedenle 4 hatlı çözüm sizin için çalışmalıdır. ;-)
Mike Graham

Bir emir içindeki büyük bir demet kümesinin parçası ... Sadece işleri biraz kısaltmaya çalışıyordum
Brant

2
getBir istisna istemiyorsanız kullanmayın . filterBunun yerine kullanın .
jcdyer

@MikeGraham İyi cevap - bir ipucu (bağlantı?) Neden kısa devre hataya meyillidir güzel olurdu.
kratenko

85

Bu korkunç bir hack, ancak hata ayıklama için bir dizi eylem yazmak istediğimde bunu hemen kullandım:

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

Çoğunlukla, tek satırlık deneme hariç kısıtlamasından hiç rahatsız değilim, ancak sadece deneme yaptığımda ve readline'ın etkileşimli yorumlayıcıda aynı anda tüm bir kod parçasını hatırlamasını istediğimde bir şekilde ayarlayabildiğim için, bu küçük numara işe yarıyor.

Başarmaya çalıştığınız asıl amaç için deneyebilirsiniz locals().get('c', b); ideal olarak, yerel bağlam yerine gerçek bir sözlük kullanmak veya onu ayarlayabilecek veya ayarlamayacak ne varsa çalıştırmadan önce Yok'a c atamak daha iyi olacaktır.


26
Hey, bu soruyu cevaplıyor! :)
Steve Bennett

4
Bu cevabı seviyorum, çok dağınık, ama bir satır, tam sevdiğim gibi.
Patrick Cook

Cevap bu!! olacak problem[0]şey bu fonksiyon döner dönmek?
SIslam

5
Exec bir kod kokusudur ve başka hiçbir şey işe yaramadıkça bundan kaçınılmalıdır. Bir satır kodu bu kadar önemliyse bu işe yarayacaktır, ancak bir satırın neden bu kadar önemli olduğunu kendinize sormanız gerekir.
Gewthen

4
açıkça üretim kullanımı için değil, ancak garip bir hata ayıklama oturumu için tam olarak gerekli olan şey.
ThorSummoner


13

Başka bir yol da bir bağlam yöneticisi tanımlamaktır:

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

Ardından, withtek bir satırdaki hataları yok saymak için ifadeyi kullanın:

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

Bir çalışma zamanı hatası durumunda hiçbir istisna ortaya çıkmayacaktır. Bu bir gibi try:olmadan except:.


1
Bu harika! Açıkça deneme / dışlama olmadığına göre, bağlam yöneticisinin hatalarla nasıl başa çıktığını kısaca açıklayabilir misiniz?
Patrick

10

Sınırlı beklenen istisnalar ile poke53280 cevabının sürümü.

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

ve şu şekilde kullanılabilir

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

"Beklenen_exc = (İstisna,)" daki virgül ne için? Açıklayabilir misiniz lütfen?
ibilgen

1
virgül dönüştüren bir ifadeyi @ibilgen tuple . Yazmak (Exception), parantezlerin dışarıda bırakılmasına eşittir. (Exception, )tercümana bunun tek girişli bir demet (liste gibi bir şey) olduğunu söyler. Bu örnekte bu kullanıldığından expected_excbirden fazla istisna olabilir.
miile7

7
parse_float = lambda x, y=exec("def f(s):\n try:\n  return float(s)\n except:  return None"): f(x)

Her zaman bir çözüm vardır.


5

Sorun şu ki, test etmeye çalıştığım aslında bir django model.objects.get sorgusu. .get veri bulunmazsa bir hata döndürür ... Hiçbiri döndürmez (bu beni rahatsız eder)

Bunun gibi bir şey kullanın:

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

Try_or sizin tarafınızdan tanımlanan bir yardımcı program işlevi olduğunda:

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

İsteğe bağlı olarak size kabul istisna türü kısıtlayabilir NameError, AttributeErrorvb


5

İki satır kullanmaya ne dersiniz? tamam mı ?

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

4

Sen kullanarak ad dicti erişerek bunu yapabilirsiniz vars(), locals()veya globals()durumunuza en uygun hangisi.

>>> b = 'some variable'
>>> a = vars().get('c', b)

3
Bu, bir değişkenin ayarlanıp ayarlanmadığını kontrol etmekle tamamen aynı şekilde çalışmaz (ancak belirli bir kapsamla ilgileniyorsanız çalışır.) Ayrıca, ewwwwwwww .....
Mike Graham

2

Django kullandığından bahsetmiştin. Yaptığınız şey mantıklıysa, kullanmak isteyebilirsiniz:

my_instance, created = MyModel.objects.get_or_create()

createdDoğru veya Yanlış olacaktır. Belki bu size yardımcı olur.


2

Walter Mundt'tan esinlenerek Python3 üzerinde çalışıyor

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

Çoklu hatlar için tek satıra

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

Ps: Exec, üzerinde kontrolünüz olmayan veriler üzerinde kullanmak güvenli değildir.


1

istisnaları gerçekten yönetmeniz gerekiyorsa:
(poke53280'in cevabından değiştirilmiştir)

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

istisna desteklenmiyorsa, beklendiği gibi artacağını unutmayın:

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

ayrıca Exceptionverilirse, aşağıdaki herhangi bir şeyle eşleşecektir.
( BaseExceptiondaha yüksek, bu yüzden eşleşmeyecek)

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

0

İşte @surendra_ben tarafından sağlanan cevabın daha basit bir versiyonu

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

...

nope

0

withTek satırda sözdizimi kullanın :

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

Hataları göz ardı edin:

with OK(): 1/0

Belirtilen hataları yoksay:

with OK(ZeroDivisionError, NameError): 1/0
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.