Объектно-ориентированный стиль программирования в Python

In [ ]:
class Dog:
    pass

dog1 = Dog()
dog2 = Dog()

print(type(dog1))
print(type(dog2))
In [ ]:
 
In [ ]:
 
In [ ]:
 
In [ ]:
a = int('5')
print(type(a))
In [ ]:
 
In [ ]:
 
In [ ]:
 
In [ ]:
class Dog:
    pass

dog1 = Dog()

# атрибуты объекта добавляются динамически по аналогии со словарями:
dog1.name = "Шарик"
dog1.age = 2

# вывести возраст собаки
print(dog1.age)
# посмотреть атрибуты объекта dog1:
print(dog1.__dict__)

dog2 = Dog()

# атрибуты объекта добавляются динамически по аналогии со словарями:
dog2.name = "Бобик"
dog2.age = 1

# вывести возраст второй собаки
print(dog2.age)
# посмотреть атрибуты объекта dog1:
print(dog2.__dict__)
In [ ]:
 
In [ ]:
 
In [ ]:
 
In [ ]:
def info_obj(obj):
    """ Отображает на экране поля объекта """

    # обратиться к полям через словарь:
    for i in obj.__dict__:
        print(f'{i} : {obj.__dict__[i]}')
In [ ]:
info_obj(dog1)
In [ ]:
info_obj(dog2)
In [ ]:
 
In [ ]:
 

Состояние и поведение объектов

In [ ]:
class Dog:    
    # метод для произношения имени:
    def bark(self):         
        return f"Собака говорит: {self.name}"

# Конкретная собака:        
my_dog = Dog()

# определяем имя собаки
my_dog.name = "Шарик" # динамически добавляется атрибут объекта name

# выводим имя собаки через обращение к атрибуту
print(my_dog.name)

# определяем дополнительные атрибуты
my_dog.weight = 20
my_dog.age = 3

# просим собаку что-нибудь сказать через обращение к методу
print(my_dog.bark()) # перед вызовом методы атрибут name уже должен существовать

# Преобразуется в полную форму:
print(Dog.bark(my_dog))
In [ ]:
 
In [ ]:
# Упражнение
In [ ]:
 
In [ ]:
 
In [ ]:
class Dog:    
    # Конструктор
    # Вызывается в момент создания объекта данного типа (класса)
    def __init__(self):
        self.name = "Собака без имени"
        print("Родилась новая собака!")

# Создаем собаку
my_dog = Dog() # здесь хочется здать имя....

print(my_dog.name)
In [ ]:
 
In [ ]:
 
In [ ]:
 
In [ ]:
class Dog:    
    # Конструктор
    # Вызывается на момент создания объекта этого типа
    def __init__ (self, new_name='Собака без имени'):
        self.name = new_name # переменной объекта присваиваем локальную переменную
        print("Родилась новая собака!")

# Создаем собаку и теперь можем задать ей имя!
my_dog = Dog("Шарик")

# Вывести имя собаки, убедиться, что оно было установлено 
# (так обычно не делают!)
print(my_dog.name)

# Создаем еще одну собаку 
her_dog = Dog() # имя по умолчанию 'Собака без имени'

print(her_dog.name)
In [ ]:
 
In [ ]:
 
In [ ]:
 
In [ ]:
 

Скрываем работу с внутренними переменными класса. Просим, чтобы к ним обращались через методы.

Со временем внутренние переменные могут измениться, а методы (API - application programming interface) остаются неизменными.

Мы работаем с API и нам неважно, как оно внутри работает (инкапсуляция). Главное, правильность работы и стабильность (неизменнный интерфейс вызова).

In [ ]:
class Dog:    
    # Конструктор
    def __init__(self, new_name='Собака без имени'):        
        self._name = new_name
    # Можем в любой момент вызвать этот метод и изменить имя объекта:
    def set_name(self, new_name):
        self._name = new_name
    # Можем в любой момент вызвать этот метод и узнать имя объекта:
    def get_name(self):
        return self._name

# Создаем конкретную собаку
my_dog = Dog("Тузик")

# Вывести имя собаки
print(my_dog.get_name())

# Изменили имя собаки
my_dog.set_name("Шарик")

# Посмотрели изменения
print(my_dog.get_name())
In [ ]:
 
In [ ]:
 
In [ ]:
# цитата
In [ ]:
 
In [ ]:
# упражнение
In [ ]:
 
In [ ]:
 
In [ ]:
 
