'অবশেষে' সর্বদা পাইথনে চালিত হয়?


126

পাইথনের যে কোনও সম্ভাব্য চেষ্টা অবশেষে অবরুদ্ধ করার জন্য, এটির নিশ্চয়তা কি? finally ব্লকটি সর্বদা কার্যকর করা হবে?

উদাহরণস্বরূপ, আসুন আমি বলি যে আমি একটি exceptব্লক থাকাকালীন ফিরে আসছি :

try:
    1/0
except ZeroDivisionError:
    return
finally:
    print("Does this code run?")

অথবা হতে পারে আমি আবার উত্থাপন Exception:

try:
    1/0
except ZeroDivisionError:
    raise
finally:
    print("What about this code?")

পরীক্ষার শোগুলি যা finallyউপরের উদাহরণগুলির জন্য কার্যকর করা হয়, তবে আমি কল্পনা করি যে অন্যান্য পরিস্থিতিতেও আমি ভাবিনি।

finallyপাইথনে কোনও ব্লক কার্যকর করতে ব্যর্থ হতে পারে এমন কোনও দৃশ্য আছে কি?


18
আমি কেবলমাত্র finallyকার্যকর করতে বা "এর উদ্দেশ্যকে পরাভূত করতে" ব্যর্থতা কল্পনা করতে পারি তা অসীম লুপের সময় sys.exitবা জোর করে বাধা দেওয়ার সময়। ডকুমেন্টেশন বলে যে finallyসবসময় মৃত্যুদন্ড কার্যকর হয়, তাই আমি যে তার সাথে যেতে চাই।
জায়ে

1
কিছুটা পার্শ্বীয় চিন্তাভাবনা এবং আপনি যা চেয়েছিলেন তা নিশ্চিত নয়, তবে আমি নিশ্চিত যে আপনি যদি টাস্ক ম্যানেজারটি খোলেন এবং প্রক্রিয়াটি মেরে ফেলেন তবে finallyচলবে না। বা কম্পিউটারটি আগে ক্রাশ হলে একই: ডি
আলেজান্দ্রো

144
finallyযদি দেওয়াল থেকে পাওয়ার কর্ডটি ছিঁড়ে ফেলা হয় তবে তা কার্যকর করা হবে না।
ব্যবহারকারী 253751

3
সি সম্পর্কে একই প্রশ্নের উত্তরের আপনি এই উত্তরটিতে
এরিক লিপার্ট

1
একটি খালি semaphore এ এটি ব্লক করুন। এটি কখনই সংকেত দেবেন না। সম্পন্ন.
মার্টিন জেমস

উত্তর:


206

