Поиск по блогу

воскресенье, 5 января 2014 г.

Упражнения к Главе 26 "Основы программирования классов" книги М.Лутца...

Как получилось, что я решил изучать ООП по такой "длинной" книге? Не могу понять. Но с этой главы начались конспекты по теме "классы в Питон".
Здесь собраны простейшие примеры... Вот здесь можно посмотреть первоисточник книги М.Лутца "Изучаем Питон" (2011 pdf)
In [6]:
# Первый пример (стр. 711)
class C1(): # Создать и связать класс C1
  def setname(self, who): # Присвоить: C1.setname
    self.name = who # self – либо I1, либо I2 
I1 = C1() # Создать два экземпляра
I2 = C1()
I1.setname('bob') # Записать ‘bob’ в I1.name
I2.setname('mel') # Записать ‘mel’ в I2.name
I1.name # Выведет ‘bob’
Out[6]:
'bob'

Поговорим о объектах "класс" и немного об "экземплярах класса" - это другие объекты

Самый простой в мире класс на языке Python (стр. 721)

In [26]:
class rec: pass # Объект пустого пространства имен
... мы можем приступать к присоединению атрибутов, выполняя операции присваивания из-за пределов класса:
In [31]:
rec.name = 'Bob' # Так же для объектов с атрибутами
rec.age = 40
In [33]:
rec.age
Out[33]:
40
Классы – это полноценные объекты, даже если нет ни одного экземпляра. Фактически они всего лишь самостоятельные пространства имен, поэтому, пока у нас имеется ссылка на класс, мы можем в любое время добавлять или изменять его атрибуты по своему усмотре- нию. Однако посмотрим, что произойдет, когда будут созданы два экземпляра класса:
In [35]:
x = rec() # Экземпляры наследуют имена из класса
y = rec()
In [36]:
x.name, y.name # Сейчас имена хранятся только в классе
Out[36]:
('Bob', 'Bob')
In [38]:
x.name = 'Sue' # Но присваивание изменит только объект x 
rec.name, x.name, y.name
Out[38]:
('Bob', 'Sue', 'Bob')
Например, в большинстве объектов, созданных на базе классов, имеется атрибут __dict__, который является словарем пространства имен (некоторые классы могут также определять атрибуты в __slots__
In [39]:
rec.__dict__.keys()
Out[39]:
['age', '__module__', '__doc__', 'name']
In [40]:
x.__dict__.keys()
Out[40]:
['name']
In [41]:
list(x.__dict__.keys()) # В Python 2.6 функцию list() можно не использовать
Out[41]:
['name']
In [42]:
list(y.__dict__.keys())
Out[42]:
[]
Здесь в словаре класса присутствуют атрибуты name и age, которые мы создали ранее, объект x имеет свой собственный атрибут name, а объект y по-прежнему пуст. Каждый экземпляр имеет ссылку на свой наследуемый класс, она называется __class__, если вам захочется проверить ее:
In [43]:
x.__class__
Out[43]:
__main__.rec
Классы также имеют атрибут __bases__, который представляет собой кортеж его суперклассов:
In [44]:
rec.__bases__ # () пустой кортеж в Python 2.6
Out[44]:
()
Эти два атрибута описывают, как деревья классов размещаются в памяти. Главное, что следует из этого взгляда на внутреннее устройство, это то, что модель классов в языке Python чрезвычайно динамична. Классы и экземпляры – это всего лишь объекты пространств имен с атрибутами, создаваемыми на лету с помощью операции присваивания. Обычно эти операции присваивания выполняются внутри инструкции class, но они могут находиться в любом другом месте, где имеется ссылка на один из объектов в дереве. Даже методы, которые обычно создаются инструкциями def, вложенными в инструкцию class, могут создаваться совершенно независимо от объекта класса. Например, ниже определяется простая функция вне какого-либо класса, которая принимает единственный аргумент:
In [46]:
def upperName(self):
    return self.name.upper() # Аргумент self по-прежнему необходим
Здесь еще ничего не говорится о классе – это простая функция и она может вызываться как обычная функция при условии, что объект, получаемый ею, имеет атрибут name (в данном случае имя аргумента self не имеет никакого особого смысла).
In [47]:
upperName(x) # Вызов, как обычной функции
Out[47]:
'SUE'
Однако, если эту простую функцию присвоить атрибуту нашего класса, она станет методом, вызываемым из любого экземпляра (а также через имя самого класса при условии, что функции вручную будет передан экземпляр):
In [48]:
rec.method = upperName
Фактически это одна из причин, почему в языке Python аргумент self всегда должен явно объявляться в методах, – потому что методы могут создаваться как простые функции, независимо от классов, и им необходим явный аргумент со ссылкой на подразумеваемый экземпляр. В противном случае интерпретатор не смог бы обеспечить превращение простой функции в метод класса. Однако основная причина, по которой аргумент self объявляется явно, заключается в том, чтобы сделать назначение имен более очевидным. Имена, к которым обращаются не через аргумент self, являются простыми переменными, тогда как имена, обращение к которым происходит через аргумент self, очевидно являются атрибутами экземпляра
In [49]:
x.method() # Вызвать метод для обработки x
Out[49]:
'SUE'
In [50]:
rec.method(x) # Можно вызвать через имя экземпляра или класса
Out[50]:
'SUE'
In [51]:
y.method() # То же самое, но в self передается y
Out[51]:
'BOB'
Обычно заполнение классов производится внутри инструкции class, а атрибуты экземпляров создаются в результате присваивания значений атрибутам аргумента self в методах. Однако отметим снова, что все это не является обязательным, поскольку ООП в языке Python – это в основном поиск атрибутов во взаимосвязанных объектах пространств имен.
In []:

In [13]:
class FirstClass:           # Определяет объект класса
    def setdata(self, value): # Определяет метод класса
        self.data = value     # self – это экземпляр
    def display(self):
        print(self.data)      # self.data: данные экземпляров
Как мы уже знаем, инструкции def в действительности являются операциями присваивания – в данном случае они присваивают объекты функций именам setdata и display в области видимости инструкции class и тем самым создают атрибуты, присоединяемые к классу: FirstClass.setdata и FirstClass.display. Фактически любое имя, которому присваивается значение на верхнем уровне во вложенном блоке класса, становится атрибутом этого класса.
In [14]:
x = FirstClass() # Создаются два экземпляра
y = FirstClass() # Каждый является отдельным пространством имен
In [7]:
from IPython.display import Image
Image(filename='C:\\Users\\kiss\\Pictures\\for_blogs\\py_c_fc.PNG')
Out[7]:
In [16]:
x.setdata('King Arthur') # Вызов метода: self – это x
y.setdata(3.14159) # Эквивалентно: FirstClass.setdata(y, 3.14159)
In [17]:
x.display() 
y.display() 
King Arthur
3.14159

In [22]:
x.data, y.data
Out[22]:
('King Arthur', 3.14159)
In [21]:
FirstClass.data
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-21-ef19d1ac0345> in <module>()
----> 1 FirstClass.data

AttributeError: class FirstClass has no attribute 'data'
In []:
x.data = New value # Можно получать/записывать значения атрибутов
x.display()          # И за пределами класса тоже
In []:
x.anothername = spam # Здесь также можно создавать новые атрибуты
In []:
class FirstClass: # Определяет объект класса
    def setdata(self, value): # Определяет метод класса
        self.data = value # self – это экземпляр
    def display(self): 
        print(self.data) # self.data: данные экземпляров
In []:
x = FirstClass() # Создаются два экземпляра
y = FirstClass() # Каждый является отдельным пространством имен

Классы – это атрибуты в модулях (стр. 714)

In []:
> class SecondClass(FirstClass): # Наследует setdata
    def display(self): # Изменяет display
        print(Current value = %s”’ % self.data)
In []:
z = SecondClass()
z.setdata(42) # Найдет setdata в FirstClass
z.display() # Найдет переопределенный метод в SecondClass

Комментариев нет:

Отправить комментарий