In [ ]:
# ответ к заданию про кошку
In [ ]:
class Cat:    
    def __init__(self, new_name='Кошка без имени'):        
        self._name = new_name # новое имя
        print(f'Родилась новая кошка... {self._name}')
        self._eat = 0 # счетчик сытости на нуле
    
    def set_name(self, new_name):
        self._name = new_name # новое имя
    
    def meow(self):
        print(f"Кошка говорит: меня зовут {self._name}")
        if self._eat == 0: # если счетчик сытости на нуле
            print("Кошка проголодалась...")    
    
    def gaming(self):
        if self._eat == 0:
            print('Нет сил играть...')
        else:
            print("Кошка играет с мячиком...")
            self._eat -= 1 # счетчик сытости уменьшается
            
    def eating(self):
        self._eat += 1 # счетчик сытости увеличивается
        print("Кошка ест...")
        
# Создаем кошку:        
my_сat1 = Cat()
my_сat1.set_name("Котик")

# Несколько дней из жизни кошки
my_сat1.gaming()
my_сat1.meow()
my_сat1.eating()
my_сat1.gaming()

my_сat2 = Cat('Барсик')

# Несколько дней из жизни кошки
my_сat2.meow()
my_сat1.eating()
my_сat1.gaming()
In [ ]:
 
In [ ]:
 
In [ ]:
# упражнения
In [ ]:
 
In [ ]:
 
In [ ]:
# ответ к упражнению
In [ ]:
class Point: 
    def __init__(self, x=0, y=0):
        '''
        Конструктор
        '''
        self.x = x
        self.y = y
        print(f"Инициализация координат ({x},{y}) ")

    def set(self, x, y):
        self.x = x
        self.y = y

    def get(self):
        print(f'координата x={self.x}, координата y={self.y}')

pt1 = Point()
pt2 = Point(3, 5)

pt2.get()

pt1.set(4, 6)
pt1.get()
In [ ]:
 
In [ ]:
 
In [ ]:
 

Как суммировать координаты двух точек?

pt1 = Point(2, 4)
pt2 = Point(1, 5)

pt3 = pt1 + pt2 # Point.__add__(pt1, pt2)
pt3.get()
# (3, 9)
In [ ]:
 
In [ ]:
# Напоминалочка
In [ ]:
'3' + '5'
In [ ]:
'3'.__add__('5')
In [ ]:
str.__add__('3', '5')
In [ ]:
 
In [ ]:
# ответ про сумму координат двух точек
In [ ]:
class Point: 
    def __init__(self, x=0, y=0):
        '''
        Конструктор
        '''
        self.x = x
        self.y = y
        print(f"Инициализация координат ({x},{y})")

    def set(self, x, y):
        self.x = x
        self.y = y

    def get(self):
        print(f'координата x = {self.x}, координата y = {self.y}')

    def __add__(self, other):
        return Point(self.x + other.x, self.y + other.y)

pt1 = Point()
pt2 = Point(3, 5)

pt2.get()
pt1.set(1, 2)
pt1.get()

pt3 = pt1 + pt2
pt3.get()
In [ ]:
 
In [ ]:
 
In [ ]:
# выводим информацию о точке с помощью функции print
In [ ]:
print(pt1) # вместо метода get
In [ ]:
 
In [ ]:
# Point.__str__(pt1)
In [ ]:
 
In [ ]:
 
In [ ]:
class Point: 
    def __init__(self, x=0, y=0):
        '''
        Инициализация точки
        '''
        self.x = x
        self.y = y
        print(f"Инициализация координат ({x},{y})")

    def set(self, x, y):
        '''
        Устанавливает координаты точки
        '''
        self.x = x
        self.y = y

    def __add__(self, other):
        '''
        Специальный метод для выполнения операции сложения двух точек
        '''
        return Point(self.x + other.x, self.y + other.y)

    def __str__(self):
        '''
        Специальный метод для отображения информации о точке
        '''
        return f'Точка с координатами ({self.x},{self.y})'

pt1 = Point()
print(pt1)

pt2 = Point(3, 5)
print(pt2)

pt1.set(3, 5)
print(pt1)

print(pt1 + pt2)
In [ ]:
 
In [ ]:
 
In [ ]:
 
In [ ]:
# Про переменные и атрибуты объекта
In [ ]:
# создаем класс Car
class Car:  
    def start(self):
        # локальная переменная внутри метода:
        message = "Двигатель заведен" 
        return message

car = Car()  
# print(car.message)
# AttributeError: 'Car' object has no attribute 'message'
# не можем обратиться к переменной внутри метода

print(car.start()) # Car.start(car)
In [ ]:
 
