What are Metaclasses in Python?
Ի՞նչ է metaclass-ը, և ինչո՞ւ է պետք իմանալ metaclass-ների մասին։ Metaclass-ները էզոթերիկ OOP հայեցակարգեր են, որոնք թաքնված են գրեթե բոլոր Python֊ական կոդերի ներսում: Մենք դրանք օգտագործում եք անկախ նրանից տեղյա՞կ ենք, թե՞ ոչ: Ծրագրավորման աշխարհում քիչ լեզուներ են ապահովում այս հայեցակարգը։ Կան լեզուններ, որոնք չունեն metaclass հասկացությունը։ Այնուամենայնիվ, Python-ը ապահովում է metaclass-ի գաղափարը։
Իրականում, հաճախ ասում են, որ Python-ում ամեն ինչ օբյեկտ է:
Այսպիսով, Python-ը լիովին հասկանալու համար պետք է հասկանալ նրա հիմքում ընկած կառույցները(ինչպիսիք են object֊ները և class֊ները), որպեսզի կարողանանք հասկանալ, թե իրականում ինչ է կատարվում կոդի ներսում: Օբյեկտը, իհարկե, class-ի նմուշ է, և երբ լսում են, որ Python-ում ամեն ինչ object է, հետաքրքրասերների(որոնք մենք ենք) մտքում հարց է ծագում(ճի՞շտ է), այն է՝ եթե class-ները նաև object-ներ են, ապա ի՞նչն է ստեղծում class-ը:
Հասկանում եմ՝ բարդ է ըմբռնել միանգամից, բայց, այնումենայնիվ, պիտի փորձենք հասկանալ։Եթե class-ները object-ներ են, որոնք ստեղծում են object-ներ, ապա ինչպե՞ս են կոչվում object-ները, որոնք class-ներ են ստեղծում։ Հավատացեք ինձ, սա հավի կամ ձվի գլուխկոտրուկը չէ, թե որն է առաջինը եղել: Այստեղ կա հստակ պատասխան. նման object-ները կոչվում են metaclass-ներ: Ամենապարզ metaclass-ի տեսակն (type-ն է) այն է, երբ metaclass֊ը(type-ը), որպես մուտքային պարամետր, ընդունում է միայն մեկ պարամետր և վերադարձնում որպես պարամետր փոխանցված object-ի տեսակը(type-ը): Այս դեպքում այն չի աշխատում որպես metaclass: Երբ type-ը ստանում է երեք մուտքային պարամետր, այն գործում է որպես metaclass և ստեղծում է class՝ հիմնվելով փոխանցված պարամետրերի վրա: Որպես պարամետրեր պետք է փոխանցվեն class-ի անվանումը,
“ծնողները “(class-ներ, որոնցից ժառանգումը տեղի է ունենում) և dictionary-ի ատրիբուտներ: Վերջին երկու պարամետրերը կարող են դատարկ լինել:
Բերենք օրինակ՝
Մեզ կվերադարձնի այս արդյունքը՝
<class ‘type’>
0
Ուշադրություն դարձրեք՝ երկրորդ պարամետրը պետք լինի tuple։
Classes and Objects
Առաջին բանը, որ մենք պետք է քննարկենք ՝ object-ների և class-ների փոխհարաբերությունն է(relationship):
Ունեք հետևյալ class-ը։
Մենք ստեղծում ենք դատարկ class, որը չի պարունակում attribute֊ներ և method֊ներ: Այնուհետև մենք այն ներկայացնում ենք population object-ում և վերջում type ֆունկցիայի միջոցով հարցնում ենք, թե որ class-ի ստեղծած նմուշն է(instance)։
Մեզ կվերադարձնի `
<class ‘__main__.Person’>
Այն class-ը, որը ներկայացրել է population object-ը, Person-ն է, և այն սահմանվել է նույն մոդուլում: Լավ, բայց ո՞րն է class-ի տեսակը(type-ը)։ Եկեք փորձենք։
Մեզ կվերադարձնի ՝
<class ‘type’>
<class ‘type’>
<class ‘type’>
Եկեք հիշենք, որ Python-ում ամեն ինչ object է: Class-ները նույնպես object-ներ են: Արդյունքում class-ը պետք է ունենա տեսակ(type)։
Ո՞րն է class-ի տեսակը(type-ը):
Օրինակ ՝
Արդյունքը կլինի՝
<class ‘__main__.Foo’>
<class ‘type’>
x-ի տեսակը(type-ը) Foo class-ն է, բայց Foo-ի տեսակը(type-ը), ինքնին տեսակ է (type է):
Եվս մի օրինակ, որպեսզի ավելի հասկանալի լինի։
Ծրագրի աշխատանքի արդյունքում կվերադարձնի`
<class ‘type’>
<class ‘type’>
<class ‘type’>
<class ‘type’>
<class ‘type’>
Տեսակը(type-ը) metaclass է, որի class-ները նմուշներ են(instances):
Եկեք հասկանանք վերևում բերված օրինակը՝
1.x-ը Foo class-ի նմուշ է(instance),
2.Foo-ն հանդիսանում է metaclass տիպի նմուշ(instance),
3.type-ը նաև metaclass֊ի նմուշ է(instance), ուստի այն ինքնին նմուշ է(instance):
Այս գծապատկերը կօգնի մի փոքր ավելի լավ հասկանալ․
Հետաքրքիր է չէ՞ ՝ class-ի տեսակը(type-ը) տեսակ է(type)։Դա պայմանավորված է նրանով, որ այն մեզ հայտնի է որպես metaclass։ Metaclass-ը ստեղծում է class-ների նմուշներ(instances) այնպես,ինչպես class-ները ստեղծում են object-ի նմուշներ(instances)։
Հարց է առաջանում,թե մենք ինչպես կարող ենք այն օգտագործել։
Եկեք հասկանանք՝ որ դեպքում կօգտագործենք։Քանի որ metaclass-ը որոշակի քայլերով class է ստեղծում, կարող է օգտակար լինել, եթե մենք կարողանանք մուտք գործել ու մանիպուլացնել այդ գործընթացը(process-ը) և դրանով իսկ ստեղծել մեր սեփական metaclass-ը, որը class-ները կստեղծի այլ կերպ(ոչ այնպես, ինչպես type-ը)։Սա մի փոքր նման է decorator-ին։ Decorator-ները Python-ում մեզ հնարավորություն են տալիս մանիպուլյացիայի ենթարկել function-ները նախքան դրանք կանչելը։ Իրականում, ինչպես կտեսնենք, այդ երկուսը շատ ընդհանրություններ ունեն:
Metaclass-ը հենց class-ի blueprint-ն է, ճիշտ այնպես, ինչպես class-ը՝ այդ class-ի նմուշների(instances) blueprint-ը:
Default metaclass-ը type է և բոլոր metaclass-ները պետք է բխեն տիպից(type-ից):
Class instantiations
Առաջին բանը, որ պետք է հասկանալ metaclass-ների մասին խոսելիս, այն է, թե ինչպես է Python-ում class-ը կառուցվում default metaclass տիպով (type-ով):Երբ class-ը ստեղծվում է, Python-ը վերցնում է որոշ փոփոխականներ, ինչպիսիք են class-ի անվանումը և բազային class-ները, որոնցից class-ը ժառանգում է, և հիմնականում կառուցում է dictionary՝ կանչելով dunder մեթոդը __prepare__ անունով: Այնուհետև class-ի մարմինը գործարկվում է, որպեսզի dictionary-ին լրացվի attribute-ներով և method-ներով:
Վերջին քայլը ստեղծվող class-ին անվանում ,ինչպես նաև բազային class-ները և վերը նշված dictionary-ն որպես պարամետր տալն է։
Այն հետևյալն է`
Person = type(‘Person’, (Base1, Base2), cls_dict)
Person object-ն այժմ class է, որը ժառանգում է իր ծնողներից՝ Base1֊ից և Base2֊ից, և ունի cls_dict-ով սահմանված attribute-ներ ու method-ներ:
Եթե մենք նորից ստեղծեինք Person կոչվող դատարկ class-ը, ապա կարող էինք այն դինամիկ կերպով անել այսպես`
Person = type(‘Person’, (), {})
Կարծում եմ, որ կարևոր է իմանալ Python-ի ներքին աշխատանքը, որպեսզի հասկանանք, թե ինչ է կատարվում կոդի տակ, և իմանանք՝ երբ օգտագործել ճիշտ գործիքները աշխատանքի համար: Եթե ունենք շատ class-ներ, որոնք ունեն ընդհանուր բազային class, ապա metaclass-ը անպայման կներթափանցի ժառանգման միջոցով :
Singleton class-ի իրականացումը Python-ում Metaclass-ների միջոցով․
Ծրագրի արդյունքը կլինի հետևյալը․
TRUE
MYSQL 3306
ORACLE 3306
Class-Factory
Metaclass-ը հիմնականում օգտագործվում է որպես class-factory։ Երբ ստեղծում ենք օբյեկտ՝ կանչելով class-ը, Python-ը ստեղծում է նոր class՝ կանչելով metaclass-ը։ Օգտագործենք type-ը, ստեղծենք դինամիկ class-ներ:
Բերենք օրինակ ՝
Այս ծրագրի աշխատանքի արդյունքում մեզ կվերադարձվի․
red
Բայց այս օրինակում մենք չենք կարողանա նորից օգտագործել init և getColor ֆունկցիաները, այդ նպատակով օգտագործում ենք class-factory-ի մոտեցումը։ Բերենք մի օրինակ, որ ավելի պարզ լինի․
Մեզ կվերադարձնի՝
red
__new__ և __init__
Metaclass-ները կարող են սահմանվել նաև ներքևում ներկայացված երկու եղանակներից մեկով:
__new__-ն օգտագործվում է, երբ ցանկանում ենք սահմանել dict կամ ստեղծել tuples՝ նախքան class-ի ստեղծումը: __new__-ի վերադարձի արժեքը սովորաբար cls-ի օրինակ է(instance): Իսկ __init__-ը, սովորաբար, կանչվում է այն բանից հետո, երբ object-ը ստեղծվել է, որպեսզի այն սկզբնավորվի:
Metaclass-ում կա նաև __call__ մեթոդ։ Մենք կարող ենք նաև վերասահմանել class-ի այլ մեթոդներ՝ մետակլասում սահմանելով հատուկ __call__() մեթոդ, որը թույլ է տալիս հատուկ վարքագիծ, երբ class-ը կանչվում է:
Հուսով եմ, որ այս հոդվածը Ձեզ համար օգտակար էր:
Շնորհակալություն։