Kodomo

Пользователь

Учебная страница курса биоинформатики,
год поступления 2013

Классы и объекты

Идея классов заключается в следующем. Мир состоит из объектов, которые имеют некоторые характеристики (атрибуты) и функции. Например, объект класса «человек» характеризуется атрибутами: именем, ростом, цветом глаз, – и может выполнять определённые функции: ходить на работу, спать, кормить кота. Если бы мы описывали систему «мир людей», было бы удобно хранить информацию, относящуюся к одному объекту – человеку, в одном месте, а не в разных списках (для имен, для ростов и т.п.). Класс –- это шаблон, тип данных, который задает, какие у объекта свойства, и что он может делать. В питоне есть множество стандартных классов, и с некоторыми из них вы уже работали: list, Canvas, – но часто бывает удобно определить свой тип данных. Например, если в программе встречаются описания таблиц (графиков, драконов), вероятно, стоит создать класс "таблица" ("график", "дракон").

Создание класса

Класс создаётся следующим образом.

   1 class Boy:
   2     can_fly = False

У класса Boy есть только один параметр и нет функций. Теперь создадим объект peter_pan класса Boy.

   1 peter_pan = Boy()

К атрибуту объекта можно обратиться так: имя_объекта.имя_атрибута.

   1 peter_pan.can_fly = True

Методы класса –- что он может делать, –- пишутся так же, как и обычные функции (def), только одним из входных параметров обязательно должен быть self. Этот параметр нужен для связи с конкретным объектом класса. В примере ниже можно видеть, как одна и та же функция может быть обычной send_to_hogwarts() и методом класса go_to_hogwarts().

   1 def send_to_hogwarts(person):
   2     person.can_use_magic = True
   3 
   4 class Student:
   5     can_use_magic = False
   6     def go_to_hogwarts(self):
   7         self.can_use_magic = True
   8 
   9 ron, harry = Student(), Student()
  10 ron.go_to_hogwarts()
  11 send_to_hogwarts(harry)

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

Пример класса: бактерии

Дальше мы будем работать с классом бактерий: кружочков радиуса r, у которых есть цвет color и плодовитость p. Скачать код примера целиком можно здесь.

   1 import Tkinter
   2 import random
   3 import time
   4 
   5 canvas_size = 500
   6 r = 15
   7 delay = 130
   8 
   9 class Bacteria:
  10     colors = ["red","orange","yellow","green","blue","cyan","magenta","light blue"]
  11     def __init__(self, canvas, p, color = None):
  12         self.canvas = canvas
  13         self.r = r
  14         self.p = max(p+random.randint(-2,2), 0)
  15         self.x = random.randint(self.r, canvas_size - self.r)
  16         self.y = random.randint(self.r, canvas_size - self.r)
  17         if color == None:
  18             self.color = random.choice(self.colors)
  19         else:
  20             self.color = color
  21         self.draw()

При создании каждой новой бактерии мы обязаны передать функции __init__() указатель на холст canvas, где эта бактерия будет жить, и предпочитаемую плодовитость p. Цвет бактерии мы можем задать, а можем этого не делать – тогда он будет выбран случайным образом. Кроме того, у каждой бактерии случайным образом определяются её координаты на холсте x, y. Строка self.draw() вызывает другую функцию класса, которая должна нарисовать бактерию на холсте.

   1     def draw(self):
   2         x1 = self.x - self.r
   3         x2 = self.x + self.r
   4         y1 = self.y  - self.r
   5         y2 = self.y  + self.r
   6         self.body = self.canvas.create_oval(x1, y1, x2, y2, fill=self.color)

Ссылку на кружочек мы сохраняем в переменной body. Теперь, если мы захотим удалить конкретную бактерию, нам не придётся стирать весь холст.

   1     def die(self):
   2         self.canvas.delete(self.body)

Бактерии могут ещё и размножаться.

   1     def give_child(self):
   2         return Bacteria(self.canvas,self.p,self.color)

А теперь пишем внешнюю (не принадлежащую классу) функцию step, которая определяет развитие системы во времени. bacs –- список уже имеющихся на данный момент бактерий. На каждом шаге выбираем одного счастливчика и размножаем в соответствии с его плодовитостью, а сколько-то случайно выбранных несчастных убиваем. Соотношение рождений и смертей можно варьировать.

   1 def step():
   2     lucky = random.choice(bacs)
   3     for i in range (lucky.p):
   4         bacs.append(lucky.give_child())
   5     for i in range (random.randint(0,len(bacs)//4)):
   6         looser = random.choice(bacs)
   7         looser.die()
   8         bacs.remove(looser)
   9     if len(bacs)>0 :
  10         root.after(delay, step)

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

   1 root=Tkinter.Tk()
   2 canv = Tkinter.Canvas(root, width=canvas_size, height=canvas_size, bg="white")
   3 canv.pack()
   4 bacs=[]
   5 for i in range(20):
   6     bacs.append(Bacteria(canv,random.randint(0,5)))
   7 step()
   8 root.mainloop()