finallyপ্রাপ্য যে কোনও প্রয়োগের চেয়ে "গ্যারান্টেড" একটি শক্তিশালী শব্দ । গ্যারান্টিযুক্ত যা হ'ল যদি নির্বাহ সম্পূর্ণ try- finallyনির্মাণের বাইরে চলে যায় তবে এটি এটি finallyকরার মধ্য দিয়ে চলে যাবে। যেটির গ্যারান্টি নেই তা হ'ল এক্সিকিউশনটি try- এর বাইরে চলে যাবে finally

  • একটি finallyজেনারেটরের বা ASYNC coroutine চালানোর কখনো পারে , যদি বস্তুর উপসংহার কখনো সঞ্চালন করে। ঘটতে পারে এমন অনেকগুলি উপায় রয়েছে; এখানে একটি:

    def gen(text):
        try:
            for line in text:
                try:
                    yield int(line)
                except:
                    # Ignore blank lines - but catch too much!
                    pass
        finally:
            print('Doing important cleanup')
    
    text = ['1', '', '2', '', '3']
    
    if any(n > 1 for n in gen(text)):
        print('Found a number')
    
    print('Oops, no cleanup.')

    নোট করুন যে এই উদাহরণটি কিছুটা জটিল: জেনারেটর আবর্জনা সংগ্রহ করা হলে পাইথন finallyএকটি GeneratorExitব্যতিক্রম ছুঁড়ে দিয়ে ব্লকটি চালানোর চেষ্টা করে , তবে এখানে আমরা সেই ব্যতিক্রমটি ধরি এবং তারপরে yieldআবার পাই , পাইথন একটি সতর্কতা প্রিন্ট করে ("জেনারেটর জেনারেটর এক্সটাকে উপেক্ষা করে) ") এবং ছেড়ে দেয়। দেখুন PEP 342 (বর্ধিত জেনারেটর মাধ্যমে Coroutines) বিস্তারিত জানার জন্য।

    জেনারেটর বা কর্টিন অন্য উপায়ে সিদ্ধান্তে নির্বাহ করতে না পারে তার মধ্যে অন্তর্ভুক্ত রয়েছে যদি বস্তুটি কখনই জিসি'ড হয় না (হ্যাঁ, এটি সম্ভব, এমনকি সিপিথনেও), অথবা যদি কোনও async with awaitএস ইন __aexit__, বা কোনও ব্লকের মধ্যে অবজেক্টের awaitগুলি বা yieldগুলি থাকে finally। এই তালিকাটি নিখুঁত হওয়ার উদ্দেশ্যে নয়।

  • একটি finallyএকটি ডেমন থ্রেড চালানো কখনোই পারে যদি সমস্ত অ-ডেমন থ্রেড প্রস্থান প্রথম।

  • os._exitfinallyব্লকগুলি কার্যকর না করে প্রক্রিয়াটি অবিলম্বে থামিয়ে দেবে

  • os.forkহতে পারে finallyব্লক চালানো দুইবার । পাশাপাশি দু'বার ঘটে যাওয়া ঘটনা থেকে কেবলমাত্র সাধারণ সমস্যাগুলিই আপনি আশা করতে চেয়েছিলেন, যদি ভাগ করে নেওয়া সংস্থানগুলিতে অ্যাক্সেস সঠিকভাবে সিঙ্ক্রোনাইজ না করা হয় তবে এটি একযোগে অ্যাক্সেস দ্বন্দ্ব (ক্রাশ, স্টল, ...) তৈরি করতে পারে ।

    যেহেতু multiprocessingকাঁটাচামচ ছাড়াই এক্সিকিউট ব্যবহার করে কর্মী প্রক্রিয়া তৈরি করতে কাঁটা শুরু করার পদ্ধতিটি (ইউনিক্সে ডিফল্ট) ব্যবহার করা হয় এবং তারপরে os._exitশ্রমিকের কাজ শেষ হয়ে গেলে কর্মীদের ডেকে আনা হয় finallyএবং multiprocessingমিথস্ক্রিয়া সমস্যাযুক্ত হতে পারে ( উদাহরণস্বরূপ )।

  • সি-লেভেল সেগমেন্টেশন ফল্ট finallyব্লকগুলি চলমান থেকে আটকাবে ।
  • kill -SIGKILLfinallyব্লকগুলি চলমান থেকে আটকাবে । SIGTERMএবং SIGHUPপ্রতিরোধ করবেfinally আপনি নিজে শাটডাউনটি নিয়ন্ত্রণ করতে কোনও হ্যান্ডলার ইনস্টল না করাতে ব্লকগুলি চলতে ; ডিফল্টরূপে পাইথন হ্যান্ডেল করে না SIGTERMবা SIGHUP
  • একটি ব্যতিক্রম finallyক্লিনআপ সম্পূর্ণ হতে বাধা দিতে পারে। একটি বিশেষ লক্ষণীয় কেস হ'ল আমরা যদি ব্লকটি কার্যকর করতে শুরু করি ঠিক একইভাবে ব্যবহারকারী যদি কন্ট্রোল-সিটিকে হিট করে finally। পাইথন একটি উত্থাপন করবে KeyboardInterruptএবং এর প্রতিটি লাইন এড়িয়ে যাবেfinally ব্লকের সামগ্রীর । ( KeyboardInterrupt-সেফ কোডটি লেখা খুব শক্ত)।
  • যদি কম্পিউটার শক্তি হারিয়ে ফেলে, বা যদি হাইবারনেট হয় এবং জেগে না যায়, finally না যায় তবে ব্লকগুলি চলবে না।

finallyব্লক একটি লেনদেন সিস্টেম নয়; এটি পারমাণবিকতা গ্যারান্টি বা সাজানোর কিছু সরবরাহ করে না। এর মধ্যে কয়েকটি উদাহরণ সুস্পষ্ট বলে মনে হতে পারে তবে এ জাতীয় জিনিসগুলি ঘটতে পারে এবং এটি finallyখুব বেশি নির্ভর করতে পারে তা ভুলে যাওয়া সহজ ।