In [ ]:
class Car:  
    def __init__(self):
        print("Двигатель заведен")
        self.name = "corolla"
        self._make = "toyota"
        self._model = 1999
        
car = Car()  
# можем обратиться к переменной объекта:
print(car.name)
In [ ]:
 
In [ ]:
class Car:  
    # переменная класса:
    message1 = "Двигатель заведен"

print(Car.message1)    

car = Car()  
# можем обратиться к (глобальной) переменной класса:
print(car.message1)
In [ ]:
 
In [ ]:
 

Атрибуты класс

In [ ]:
class Dog:
    # Атрибуты класса доступны из всех экземпляров данного класса
    count = 0
    legs = 4    
    
    # Конструктор
    def __init__(self, new_name='Собака без имени'):        
        self._name = new_name
        Dog.count += 1 # увеличиваем счетчик экземпляров класса Dog
        
    # Можем в любой момент вызвать этот метод и изменить имя:
    def set_name(self, new_name):
        self._name = new_name
    
    # Можем в любой момент вызвать этот метод и узнать имя:
    def get_name(self):
        return self._name

# Создаем конкретную собаку
my_dog = Dog()

# Изменяем имя собаки
my_dog.set_name("Шарик")

# Сколько ног у собаки (доступ к атрибуту класса):
print(f{my_dog.get_name()}а {my_dog.legs} ноги')

# Создаем еще одну конкретную собаку
her_dog = Dog("Бобик")

print(f{her_dog.get_name()}а {her_dog.legs} ноги')

# Сколько экземпляров класса Dog создано:
print('создано собак:', Dog.count)
In [ ]:
 
In [ ]:
 

Наследование

In [ ]:
class Person:
    def __init__(self, name='Человек без имени'):
        self.name = name
        self.age = 0
    def say(self):
        print(f"{self.name} говорит")

class Employee(Person):
    def set_job(self, job_title='Безработный'):
        self.job_title = job_title        
    def get_job(self):
        print(self.job_title)
    
class Customer(Person):    
    def set_email(self, email='Нет почты'):
        self.email = email        
    def get_email(self):
        print(self.email)

person = Person('Иван')
person.say()

emp = Employee()
# вызываем метод из базового класса:
emp.say()
# в этот момент ошибка. почему? как исправить?
emp.get_job()

cust = Customer('Петр')
# вызываем метод из базового класса:
cust.say()
# в этот момент ошибка. почему? как исправить?
cust.get_email()
In [ ]:
 
In [ ]:
class Person:
    def __init__(self, name='Человек без имени'):
        self.name = name
        self.age = 0
    def say(self):
        print(f"{self.name} говорит")

class Employee(Person):
    def __init__(self, name='Работник без имени'):
        Person.__init__(self, name=name)
        self.job_title = 'Безработный'
    def set_job(self, job_title):
        self.job_title = job_title        
    def get_job(self):
        print(self.name, self.job_title)
    
class Customer(Person):
    def __init__(self, name='Покупатель без имени'):
        Person.__init__(self, name=name)
        self.email = 'Нет почты'
    def set_email(self, email):
        self.email = email        
    def get_email(self):
        print(self.name, self.email)

person = Person('Иван')
person.say()

emp = Employee('Игорь')
emp.say()
emp.get_job()

cust = Customer('Петр')
cust.say()
cust.get_email()

print(type(emp))
In [ ]:
 
In [ ]:
class Person:
    def __init__(self, name='Человек без имени'):
        self.name = name
        self.age = 0
    def __str__(self):
        return f'{self.name}'                
    def say(self):
        print(f"{self.name} говорит")

class Employee(Person):
    def __init__(self, name='Работник без имени'):
        Person.__init__(self, name=name)
        self.job_title = 'Безработный'
    def __str__(self):
        return f'{self.name} {self.job_title}'                
    def set_job(self, job_title):
        self.job_title = job_title        

class Customer(Person):
    def __init__(self, name='Покупатель без имени'):
        Person.__init__(self, name=name)
        self.email = 'Нет почты'
    def __str__(self):
        return f'{self.name} {self.email}'
    def set_email(self, email):
        self.email = email        

person = Person('Иван')
print(person)

emp = Employee('Игорь')
print(emp)

cust = Customer('Петр')
print(cust)
In [ ]:
 
In [ ]:
 
In [ ]:
# Определяем собственное исключение:
class MyError(Exception):
    pass

try:
    raise MyError("Мое исключение... я могу написать о нем")
except MyError as error:
    print("Поймали исключение:", error)
In [ ]:
 
In [ ]:
# упражнение
In [ ]:
 
In [ ]: