ПредишенСледващото

Python отвътре
1. Въведение.
2. обекти. Започнете.
3. обекти. Опашката.

В предишния раздел ние започнахме да изучаваме системата на Python обект: да се разбере това, което може да се счита за един обект, и как техните сайтове за работа. За да продължите разглеждането му.

Приветствия към вас в третата част на нашата поредица от статии за вътрешността на питон (силно ви препоръчваме да прочетете втората част, ако не сте го направили, или нищо не разбират). В този епизод ние говорим за важни понятия, на които не всички ще вдигнат - атрибути. Ако имате нещо написано в Python, а след това сте да ги използвате. атрибути на обекта - това е другият, свързани с нея, съоръжения на разположение чрез operetor. (Точка), например: >>> my_object.attribute_name. Опишете накратко поведението на Python работа атрибути. Това поведение зависи от типа на обекта, който е на разположение на атрибут (вече разбрах, че това се отнася за всички транзакции, свързани с обектите?).

Типът може да се опише чрез специални методи за модифициране достъп до характеристиките на своите копия. Тези методи са описани тук (както вече знаем, те ще бъдат свързани с изисквания вид функционални слота fixup_slot_dispatchers. Което създава вид ... ами четете предишния пост. Не е ли?). Тези методи могат да направят нищо; Притежавате ли тип в С описване или Python, можете да напишете такива методи, които съхраняват и да се върнат на атрибутите на някои невероятни място, ако така желаете, можете да изпращате и получавате атрибути по радиото до МКС или дори да ги съхранявате на релационна база данни. Но в повече или по-малко нормални условия, тези методи просто напишете атрибут под формата на двойки ключ-стойност (атрибут / атрибут стойност на името) във всяка една речника обект, когато атрибута се задава, и да се върнат атрибут от речника, когато това се изисква (или по изключение е хвърлен AttributeError. ако речника не е ключ, съответстващ на исканото име атрибут). Това е толкова просто и перфектно, благодаря ви за вниманието към това, може би, покритие.

Стойка. Моите приятели, изпражнения все още само започнали бързото им подход към въртящите се турбини. Изчезни, защото всички изчезват. Аз предлагам да се разгледа съвместно, което се случва в интерпретатора и да попитам, тъй като правим обикновено, няколко досадни проблеми.

Прочетете внимателно кода или отидете директно в текстовото описание:

Нека да го преведе на човешки език: при обекта (най-лесният вграден тип, ако сте забравили), както виждаме, не е речник и всичко, което можем да се повишила през атрибути, идентични с това, което виждаме в обект .__ dict__. Ние би трябвало да е изненада, че случаите на обекта (например, обект о) не поддържат допълнителни дефиниции на атрибутите и като цяло не са __dict__. но запазване на достъпа до съществуващите атрибути (опитайте о .__ class__ о .__ hash__ др.;. тези команди се върнат нещо). След това, ние създадохме един нов клас В. го наследила от обекта. добавя атрибут А и е установено, че тя е достъпна чрез C.A и С .__ Dict __ [ "А"]. както се очаква. След това ние създадохме инстанция на клас C o2 а и видях, че определението на атрибут променя __dict__. и обратно, промяната засяга __dict__ атрибути. След бяхме изненадани да научат, че __dict__ клас е само за четене, въпреки факта, че определението на атрибути (C.A2) работи добре. И накрая, ние видяхме, че инстанция обект и клас __dict__ различните видове - Dict запознат и тайнствен dict_proxy съответно. И ако това не е достатъчно, не забравяйте, предишната част от пъзела: ако наследниците чист обект (например, о) са __dict__. и С се разширява обект. без да добавя нещо от значение, когато изведнъж се копия на клас C (О2) се появява __dict__?

В този пример, на последния ред показва препратка към типа атрибут. В този случай, за да намерите бар атрибут. функция се нарича за достъп атрибутите на Фу клас (който показва tp_getattro). Приблизително същото се случва в установяването и отстраняването на атрибути (за преводача, между другото, "отстраняване" - това е само за да зададете NULL стойности). Надявам се, че все още, всичко е ясно, но в същото време ние сме обсъждали атрибути за достъп.

Преди да помислите за достъп до атрибутите на копия, позволете ми да ви разкажа за един малко познат (но много важно!) Понятие: ЕВРОВОК. Описания играят специална роля в достъпа до атрибутите на копия, а аз трябва да обясни какво е то. дескриптор обект се счита, ако е един или два слота неговия тип (tp_descr_get и / или tp_descr_set) са изпълнени с ненулеви стойности. Тези слотове са свързани със специални техники __get__. __set__ и __delete__ (например, ако дефинирате клас с метод __get__., който ще се свърже с tp_descr_get слот. и да се създаде обект от този клас, обектът е описание). И накрая, на обекта се счита за да се справят с данните. ако ненулева стойност е изпълнен слот tp_descr_set. Както ще видим, дръжки играят важна роля в достъпа до атрибутите, и ще дам още няколко обяснения и препратки към помощна документация.

Така че, ние разбираме, че тези описания, и да разберат как да получите достъп типовете атрибути. Но повечето от обектите - не видове, т.е. тип им - не пишете. но нещо по-прозаично, например, вътр. Dict или потребителски клас. Всички те разчитат на универсален достъп до функции на атрибутите, които или са дефинирани в типа или наследени от тип родител, когато е създадена (тази тема, наследството на слотове които обсъждахме в "главата"). Алгоритъмът на универсалната жалбата до атрибутите на функцията (PyObject_GenericGetAttr) изглежда така:

  1. Търсене в модел на тип речника и в речниците на всички видове родители. Ако открие дескриптора на данни. причини тя да функционира tp_descr_get и връщане на резултата. Ако сте намерили нещо друго, не забравяйте, че това е само в случай, че (например, под името X).
  2. Търси в обекта речник, и да върне резултат, ако се установи.
  3. Ако не са открити на речника обект нищо проверка Х., ако е бил инсталиран; Ако X - ЕВРОВОК причини тя да функционира tp_descr_get и връщане на резултата. Ако X - обикновен обект, да го върне.
  4. И накрая, ако е намерено нищо, хвърли изключение AttributeError.

Имайте предвид, че ние току-що спечели пълно разбиране на обектно-ориентираното наследство в Python: защото Търсене атрибути започва с вида на обекта, а след това на всички родители, ние разбираме, че обжалването на атрибут на обекта О C1 клас. която се унаследява от С2. което от своя страна е получен от С3. А може да се върне от О. и С1. и С2 и С3. Тя определя, че определен ред на способи, които са добре описани. Този метод позволява атрибутите заедно с наследството на слотовете е достатъчно да се обясни най-на функционалността на наследство в питон (макар дявола, както обикновено, е в детайлите).

Ние сме създали нов клас обект и определя той атрибут (o.foo "бар" =), влезе в GDB. сочен тип обект (С) и намериха tp_dictoffset (16), и след това тествани какъв е, че компенсират в С-структурата на предмета. Не е изненадващо, но открихме, че има речник обект с един ключ Foo. посочване на стойността на бара. Естествено, ако установи, тип tp_dictoffset, че не разполага с __dict__. например в обекта. ние откриваме там е нула. Настръхнеш, нали?

Фактът, че видовете речници и речници екземпляри са сходни, но изпълнението им много различни, може да е объркващо. Все още има няколко мистерии. Нека да обобщим и да определят това, което сме пропуснали: дефиниране на празен клас C наследява от обект. о създаде обект от този клас, допълнителната памет е предназначена за указател към речника tp_dictoffset офсет (мястото, разпределени в началото, но в речника се освобождава само когато първият (който и да е) лечение; това е мошеник.). След това работи в интерпретатора о .__ dict__. компилиран байткод с LOAD_ATTR екип. че нарича функция PyObject_GetAttr. който dereferences тип обект о и намира tp_getattro слот. което води стандартния процес на търсене атрибут описано по-горе и въплътен в PyObject_GenericGetAttr. В крайна сметка, след като всичко това се случва, че един речник на нашето съоръжение? Ние знаем, в която се помещава в речника, но можете да видите, че в __dict__ там себе си, така че не е за кокошката и яйцето проблем: това ни връща към речника, когато ние се обръщаме към __dict__. ако в същия речник, че не е?

Нещо, което е с приоритет над речника обект - от ЕВРОВОК. Виж:

Уау! Vidto, че има нещо, наречено getset_descriptor (./Objects/typeobject.c файл), определена група от функции, осъзнавайки протокола от ЕВРОВОК, както и че трябва да бъде тип обект __dict__. Тази дръжка ще пресече всички опити за достъп до о .__ dict__ обекти от този тип, и ще се върне всичко, което той иска да, в нашия случай, тя ще бъде указател към речника tp_dictoffset промяна в о. Това обяснява и защо видяхме малко по-рано dict_proxy. Ако tp_dict е показалец към обикновен речник, можем да видим защо това е обвито в обект, който не може да бъде всичко, за да пиша? Това прави дръжката __dict__ като нашия вид, тип.

В края на настоящия пример:

Това ЕВРОВОК - функция, която обвива обикновен речник обект, който симулира поведението на конвенционален речник, с изключение на това, че е достъпна само за четене. Защо е толкова важно да се предотврати потребителското тип интервенция __dict__? Тъй като имена от типа пространство може да съдържа специални методи като __sub__. Когато ние създаваме тип със специални техники, или когато ги определят в натура чрез атрибути, извършена update_one_slot функция. които се свързват тези методи тип с прорези, например, както е случаят с операция на изваждане в предишния пост. Ако можем да добавим тези методи директно в __dict__ тип, те не биха влезли във връзка със слотовете, и ние сме получили, ние пишете, което е подобно на това, което трябва (например, той е __sub__ в речника), но който се държи по друг начин ,

И знаеш ли какво? Не само момичета. Ние също сме хора като. Елате при нас. Заедно забавно.

Свързани статии

Подкрепете проекта - споделете линка, благодаря!