14
আমি বিশ্বাস করি যে আপনার তালিকার প্রথম পয়েন্টটি সত্যই প্রাসঙ্গিক এবং এটি এড়ানোর সহজ উপায় রয়েছে: 1) কখনই কোনও খালি ব্যবহার করবেন exceptনা এবং কোনও GeneratorExitজেনারেটরের অভ্যন্তরে কখনও ধরবেন না । প্রক্রিয়াটি মেরে ফেলা / সেগফোল্টিং / পাওয়ার বন্ধের বিষয়গুলি আশা করা যায়, পাইথন যাদু করতে পারে না। এছাড়াও: ব্যতিক্রমগুলি finallyস্পষ্টতই একটি সমস্যা তবে কন্ট্রোল প্রবাহটি ব্লকে স্থানান্তরিত হয়েছিল তা পরিবর্তন করে না finally। সম্পর্কিত Ctrl+C, আপনি এটিকে উপেক্ষা করে এমন একটি সিগন্যাল হ্যান্ডলার যুক্ত করতে পারেন বা বর্তমান ক্রিয়াকলাপটি সমাপ্ত হওয়ার পরে কেবল একটি ক্লিন শটডাউন "শিডিয়ুলস" করতে পারেন।
গিয়াকোমো আলজেটা

8
কিল -9-এর উল্লেখ প্রযুক্তিগতভাবে সঠিক তবে কিছুটা অন্যায়। কোনও ভাষায় লিখিত কোনও প্রোগ্রাম একটি কিল -9 পাওয়ার পরে কোনও কোড চালায় না। আসলে, কোনও প্রোগ্রাম কখনই একটি কিল -9 পায় না, তাই এটি চাইলেও এটি কোনও কিছুই কার্যকর করতে পারে না। এটি হত্যার পুরো পয়েন্ট -9।
টম

10
@ টম: সম্পর্কে বিন্দুটি kill -9কোনও ভাষা নির্দিষ্ট করে নি। এবং সত্যই, এটি পুনরাবৃত্তি প্রয়োজন, কারণ এটি একটি অন্ধ জায়গায় বসে। অনেক লোক ভুলে যায়, বা বুঝতে পারে না যে তাদের প্রোগ্রামটি পরিষ্কার করার অনুমতি না দিয়েও তাদের ট্র্যাকগুলিতে মারা যাওয়া বন্ধ করা যেতে পারে।
সিএইচও

5
@ জিয়াকোমো অলজিটা: এমন কিছু লোক আছে যারা finallyব্লকের উপর নির্ভর করে যেন তারা লেনদেনের গ্যারান্টি সরবরাহ করে। এগুলি সুস্পষ্ট বলে মনে হতে পারে যে তারা তা করে না তবে এটি এমন কিছু নয় যা প্রত্যেকে উপলব্ধি করে। জেনারেটরের ক্ষেত্রে, জেনারেটরটি মোটেও জিসি'ড না করা যেতে পারে এমন অনেকগুলি উপায় রয়েছে এবং জেনারেটর বা কর্টিন অনেকগুলি উপায়ে দুর্ঘটনাক্রমে উত্পন্ন হতে পারে GeneratorExitএমনকি যদি এটি ধরা নাও দেয় GeneratorExit, উদাহরণস্বরূপ যদি async withস্থগিত হয় একটি coroutine __exit__
ব্যবহারকারী 2357112

2
@ ব্যবহারকারী 2357112 হ্যাঁ - আমি অ্যাপগুলির শুরুতে টেম্প ফাইলগুলি পরিষ্কার করার জন্য ডেভসকে পাওয়ার জন্য কয়েক দশক ধরে চেষ্টা করে এসেছি, প্রস্থান নয়। তথাকথিত 'ক্লিন আপ এবং গ্রেফিউল টার্মিনেশন' এর উপর নির্ভর করে হতাশা এবং অশ্রু চাইছে :)
মার্টিন জেমস

69

হ্যাঁ. অবশেষে সর্বদা জিতে যায়।

এটিকে পরাস্ত করার একমাত্র উপায় হ'ল মৃত্যুদন্ড কার্যকর করার finally:সুযোগ পাওয়ার আগেই মৃত্যুদণ্ড বন্ধ করা (যেমন দোভাষী অনুবাদককে ক্রাশ করা, আপনার কম্পিউটারটি বন্ধ করে দেওয়া, জেনারেটরকে চিরতরে স্থগিত করা)।

আমি ভাবলাম এমন অন্যান্য পরিস্থিতি আছে যা আমি ভেবে দেখিনি।

আপনি আরও কিছু ভেবে নাও নিতে পারেন এখানে আরও কয়েকটি রয়েছে:

def foo():
    # finally always wins
    try:
        return 1
    finally:
        return 2

def bar():
    # even if he has to eat an unhandled exception, finally wins
    try:
        raise Exception('boom')
    finally:
        return 'no boom'

