Разбор ДЗ

DungeonMap

Вводится карта проходимых в обе стороны тоннелей подземлья в виде строк, содержащих разделённые пробелом названия двух пещер, которые соединяет соответствующий тоннель. Две последние строки не содержат пробелов — это название входа в подземелье и название выхода. Вывести "YES", если из входа можно попасть в выход, и "NO" в противном случае. Пары могут повторяться или содержать одинаковые слова.

   1 Tunnels = {}
   2 From = input()
   3 while " " in From:
   4     From, To = From.split()
   5     Tunnels.setdefault(From,set()).add(To)
   6     Tunnels.setdefault(To,set()).add(From)
   7     From = input()
   8 To = input()
   9 Res, Plan = set(), {From}
  10 while Plan:
  11     New = set()
  12     for e in Plan:
  13         New |= Tunnels[e]
  14     Res |= Plan
  15     Plan = New - Res
  16 print("YES" if To in Res else "NO")

MostPopular

Ввести строку, состоящую из разделённых пробелами последовательностей маленьких и больших латинских букв. Вывести, сколько различных слов (без учёта регистра) встречается в этой строке чаще всего.

   1 Count = {}
   2 for w in input().split():
   3     Count[w.lower()] = Count.get(w.lower(),0)+1
   4 print(tuple(Count.values()).count(max(Count.values())))

Поговорим о понятиях объектно-ориентированного программирования

  1. Инкапсуляция
  2. Наследование
  3. Полиморфизм

Инкапсуляция — ограничение доступа к составляющим объект компонентам (методам и переменным). Инкапсуляция делает некоторые из компонент доступными только внутри класса. В Python инкапсуляция реализована лишь частично. Мы переходим от традиционной схемы к иерархической, т.е. объекты хранятся друг в друге. Чтобы обратится к полю объекта пишем так: объект.поле.

Рассмотрим пример и убедимся, что на самом деле это просто словари.

   1 >>> class C:
   2         pass
   3 
   4 >>> c = C()
   5 >>> dir(c)
   6 ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
   7 >>> c.__dict__
   8 {}
   9 >>> c.field = 100500
  10 >>> c.__dict__
  11 {'field': 100500}
  12 >>> c.field
  13 100500
  14 >>> c.__dict__["ZZZ"]="QQ"
  15 >>> c.ZZZ
  16 'QQ'
  17 >>> c.ZZZ
  18 'QQ'
  19 >>>

Одной из важнейших особенностей ООП является возможность наследования объектами атрибутов классов, а также наследование одними классами атрибутов других классов. На самом деле с наследованием мы уже сталкивались, когда создавали любой объект в Python: объекты наследуют атрибуты класса, хотя могут иметь и индивидуальные.

Python поддерживает полную интроспекцию (отражение) времени исполнения, в том числе интроспекцию типа (type introspection (англ.)). Это означает, что для любого объекта можно получить всю информацию о его внутренней структуре и среде исполнения (т.е,компилятор знает кто и чей производный класс ).

Тип наследования – это классы и подклассы.

Полиморфизм - разное поведение одного и того же метода в разных классах. Например, мы можем сложить два числа, и можем сложить две строки. При этом получим разный результат, так как числа и строки являются разными классами. В Python используется параметрический полиморфизм. В случае параметрического полиморфизма функция реализована для всех классов одинаково, и, таким образом, реализована вообще для произвольного типа данных. Необходимо следить за количеством параметров в этой функции.

Спецметоды и перегрузка операций

Операций над объектами не существует. Это вызов их методов или логика вызовов нескольких методов.

Базовые функции

__dict__() - его задача — хранить пользовательские атрибуты. Он представляет собой dictionary, в котором ключом является имя_атрибута, значением, соответственно, значение_атрибута.

__init__() автоматически при создании объекта создает классу атрибуты. Т.е. вызывать данный метод не нужно, т.к. он сам запускается при вызове класса. (Вызов класса происходит, когда создается объект.)

Первым параметром, как и у любого другого метода, у __init__ является self, на место которого подставляется объект в момент его создания. Второй и последующие (если есть) параметры заменяются аргументами, переданными в конструктор при вызове класса.

__del__() если __new__ и __init__ образуют конструктор объекта, то __del__ это его деструктор. Он не определяет поведение для выражения del x (поэтому этот код не эквивалентен x.__del__()). Скорее, он определяет поведение объекта в то время, когда объект попадает в сборщик мусора. Это может быть довольно удобно для объектов, которые могут требовать дополнительных чисток во время удаления, таких как сокеты или файловыве объекты. Однако, нужно быть осторожным, так как нет гарантии, что __del__ будет вызван, если объект продолжает жить, когда интерпретатор завершает работу.

__str__(self) - вызывается функциями str, print и format. Возвращает строковое представление объекта.

__repr__(self) - вызывается встроенной функцией repr; возвращает "сырые" данные, использующиеся для внутреннего представления в python.

   1 class C:
   2     def __init__(self, per1, per2):
   3         self.val, self.res = per1, per2
   4 
   5     def __str__(self):
   6         return "<{}:{}>".format(self.val, self.res)
   7     def __repr__(self):
   8         return "{}:{} of {}".format(self.val, self.res, type(self))
   9 c = C(12,56)
  10 print(c)

__bytes__(self) - вызывается функцией bytes при преобразовании к байтам.

__bool__ - позволяет определить поведение экземпляра пользовательского типа при проверке на истинность. Возвращает либо True либо False. Когда не определен, вызывается __len__ , если он определен и объект считается истинным, если результат ненулевой.

   1 class C:
   2     def __init__(self, per1, per2):
   3         self.val, self.res = per1, per2
   4 
   5     def __str__(self):
   6         return "<{}:{}>".format(self.val, self.res)
   7     def __repr__(self):
   8         return "{}:{} of {}".format(self.val, self.res, type(self))
   9     def __bool__(self):
  10         return self.val != self.res
  11     def __len__(self):
  12         return self.val + self.res

__getattr__ - позволяет определить поведение экземпляра пользовательского типа при попытке получения значения атрибута. Вызывается в случае, когда значение атрибута не удалось получить обычным способом (не определён ни для экземпляра, ни в иерархии типов данного экземпляра). Метод должен возвращать значение (возможно вычисляемое) для атрибута, либо генерировать исключение.

   1 class C:
   2     def __getattr__(self,attr):
   3         return "NOPE"

__getattribute__ - вызывается при попытке доступа к атрибуту экземпляра класса.

Метод должен вернуть вычисленное значение для указанного атрибута, либо поднять исключение.

__setattr__ - позволяет определить поведение экземпляра пользовательского типа при попытке присвоения значения атрибуту.

__delattr__ - позволяет определить поведение экземпляра пользовательского типа при воздействии на него инструкцией del.

Последовательности и прочие хранилища

__getitem__- позволяет задать поведение при обращении к элементу контейнера (это всего лишь замена квадратных скобок).

__iter__ - позволяет определить механизм прохода (итерирования) по элементам объекта. Данный метод можно определить, например, в пользовательском типе-контейнере и таким образом задать механизм прохода по его элементам, который будет задействован в for in.

   1 class C:
   2     def __getitem__(self, idx):
   3         if type(idx) is int:
   4             return idx%2
   5         elif type(idx) is slice:
   6             return idx.start, idx.stop
   7     def __iter__(self):
   8         return iterr("QWA")

__setitem__ - позволяет задать поведение при инициализации элемента контейнера значением.

__reversed__ - он получает существующую последовательность и возвращает итератор который производит элементы в последовательности в обратном порядке, от последнего к первому.

__contains__- проверка на принадлежность элемента контейнеру (item in self).

Числа

__add__(self, other) - сложение. x + y вызывает x.__add__(y).

   1 class C:
   2     def __init__(self, var):
   3         self.val = var
   4 
   5     def __lt__(self, other):
   6         return self.val < other.val
   7     def __le__(self, other):
   8         return self.val <= other.val
   9     def __add__(self, other):
  10         return C(self.val + other.val)

Замечание: в Python есть умножение строки на число, но он не знает как умножать число на строку. Есть два пути развития события.

  1. Не умножать число на строку.
  2. Я - число, и не знаю как умножить, но вы можете попробовать сами, т.е. вызвать другой метод __r mul__(отраженное умножение).

Есть еще операция 1@2 (матричное умножение), но она не определена ни для одного типа данных.

LecturesCMC/PythonIntro2017/09_Overload/Conspect (последним исправлял пользователь AslanAshabokov 2017-12-29 15:35:08)