Python'da neden “nihayet” maddesine ihtiyacımız var?


306

İhtiyacımız neden emin değilim finallyiçinde try...except...finallytablolar. Bence bu kod bloğu

try:
    run_code1()
except TypeError:
    run_code2()
other_code()

şu ile aynıdır finally:

try:
    run_code1()
except TypeError:
    run_code2()
finally:
    other_code()

Bir şey mi kaçırıyorum?

Yanıtlar:


422

Erken dönerseniz bir fark yaratır:

try:
    run_code1()
except TypeError:
    run_code2()
    return None   # The finally block is run before the method returns
finally:
    other_code()

Bununla karşılaştır:

try:
    run_code1()
except TypeError:
    run_code2()
    return None   

other_code()  # This doesn't get run if there's an exception.

Farklılıklara neden olabilecek diğer durumlar:

  • Dıştaki bloğun içine bir istisna atılırsa.
  • Bir istisna atılırsa run_code1()ancak bu bir değil TypeError.
  • Gibi diğer kontrol akış tabloları continueve breakbildirimler.

1
şunu deneyin: #x = Merhaba + 20 x = 10 + 20 hariç: print 'blok dışındayım' x = 20 + 30 başka: print 'else bloktayım' x + = 1 nihayet: print 'Sonunda x =% s '% (x)
Abhijit Sahu

89

Kural dışı durumu yakalamasanız bilefinally , bir istisnanın oluşup oluşmadığından bağımsız olarak dosyaların veya kaynakların kapatıldığından veya serbest bırakıldığından emin olmak için kullanabilirsiniz . (Veya bu özel istisnayı yakalamazsanız .)

myfile = open("test.txt", "w")

try:
    myfile.write("the Answer is: ")
    myfile.write(42)   # raises TypeError, which will be propagated to caller
finally:
    myfile.close()     # will be executed before TypeError is propagated

Bu örnekte, withifadeyi kullanmaktan daha iyi olursunuz , ancak bu tür bir yapı diğer kaynak türleri için kullanılabilir.

Birkaç yıl sonra, okuyucuların eğlenceli bulabileceği bir kötüye kullanım hakkında bir blog yazısı yazdım finally.


23

Eşdeğer değiller. Sonunda başka ne olursa olsun kod çalıştırılır. Çalıştırılması gereken temizleme kodu için kullanışlıdır.


15
Finally code is run no matter what else happens... sonsuz bir döngü olmadığı sürece. Veya bir elektrik kesimi. Veya os._exit(). Veya ...
Mark Byers

3
@ Mark Gerçekte, sys.exit normal bir istisna atar. Ancak evet, sürecin hemen sona ermesine neden olan herhangi bir şey, başka hiçbir şeyin yürütülmediği anlamına gelecektir.
Antimon

1
@Antimony: Teşekkürler. Olarak değiştirildi os._exit.
Mark Byers

Sadece bir istisna bulunursa kodun girilmesi durumunda neden temizleme kodunu hariç tutamazsınız diye merak ediyorum.
Stephen Jacob

2
@Stephen Bir kere, try bloğundan dönseniz bile kod çalışır. Bu durumda, hariç cümleye çarpmazsınız.
Antimon

18

Yukarıdaki diğer yanıtlara eklemek için, finallymadde ne olursa olsun yürütülürken, elseyalnızca bir istisna oluşturulmadığı takdirde yan tümce yürütülür.

Örneğin, istisnasız bir dosyaya yazmak aşağıdakileri çıkarır:

file = open('test.txt', 'w')

try:
    file.write("Testing.")
    print("Writing to file.")
except IOError:
    print("Could not write to file.")
else:
    print("Write successful.")
finally:
    file.close()
    print("File closed.")

ÇIKTI:

Writing to file.
Write successful.
File closed.