আপনি কীভাবে দোভাষী ছেড়ে চলেছেন তার উপর নির্ভর করে কখনও কখনও আপনি শেষ পর্যন্ত "বাতিল" করতে পারেন, তবে এটির মতো নয়:

>>> import sys
>>> try:
...     sys.exit()
... finally:
...     print('finally wins!')
... 
finally wins!
$

অনিশ্চিত ব্যবহার করে os._exit(এটি আমার মতে "ক্র্যাশ দোভাষী" এর অধীনে আসে):

>>> import os
>>> try:
...     os._exit(1)
... finally:
...     print('finally!')
... 
$

আমি বর্তমানে এই কোডটি চালাচ্ছি, মহাবিশ্বের তাপের মৃত্যুর পরে অবশেষে এখনও কার্যকর করা হবে কিনা তা পরীক্ষা করতে:

try:
    while True:
       sleep(1)
finally:
    print('done')

তবে, আমি এখনও ফলাফলটির জন্য অপেক্ষা করছি, সুতরাং এখানে পরে আবার দেখুন check


5
বা আই সীমাবদ্ধ লুপটি ধরে রাখার চেষ্টা করুন
sapy


27
মহাবিশ্বের তাপের মৃত্যুর পরে সময়টির অস্তিত্ব বন্ধ হয়ে যায়, তাই sleep(1)অবশ্যই অনির্ধারিত আচরণের ফলাফল ঘটে। :-D
ডেভিড ফোস্টার

আপনি সরাসরি "সংক্ষেপে ক্রাশ হ'ল পরাস্ত করার একমাত্র উপায়" এর পরে _os.exit উল্লেখ করতে চাইতে পারেন। এই মুহূর্তে এটি অন্তর্দ্বন্দ্বী উদাহরণগুলিতে মিশ্রিত যেখানে অবশেষে জয়ী হয়।
স্টিভয়েসিয়াক

2
@ স্টিভেনভ্যাসেল্লোরো আমি এটি প্রয়োজনীয় বলে মনে করি না - os._exitএটি সমস্ত ব্যবহারিক উদ্দেশ্যে, ক্র্যাশ (অশুচি প্রস্থান) প্ররোচিত করার মতোই। প্রস্থান করার সঠিক উপায় হ'ল sys.exit
wim

9

মতে পাইথন ডকুমেন্টেশন :

পূর্বে যা ঘটেছে তা বিবেচনা করেই, কোড ব্লক সম্পূর্ণ হয়ে গেলে এবং কোনও উত্থাপিত ব্যতিক্রম হ্যান্ডেল হয়ে গেলে ফাইনাল-ব্লকটি কার্যকর করা হয়। এমনকি যদি কোনও ব্যতিক্রম হ্যান্ডলারের মধ্যে ত্রুটি থাকে বা অন্য-ব্লক হয় এবং একটি নতুন ব্যতিক্রম উত্থাপিত হয়, চূড়ান্ত-ব্লকের কোডটি এখনও চালানো হয়।

এটিও লক্ষ করা উচিত যে যদি শেষ অবধি একটির সাথে একাধিক রিটার্ন স্টেটমেন্ট থাকে তবে শেষ অবধি ব্লক রিটার্নই কেবলমাত্র কার্যকর হবে।


8

ভাল, হ্যাঁ এবং না।

গ্যারান্টিযুক্ত যা হ'ল পাইথন সর্বদা শেষ অবধি কার্যকর করার চেষ্টা করবে। আপনি যেখানে ব্লকটি থেকে ফিরে আসেন বা কোনও অব্যাহত ব্যতিক্রম উত্থাপন করেন সেই ক্ষেত্রে, অবশেষে ফিরে আসা বা ব্যতিক্রম উত্থাপনের ঠিক আগে অবশেষে ব্লকটি কার্যকর করা হয়।

(আপনি নিজের প্রশ্নে কোডটি চালিয়ে যা নিজেকে নিয়ন্ত্রণ করতে পারতেন)

কেবলমাত্র আমি কল্পনা করতে পারি যেখানে অবশেষে ব্লকটি কার্যকর করা হবে না তা যখন পাইথন ব্যাখ্যামূলক নিজে সি কোডের অভ্যন্তরে বা বিদ্যুৎ বিভ্রাটের কারণে ক্র্যাশ করে।


হা হা .. বা চেষ্টা ধরার ক্ষেত্রে একটি অসীম লুপ রয়েছে
sapy

আমি "ভাল, হ্যাঁ এবং না" সর্বাধিক সঠিক বলে মনে করি। পরিশেষে: সর্বদা জয়যুক্ত যেখানে "সর্বদা" অর্থ দোভাষী দৌড়তে সক্ষম হন এবং "অবশেষে:" এর কোডটি এখনও পাওয়া যায় এবং "বিজয়" সংজ্ঞায়িত করা হয় কারণ দোভাষী দেরীটি চালানোর চেষ্টা করবেন: ব্লক এবং এটি সফল হবে। এটি "হ্যাঁ" এবং এটি অত্যন্ত শর্তযুক্ত। "অবশেষে:" এর আগে দোভাষী যেভাবে থামাতে পারে তার সমস্ত উপায় হ'ল - বিদ্যুৎ ব্যর্থতা, হার্ডওয়্যার ব্যর্থতা, হস্তক্ষেপ -9 দোভাষীকে লক্ষ্য করে, অনুবাদক বা কোডটির উপর নির্ভর করে এর উপর নির্ভর করে, অনুবাদককে ফাঁসি দেওয়ার অন্যান্য উপায়। এবং "অবশেষে:" এর ভিতরে ঝুলে থাকার উপায়গুলি।
বিল IV

1

আমি একটি জেনারেটর ফাংশন ব্যবহার না করে এটি পেয়েছি:

import multiprocessing
import time

def fun(arg):
  try:
    print("tried " + str(arg))
    time.sleep(arg)
  finally:
    print("finally cleaned up " + str(arg))
  return foo

list = [1, 2, 3]
multiprocessing.Pool().map(fun, list)

ঘুম এমন কোনও কোড হতে পারে যা অসম্পূর্ণ সময়ের জন্য চলতে পারে।

এখানে যা ঘটছে বলে মনে হচ্ছে তা হ'ল প্রথম সমান্তরাল প্রক্রিয়াটি চেষ্টা ব্লকটিকে সফলভাবে ছেড়ে দেয়, তবে তারপরে কোনও মান (foo) ফাংশন থেকে ফিরে আসার চেষ্টা করে যা কোথাও সংজ্ঞায়িত হয়নি, যা একটি ব্যতিক্রম ঘটায়। এই ব্যতিক্রমটি অন্য প্রক্রিয়াগুলি তাদের অবশেষে অবরুদ্ধ হওয়ার অনুমতি না দিয়ে মানচিত্রটিকে হত্যা করে।

এছাড়াও, আপনি লাইন যোগ করুন bar = bazz চেষ্টা ব্লকে ঘুম () কল করার ঠিক পরে । তারপরে এই রেখায় পৌঁছানোর প্রথম প্রক্রিয়াটি একটি ব্যতিক্রম ছুঁড়ে দেয় (কারণ বাজ নির্ধারিত নয়), যার ফলে এটি শেষ পর্যন্ত নিজের ব্লকটি চালিত করে, কিন্তু তারপরে মানচিত্রটি মেরে ফেলে, ফলে অন্য প্রচেষ্টাগুলি ব্লকগুলি তাদের শেষ অবধি পৌঁছনোর পরে অদৃশ্য হয়ে যায়, এবং প্রথম প্রক্রিয়াটি তার রিটার্নের বিবৃতিতে পৌঁছাতে না পারে।

পাইথন মাল্টিপ্রসেসিংয়ের এর অর্থ যা হ'ল আপনি যদি কোনও প্রক্রিয়াতেও ব্যতিক্রম থাকতে পারেন তবে সমস্ত প্রক্রিয়াতে সংস্থান পরিষ্কার করতে ব্যতিক্রম হ্যান্ডলিং প্রক্রিয়াটিকে আপনি বিশ্বাস করতে পারবেন না। মাল্টিপ্রসেসিং ম্যাপ কলের বাইরে অতিরিক্ত সংকেত পরিচালনা বা সংস্থানগুলি পরিচালনা করা প্রয়োজন হবে।


-2

গ্রহণযোগ্য উত্তরের সাথে সংযোজন, কয়েকটি উদাহরণ সহ এটি কীভাবে কাজ করে তা দেখার জন্য:

  • এই:

     try:
         1
     except:
         print 'except'
     finally:
         print 'finally'

    আউটপুট হবে

    পরিশেষে

  •    try:
           1/0
       except:
           print 'except'
       finally:
           print 'finally'

    আউটপুট হবে


    শেষ পর্যন্ত ছাড়া


এটি প্রশ্নের কোনও উত্তর দেয় না। এটি কখন কাজ করে তার উদাহরণ রয়েছে ।
জিক্সুয়ান
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.