What are Metaclasses in Python?

Aro Militosyan
Picsart Academy
Published in
6 min readOct 14, 2022

Ի՞նչ է 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-ը կանչվում է:

Հուսով եմ, որ այս հոդվածը Ձեզ համար օգտակար էր:

Շնորհակալություն։

--

--