Ծրագրի իրագործման ժամանակ կարող են սխալներ ի հայտ գալ, իսկ Python-ում բացառությունները կիրառվում են որպես սխալներին արձագանքելու միջոց։ Python-ն ունի բազմաթիվ ներկառուցված բացառություններ, օրինակ՝ IndexError-ը, երբ փորձում եք հասանելիություն ստանալ ինդեքսին, որը գոյություն չունի ցուցակում, կամ TypeError-ը, երբ փորձում եք գործողություն կատարել այնպիսի տեսակի վրա, որը տվյալ դեպքում կիրառելի չէ: Երբեմն, սակայն, կարող է օգտակար լինել սահմանել մեր սեփական բացառությունները: Սա մեզ թույլ է տալիս գրել սխալը նկարագրող օգտակար հաղորդագրություններ և աշխատել այնպիսի դեպքերի հետ, երբ ներկառուցված բացառությունները կիրառելի չեն: Կարգավորվող բացառությունները ստեղծվում են՝ սահմանելով նոր class, որը ժառանգում է ներկառուցված Exception class-ից կամ դրա ենթադասերից մեկից:
Դիտարկենք մի ծրագիր, որն աշխատում է տեսական գրադարանային համակարգի հետ։ Այս համակարգում օգտվողին չպետք է թույլ տրվի միաժամանակ ստուգել 5-ից ավելի գիրք: Ահա թե ինչպես կարող ենք տվյալ դեպքի համար ստեղծել կարգավորվող բացառություն.
class TooManyBooksError(Exception): # Define a new exception class
pass
def checkout_books(user, num_books):
if num_books > 5:
# Raise an exception if the user tries to check out more than 5 books
raise TooManyBooksError('You cannot check out more than 5 books at a time.') # Raise our custom exception
# Otherwise, add the books to the user's account.
user.books += num_books
Վերոնշյալ օրինակում, եթե օգտատերը փորձի միաժամանակ ստուգել 5-ից ավելի գիրք, մեր TooManyBooksError-ը raise կիրականացվի սխալի վերաբերյալ հատուկ հաղորդագրությամբ: Եթե բացառություն չկա, ծրագիրը կկանգնի, և վահանակի վրա կտպվի սխալը նկարագրող հաղորդագրությունը:
Մենք կարող ենք «բռնել» այս բացառությունը այնպես, ինչպես ներկառուցված բացառությունները՝ օգտագործելով try / except բլոկները.
try:
checkout_books(user, 7) # Try to check out 7 books.
except TooManyBooksError as e: # Catch our custom exception
print(e) # Print the error message.
Եթե checkout_books(user, 7) տողը raise է անում TooManyBooksError, ծրագիրը «կբռնի» այն և կտպի մեր սխալի հաղորդագրությունը 'You cannot check out more than 5 books at a time.': Այսպիսով, մենք սահուն կերպով կարգավորում ենք սխալը, իսկ ծրագիրը շարունակում է աշխատել:
Ինչպես ցանկացած այլ class-ի դեպքում, մենք բացառության class-ին կարող ենք մեթոդներ ավելացնել: Օրինակ, եկե՛ք ավելացնենք մի մեթոդ, որը հաշվում է, թե օգտվողը քանի գիրք պետք է վերադարձնի, ցանկալի քանակով գրքեր վերցնելու համար.
class TooManyBooksError(Exception):
def __init__(self, attempted, limit=5, checked_out=0):
self.attempted = attempted
self.limit = limit
self.checked_out = checked_out
self.message = f'You tried to check out {self.attempted} books, but the limit is {self.limit} books.'
super().__init__(self.message)
def books_to_return(self):
return self.checked_out + self.attempted - self.limit
Բացառությունը «բռնելուց» հետո մենք կարող ենք կիրառել հետևյալ մեթոդը.
try:
checkout_books(user, 7)
except TooManyBooksError as e:
print(e) # You tried to check out 7 books, but the limit is 5 books.
print(f'You need to return {e.books_to_return()} books.') # You need to return 2 books.
Այսպիսով, կարգավորվող բացառությունները կարող են ունենալ իրենց ատրիբուտներն ու մեթոդները, ինչի շնորհիվ դրանք դառնում են հզոր գործիք՝ սխալները կարգավորելու համար, ընդ որում՝ կարգավորումը կատարվում է այնպես, որ համապատասխանի ձեր ծրագրի պահանջներին և կարիքներին։
Կարգավորվող Բացառությունների Սահմանման Լավագույն Ձևերը
Կարգավորվող Բացառություններ ստեղծելիս շատերի մոտ գայթակղություն է առաջանում սահմանել Exception-ից ժառանգվող դատարկ class և հետո ամեն անգամ, երբ անհրաժեշտ է raise անել բացառությունը, ամբողջ հաղորդագրությունը որպես տող փոխանցել այդ դասին։ Թեև այս մոտեցումը կաշխատի, այն հանգեցնում է կրկնվող կոդի և բարդացնում է բացառության հաղորդագրությունների համահունչ պահպանումը։
Փոխարենը, ավելի արդյունավետ մոտեցում է դինամիկ տվյալները պահպանել բացառության մեջ։ Այսպես, կարելի է բացառության հաղորդագրությունը կառուցել հենց դասի ներսում, ինչը կդարձնի ձեր կոդը ավելի մաքուր և կազմակերպված.
👎 Վատ տարբերակ – հաղորդագրության ամբողջական տեքստը փոխանցել raise անելուց.
class TooManyBooksError(Exception):
pass
# Հետագայում, երբ անհրաժեշտ լինի բարձրացնել բացառությունը:
raise TooManyBooksError('You tried to check out 7 books, but the limit is 5!')
# Սա վատ միտք է հատկապես մեծ պրոյեկտների վրա աշխատելիս
👍 Լավ տարբերակ – փոխանցել միայն դինամիկ տվյալները բացառության դասին.
class TooManyBooksError(Exception):
def __init__(self, attempted, limit=5):
self.attempted = attempted
self.limit = limit
# Հաղորդագրությունը կառուցում ենք հենց class-ի մեջ
self.message = f'You tried to check out {self.attempted} books, but the limit is {self.limit}.'
super().__init__(self.message)
# Բացառությունը բարձրացնելիս պարզապես փոխանցեք պետք եղած տվյալները
raise TooManyBooksError(7)
Առաջադրանք․ տարիքի տվյալների բազա
Մի քաղաքում, որտեղ բոլորը ճանաչում են միմյանց, տեղական իշխանությունները փորձում են տարիքի ստուգման համակարգ ներդնել քաղաքային վայրերում՝ բարերում, ակումբներում և թատրոններում: Անհրաժեշտ է ծրագիր, որը, ունենալով մարդկանց տարիքի մասին տեղեկատվությունը, կընդունի անունները և կվերադարձնի տվյալ մարդու տարիքը:
Մուտքը կառավարվում է ավտոմատ կերպով: Դուք պետք է ստեղծեք find_age(name) ֆունկցիան, որը, ունենալով անունը, կվերադարձնի մարդու տարիքը:
Սակայն քաղաքի տվյալների բազայում ոչ բոլորի անունները կան: Ուստի, եթե ծրագիրը տվյալների բազայում չի կարողանում գտնել որևէ անուն, այն պետք է raise անի հատուկ բացառություն, որը կոչվում է NameNotFoundError, և տպի համապատասխան սխալի մասին հաղորդագրություն՝ {name} not found in the database։ Հաշվի առեք, որ հաղորդագրությունը պետք է ստեղծել հենց NameNotFoundError class-ի մեջ։
Մուտք
Ելք
5
Alice - 24
Bob - 32
Charlie - 21
Daisy - 27
Edgar - 30
Edgar
Edgar - 30
5
Alice - 24
Bob - 32
Charlie - 21
Daisy - 27
Edgar - 30
George
NameNotFoundError: George not found in the database.
Նշում. անվան և տարիքի դեպքում մեծատառերն ու փոքրատառերը կարևոր են։ Հնարավոր է նաև բացատների (space) առկայություն: Մուտքագրված անունը պետք է ճշտորեն համընկնի տվյալների բազայում նշված անվան հետ: