Объектно-ориентированное программирование


  • Есть разные стили (парадигмы) организации кода. До сих пор мы использовали структруное программирование. Далее мы рассмотрим объекнтно-ориентированное.
  • Создайте файл student.py и наберите в нем:
    	
    name = input("Name: ")
    house = input("House: ")
    print(f"{name} from {house}")
    
    	
    Эта программа следует структруному стилю программировония. В структурном подходе мы разбиваем задачу на подзадачи, создаем для них фукции и выражаем решение через вызов функций.
  • Мы можем создать вспомогательные функции.
    	
    def main():
        name = get_name()
        house = get_house()
        print(f"{name} from {house}")
    
    def get_name():
        return input("Name: ")
        
    def get_house():
        return input("House: ")
    
    if __name__ == "__main__":
        main()
    
    		
    get_name и get_house нужны, чтобы абстраигроваться от решения подзадач в main функции.
  • Мы можем далее упростить программу, используя tuple (кортеж). tuple - последовательность значений. В отилчие от list (список), tuple не может быть изменён.
    	
    def main():
        name, house = get_student()
        print(f"{name} from {house}")
    
    def get_student():
        name = input("Name: ")
        house = input("House: ")
        return name, house
    
    if __name__ == "__main__":
        main()
    
    		
  • Реализуем программу, используя словарь (dict).
    	
    class Student:
        def __init__(self, name, house):
            self.name = name
            self.house = house
    
    def main():
        student = get_student()
        print(f"{student.name} from {student.house}")
    
    def get_student():
        name = input("Name: ")
        house = input("House: ")
        return Student(name, house)
    
    if __name__ == "__main__":
        main()
    
    		
    В словаре мы можем указывать на элемент ключом.
  • Классы

  • Класс - способ создать свой тип данных и дать ему имя. Этот инструмент используется в объектно-ориентированном программировании.
  • Изменим наш код. Создадим класс Student.
    	
    class Student: # Создаем класс
        ...
    
    def main():
        student = get_student()
        print(f"{student.name} from {student.house}")
    
    def get_student():
        student = Student() # создаем объект
        student.name = input("Name: ") 	# задаем свойство
        student.house = input("House: ")
        return student
    
    if __name__ == "__main__":
        main()
    
    		
    Для создания класса, используем ключевое слово class. Конструкор класса Student() создает объект класса. Чтобы получить значение свойства объекта класса, используем точку после имени объекта, например, student.name.
  • Класс - это шаблон для создания экземпляров (объектов).
  • Мы можем создавать функции в классе их принято назваыть методы. Специальная функция класса ининциализирующая его свойства называется конструктор. Посмотрим как можно задать конструктор класса.
    	
    class Student:
        def __init__(self, name, house):
            self.name = name
            self.house = house
    
    def main():
        student = get_student()
        print(f"{student.name} from {student.house}")
    
    def get_student():
        name = input("Name: ")
        house = input("House: ")
        return Student(name, house)
    
    if __name__ == "__main__":
        main()
    
    		
    self используется для ссылки на объект.
  • Смотри документацию на классы.

raise

  • Используем функцию raise, чтобы создать исключение, если пользователь ошибся.
    	
    class Student:
        def __init__(self, name, house):
            if not name:
                raise ValueError("Missing name")
            if house not in ["Gryffindor", "Hufflepuff", "Ravenclaw", "Slytherin"]: 
                raise ValueError("Invalid house") 
            self.name = name
            self.house = house
    
    def main():
        student = get_student()
        print(f"{student.name} from {student.house}")
    
    def get_student():
        name = input("Name: ")
        house = input("House: ")
        return Student(name, house)
    
    if __name__ == "__main__":
        main()
    
    		
    Код создаёт объект класса ValueError c текстом.
  • Если мы зададим для нашего класса функцию __str__, то функция print сможет печатать его объекты.
    	
    class Student:
        def __init__(self, name, house):
            if not name:
                raise ValueError("Missing name")
            if house not in ["Gryffindor", "Hufflepuff", "Ravenclaw", "Slytherin"]: 
                raise ValueError("Invalid house") 
            self.name = name
            self.house = house
        def __str__(self):
            return f"{self.name} from {self.house}"
    
    def main():
        student = get_student()
        print(student)
    
    def get_student():
        name = input("Name: ")
        house = input("House: ")
        return Student(name, house)
    
    if __name__ == "__main__":
        main()
    
    		

Декораторы

  • Декораторы функций начинаются с @
    	
    class Student:
        def __init__(self, name, house):
            if not name:
                raise ValueError("Missing name")
            if house not in ["Gryffindor", "Hufflepuff", "Ravenclaw", "Slytherin"]: 
                raise ValueError("Invalid house") 
            self.name = name
            self.house = house
        def __str__(self):
            return f"{self.name} from {self.house}"
    
        @property
        def house(self):
            return self._house
    
        @house.setter
        def house(self, house):
            if house not in ["Gryffindor", "Hufflepuff", "Ravenclaw", "Slytherin"]: 
                raise ValueError("Invalid house") 
            self._house = house
    
    def main():
        student = get_student()
        student.house="Slytherin"
    
        print(student)
    
    def get_student():
        name = input("Name: ")
        house = input("House: ")
        return Student(name, house)
    
    if __name__ == "__main__":
        main()
        
    		

Методы класса

  • Можно задать функцию класса а не объекта.
  • Создадим файл hat.py не использующий метода класса.
    	
    import random
    class Hat:
        def __init__(self):
            self.houses = ["Gryffindor", "Hufflepuff", "Ravenclaw", "Slytherin"] 
    
        def sort(self, name):
            print(name, "is in", random.choice(self.houses))
    
    hat = Hat()
    hat.sort("Harry")
    
    		
  • Мы можем использовать функцию sort не создавая объекта класса. Изменим наш код:
    	
    import random
    class Hat: 
        houses = ["Gryffindor", "Hufflepuff", "Ravenclaw", "Slytherin"] 
    
        @classmethod
        def sort(cls, name):
            print(name, "is in", random.choice(cls.houses))
    
    Hat.sort("Harry")
    
    		
  • Изменим файл student.py, добавив @classmethod
    	
    class Student:
        def __init__(self, name, house):
            self.name = name
            self.house = house
    
        def __str__(self):
            return f"{self.name} from {self.house}"
    
        @classmethod
        def get(cls):
            name = input("Name: ")
            house = input("House: ")
            return cls(name, house)
    
    def main():
        student = Student.get()
        print(student)
    
    
    if __name__ == "__main__":
        main()
        
    		

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

  • Можно создать класс, которые наследует свойства и методы другого.
  • Создайте файл wizar.py. С кодом:
    	
    class Wizard:
        def __init__(self, name):
            if not name:
                raise ValueError("Missing name")
            self.name = name
    
    class Student(Wizard):
        def __init__(self, name, house):
            super().__init__(name)
            self.house = house
    
    class Professor(Wizard):
        def __init__(self, name , subject):
            super().__init__(name)
            self.subject = subject
    
    wizard = Wizard("Albus")
    student = Student("Harry", "Gryffindor")
    professor = Professor("Severus", "Defense Against the Dark Arits")
    
    print(student.name)
    
    		

Перегрузка операторов

  • Некоторые операторы, такие как +, -, могут быть перегружены.
  • Создайте файл vault.py. Наберите в нем:
    	
    class Vault:
        def __init__(self, galleons=0, sickles=0, knuts=0):
            self.galleons = galleons
            self.sickles = sickles
            self.knuts = knuts
        def __str__(self):
            return f"{self.galleons} Galleons, {self.sickles} Sickles, {self.knuts} Rnuts"
    
        def __add__(self, other):
            galleons = self.galleons + other.galleons
            sickles = self.sickles + other.sickles
            knuts = self.knuts + other.knuts
            return Vault(galleons, sickles, knuts)
    
    
    potter = Vault(100, 50, 25)
    print(potter)
    
    weasley = Vault(25, 50, 100)
    print(weasley)
    
    total= potter + weasley
    print(total)