Bir istisna varsa, kod aşağıdakileri çıkarır (kasıtlı bir hatanın dosyanın salt okunur tutulmasından kaynaklandığını unutmayın.

file = open('test.txt', 'r')

try:
    file.write("Testing.")
    print("Writing to file.")
except IOError:
    print("Could not write to file.")
else:
    print("Write successful.")
finally:
    file.close()
    print("File closed.")

ÇIKTI:

Could not write to file.
File closed.

finallyİstisnadan bağımsız olarak maddenin yürütüldüğünü görebiliriz . Bu yardımcı olur umarım.


2
OP farkı bilmek istediği için soruyu cevaplamayan "nihayet" maddesini kullanmasanız bile bu işe yarardı, iyi bir örnek IOError'dan farklı bir hataya neden olurdu. son olarak, yan tümce bloğu istisna arayana yayılmadan önce yürütülür.
Reda Drissi

2
elseBir şey olduğunu bilmiyordum . Bilmenizde fayda var.
mazunki

8

Kod blokları eşdeğer değildir. finallyEğer fıkra da idare edilecek run_code1()dışındaki bir istisna atar TypeError, ya eğer run_code2()ederken, bir istisna atar other_code()ilk sürümünde bu durumlarda çalışacağı olmaz.


7

İlk örneğinizde, run_code1()olmayan bir istisna ortaya çıkarsa ne olur TypeError? ... other_code()idam edilmeyecek.

Bunu finally:sürümle karşılaştırın : other_code()herhangi bir istisna oluşturulmaksızın yürütülmesi garanti edilir.


7

Belgelerde açıklandığı gibi , bu finallymadde her koşulda gerçekleştirilmesi gereken temizleme eylemlerini tanımlamayı amaçlamaktadır .

Varsa finally, bir 'temizleme' işleyicisi belirtir. try Maddesi her dahil olmak üzere çalıştırılır exceptve elsemaddeleri. Herhangi bir yan tümcede bir özel durum oluşursa ve işlenmezse, özel durum geçici olarak kaydedilir. finallyBloğu icra edilir. Kaydedilmiş bir istisna varsa, bu finally maddenin sonunda yeniden yükseltilir .

Bir örnek:

>>> def divide(x, y):
...     try:
...         result = x / y
...     except ZeroDivisionError:
...         print("division by zero!")
...     else:
...         print("result is", result)
...     finally:
...         print("executing finally clause")
...
>>> divide(2, 1)
result is 2.0
executing finally clause
>>> divide(2, 0)
division by zero!
executing finally clause
>>> divide("2", "1")
executing finally clause
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in divide
TypeError: unsupported operand type(s) for /: 'str' and 'str'

Gördüğünüz gibi, finallymadde herhangi bir olayda yürütülür. TypeErrorİki dizeyi bölerek kaldırdı tarafından ele edilmez exceptmaddesi ve sonrasında bu nedenle istisna tekrar finallybloğu icra edilmiştir.

Gerçek dünya uygulamalarında, nihayet cümlesi, kaynak kullanımının başarılı olup olmadığına bakılmaksızın harici kaynakları (dosyalar veya ağ bağlantıları gibi) serbest bırakmak için yararlıdır.


4

Mükemmel örnek aşağıdaki gibidir:

try:
    #x = Hello + 20
    x = 10 + 20 
except:
    print 'I am in except block'
    x = 20 + 30
else:
    print 'I am in else block'
    x += 1
finally:
    print 'Finally x = %s' %(x)

3

finally"temizlik eylemlerini" tanımlamak içindir . finallyFıkra ayrılmadan önce her halükarda yürütülen trybir istisna (Başedebilir dahi) oluştu içerisinde olup olmadığını, açıklama.

Byers örneğini ikinci olarak verdim.


2

Son olarak, ana işiniz için kodu çalıştırmadan önce "isteğe bağlı" kodu çalıştırmak istediğinizde de kullanılabilir ve isteğe bağlı kod çeşitli nedenlerle başarısız olabilir.

Aşağıdaki örnekte, ne tür istisnaların ortaya store_some_debug_infoçıkabileceğini tam olarak bilmiyoruz .

Koşabiliriz:

try:
  store_some_debug_info()
except Exception:
  pass
do_something_really_important() 

Ancak, çoğu linteri bir istisnadan çok belirsiz yakalamaktan şikayet edecektir. Ayrıca, sadece passhatalar için seçtiğimiz için, exceptblok gerçekten değer katmaz.

try:
  store_some_debug_info()
finally:
  do_something_really_important()     

Yukarıdaki kod, 1. kod bloğu ile aynı etkiye sahiptir, ancak daha özlüdür.


2

Delphi'yi birkaç yıl boyunca profesyonelce kullanmak, nihayet kullanarak temizlik rutinlerimi korumamı öğretti. Delphi, hemen hemen bir bellek sızıntısına neden olmamak için deneyin bloğundan önce oluşturulan kaynakları temizlemek için nihayet kullanımını zorlar. Java, Python ve Ruby de böyle çalışır.

resource = create_resource
try:
  use resource
finally:
  resource.cleanup

ve denemek ve nihayetinde ne yaparsanız yapın kaynak temizlenir. Ayrıca, yürütme hiçbir zaman trybloğa ulaşmazsa temizlenmez . (yani create_resourcekendisi bir istisna atar) Kodunuzu "istisna güvenli" yapar.

Neden sonunda nihayet bir bloğa ihtiyaç duyduğunuza gelince, tüm diller değil. İstisna yığının kilidini açtığında temizlemeyi zorunlu kılan yıkıcıları otomatik olarak çağırdığınız C ++ 'da. Bence bu, denemeye kıyasla daha temiz kod yönünde bir adım. Son olarak diller.

{    
  type object1;
  smart_pointer<type> object1(new type());
} // destructors are automagically called here in LIFO order so no finally required.

2

Bir try bloğunun sadece bir zorunlu maddesi vardır: try ifadesi. Dış, else ve son olarak yan tümceleri isteğe bağlıdır ve kullanıcı tercihine bağlıdır.

son olarak: Python try ifadesinden ayrılmadan önce, programı sonlandırsa bile, herhangi bir koşulda nihayet bloğundaki kodu çalıştırır. Örneğin, Python, dışlama veya başka bir blokta kod çalıştırılırken bir hatayla karşılaşırsa, son durdurma programı durdurmadan önce yine de yürütülür.


1
Bu yanlış. Dışlama ifadesi zorunludur. - Lucas Azevedo 1 Şubat, 12:04 Bu "yanlış" yan tümcesi ile bir try-finally bloğu ile bir Python 3.5 programı derledim ve çalıştırdığınız için yanlıştır.
Rob Tow

2
Bunu kendim ve inanamayarak denedim, ancak fıkra zorunlu değildir.
captainblack

1

Sonunda aşağıdakileri izlemek için bu Python3 kodlarını çalıştırın:

DAVA 1:

count = 0
while True:
    count += 1
    if count > 3:
        break
    else:
        try:
            x = int(input("Enter your lock number here: "))

            if x == 586:
                print("Your lock has unlocked :)")

                break
            else:
                print("Try again!!")

                continue

        except:
            print("Invalid entry!!")
        finally:
            print("Your Attempts: {}".format(count))

Durum 2:

count = 0

while True:
    count += 1
    if count > 3:
        break
    else:
        try:
            x = int(input("Enter your lock number here: "))

            if x == 586:
                print("Your lock has unlocked :)")

                break
            else:
                print("Try again!!")

                continue

        except:
            print("Invalid entry!!")

        print("Your Attempts: {}".format(count))

Her seferinde aşağıdaki girişleri deneyin:

  1. rastgele tamsayılar
  2. doğru kod olan 586 (Bunu deneyin ve cevabınızı alacaksınız)
  3. rastgele dizeler

** Python öğrenmenin çok erken bir aşamasında.


1

Ben excel yaprak okumak istedim bir kod çalıştırmak için çalışıyordu. Sorun, adında hiçbir sayfası olan bir dosya varsa: SheetSum Hata konumuna taşıyamıyorum !! Yazdığım kod:

def read_file(data_file):
    # data_file = '\rr\ex.xlsx'
    sheets = {}
    try:
        print("Reading file: "+data_file)
        sheets['df_1'] = pd.read_excel(open(data_file,'rb'), 'SheetSum')
    except Exception as excpt:
        print("Exception occurred", exc_info=True)
    return sheets

read_file(file)
shutil.move( file, dirpath +'\\processed_files')

Hata Verme:

[WinError 32] Başka bir işlem tarafından kullanıldığından işlem dosyaya erişemiyor

Ben tam try except with finallyblok eklemek ve finallyben gibi herhangi bir durumda dosyayı kapatmanız gerektiğini söylemek zorunda kaldı:

def read_file(data_file):
    # data_file = '\rr\ex.xlsx'
    sheets = {}
    try:
        print("Reading file: "+data_file)
        sheets_file = open(data_file,'rb')
        sheets['df_1'] = pd.read_excel(sheets_file, 'SheetSum')
    except Exception as excpt:
        print("Exception occurred", exc_info=True)
    finally:
        sheets_file.close()
    return sheets

read_file(file)
shutil.move( file, dirpath +'\\processed_files')

Aksi takdirde, dosya hala açık kalır arka plan.

Varsa finally, bir temizleme işleyicisi belirtir . try Maddesi her dahil olmak üzere çalıştırılır exceptve elsemaddeleri. Herhangi bir yan tümcede bir özel durum oluşursa ve işlenmezse, özel durum geçici olarak kaydedilir . finallyBloğu icra edilir. Kaydedilmiş bir istisna varsa, bu finally maddenin sonunda yeniden yükseltilir . Eğer finallyfıkra başka özel durum oluşturur, kaydedilen istisna yeni istisna kapsamında olarak ayarlanır.

..Daha Fazla Burada

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.