$ sudo teach IT
МОДУЛЬ 2 · УРОК 1

Создание классов и объектов

Мы уже знаем, зачем нужно ООП. Теперь пора написать первый настоящий класс на Python. Разберёмся с синтаксисом, узнаем, что такое «экземпляр», и увидим, как Python хранит объекты в памяти.

⏱ ~25 минут 🎓 Для новичков 🐍 Python 3

🔑 Ключевое слово class

В прошлом уроке мы говорили о классе как о чертеже или форме для печенья. Пора наконец написать этот чертёж на Python.

В Python для создания класса используется ключевое слово class. Это такое же зарезервированное слово, как if, for или def — Python «знает» его заранее и понимает, что дальше будет описание класса.

Базовый синтаксис выглядит вот так:

class ИмяКласса:
    # тело класса — здесь будет содержимое

Заметьте структуру: слово class, затем имя, затем двоеточие : — и дальше с отступом идёт тело класса. Точно так же, как у функции def или у блока if. Python всегда использует двоеточие + отступ для обозначения вложенных блоков.

💡 Важно: класс — это просто описание. Сам по себе он ничего не делает и не занимает много памяти. Он лишь говорит Python: «Запомни, вот как будут выглядеть объекты этого типа». Работа начнётся, когда мы создадим объект на основе этого класса.

📝 PascalCase — правило именования классов

В Python есть официальный документ с правилами оформления кода — он называется PEP 8 (Python Enhancement Proposal 8). Это что-то вроде свода правил дорожного движения для Python-программистов. Все профессиональные разработчики его соблюдают.

Согласно PEP 8, имена классов пишутся в стиле PascalCase — это когда каждое слово в названии начинается с заглавной буквы, и слова пишутся слитно, без подчёркиваний.

✅

Правильно — PascalCase

BankAccount
UserProfile
ShoppingCart
HttpRequest
❌

Неправильно

bank_account — snake_case
userprofile — всё строчным
SHOPPINGCART — всё заглавным
httpRequest — camelCase

Почему это важно? Потому что в Python по стилю написания сразу видно, с чем работает программист. Если видишь bank_account — это переменная или функция. Если видишь BankAccount — это точно класс. Код становится читаемым с первого взгляда.

🎯 Запомните: функции и переменные → snake_case (слова через подчёркивание). Классы → PascalCase (каждое слово с заглавной). Это не Python требует технически — это договорённость сообщества, которую все соблюдают.

🪴 Минимальный класс: знакомство с pass

В Python тело класса не может быть пустым. Если написать class Dog: и ничего не добавить — Python выдаст ошибку SyntaxError. Он ожидает хоть что-то внутри.

Для таких случаев в Python есть специальное слово-заглушка — pass. Оно буквально означает «здесь ничего нет, пропусти». Это полноценная инструкция, которая ничего не делает — она нужна именно для того, чтобы занять место, когда тело блока должно быть, но нам пока нечего туда писать.

# Минимальный валидный класс
class Dog:
    pass

# Вот и всё! Это полноценный класс Python.
# Пока он пустой, но это абсолютно рабочий код.

pass часто используют на этапе проектирования: сначала описывают структуру (какие классы будут), а потом заполняют их содержимым. Это нормальная практика — сначала наброски, потом детали.

🏗️ Создание объекта — вызов класса как функции

Класс у нас есть. Теперь нужно создать объект на его основе. И здесь Python делает всё очень просто: чтобы создать объект, нужно вызвать класс точно так же, как вы вызываете функцию — написать его имя и поставить скобки.

class Dog:
    pass

# Создаём объект — вызываем класс как функцию
my_dog = Dog()

# my_dog теперь — это объект (экземпляр) класса Dog
print(my_dog)  # <__main__.Dog object at 0x10a3f2b50>

Что произошло? Dog() — это вызов класса. Python «запустил» чертёж и по нему создал реальный объект в памяти компьютера. Этот объект был сохранён в переменную my_dog.

Когда вы распечатаете my_dog, увидите что-то вроде <__main__.Dog object at 0x10a3f2b50>. Это Python говорит вам: «Это объект класса Dog, и он живёт по такому-то адресу в памяти». Адрес (те числа в конце) — это физическое место в оперативной памяти вашего компьютера.

🔧 Под капотом: когда вы пишете Dog(), Python вызывает специальный метод __init__ этого класса. Сейчас у нашего класса нет своего __init__, поэтому Python использует базовый — он просто создаёт пустой объект. Об __init__ мы поговорим подробно в следующем уроке.

📌 Что такое «экземпляр» (instance)?

В программировании вы будете постоянно встречать два слова: объект и экземпляр. Хорошая новость — это синонимы. Оба слова означают одно и то же: конкретную «вещь», созданную на основе класса.

📐

Класс

Это чертёж, описание, шаблон. Существует в одном экземпляре (хе-хе). Не занимает памяти «под данные».

🐕

Объект / Экземпляр

Конкретная «вещь», созданная по чертежу. Живёт в памяти. Таких может быть сколько угодно.

Аналогия: класс Dog — это описание собак как вида (четыре лапы, хвост, лает). Объект my_dog — это конкретная собака Шарик, которая живёт у вас дома.

Термин «экземпляр» (от английского instance) пришёл из объектно-ориентированного программирования. Когда говорят «создать экземпляр класса» — это просто другой способ сказать «создать объект». В документации Python, в Stack Overflow, в книгах — вы будете видеть оба слова вперемежку. Знайте, что это одно и то же.

🔍 Встроенные функции: type(), id(), isinstance()

Python даёт нам три очень полезные встроенные функции для работы с объектами. Давайте разберём каждую.

🏷️ type(obj) — узнать класс объекта

Возвращает класс, к которому принадлежит объект. Это как спросить: «Из какого теста сделано это печенье?» — и форма ответит тебе своё имя.

🔢 id(obj) — уникальный номер объекта в памяти

Возвращает целое число — адрес объекта в оперативной памяти. Это как номер квартиры: у каждого объекта свой уникальный адрес. Два разных объекта никогда не имеют одинаковый id в один момент времени.

✅ isinstance(obj, Class) — проверка принадлежности классу

Возвращает True или False: является ли объект экземпляром указанного класса. Это самый правильный способ проверить тип объекта в Python — предпочтительнее, чем сравнение через type().

Посмотрим, как всё это работает на практике:

class Dog:
    pass

# Создаём объект
my_dog = Dog()

# type() — узнаём класс объекта
print(type(my_dog))        # <class '__main__.Dog'>
print(type(my_dog) == Dog) # True

# id() — уникальный адрес в памяти
print(id(my_dog))          # например: 4432156320 (число будет другим у вас!)

# isinstance() — проверяем принадлежность классу
print(isinstance(my_dog, Dog))  # True
print(isinstance(my_dog, str))  # False — это явно не строка

💬 Почему isinstance() лучше чем type() ==? Потому что isinstance учитывает наследование. Если класс Poodle является подклассом Dog, то isinstance(poodle_obj, Dog) вернёт True. А type(poodle_obj) == Dog вернёт False, ведь тип будет именно Poodle. Наследование мы изучим позже — просто запомните: для проверки типа используйте isinstance().

🧪 Демонстрация: три объекта — три уникальных адреса

Вот самое важное, что нужно понять про объекты: каждый раз, когда вы вызываете класс и создаёте новый объект, Python создаёт отдельную, независимую сущность в памяти. Даже если все объекты созданы по одному классу — они разные.

Это как если бы вы трижды использовали одну форму для печенья: у вас три печенья одной формы, но это три разных печенья. Можно одно съесть, второе уронить, третье украсить — они независимы друг от друга.

class Dog:
    pass

# Создаём три объекта одного класса
dog1 = Dog()
dog2 = Dog()
dog3 = Dog()

# Проверяем их id — каждый уникален!
print(id(dog1))  # например: 4432156320
print(id(dog2))  # например: 4432156480  ← другой!
print(id(dog3))  # например: 4432156640  ← тоже другой!

# Все три — это Dog
print(isinstance(dog1, Dog))  # True
print(isinstance(dog2, Dog))  # True
print(isinstance(dog3, Dog))  # True

# Но они НЕ равны друг другу (это разные объекты)
print(dog1 == dog2)  # False
print(dog1 is dog2)  # False — оператор is проверяет именно id

Посмотрите на последние две строки. В Python есть два способа сравнивать:

== — равенство по значению

Одинаково ли содержимое объектов? Два разных списка [1, 2] и [1, 2] равны по ==, хотя это разные объекты.

is — идентичность

Это буквально один и тот же объект в памяти? Сравнивает id(). dog1 is dog1 — True. dog1 is dog2 — False.

🎯 Золотое правило: каждый вызов класса создаёт новый уникальный объект. Один и тот же класс — бесконечное количество объектов. Это и есть мощь ООП: один шаблон, тысячи экземпляров.

💻 Полный пример: собираем всё вместе

Давайте напишем чуть более осмысленный пример и используем все инструменты, которые узнали сегодня:

class Car:
    pass

# Создаём три автомобиля
car1 = Car()
car2 = Car()
car3 = Car()

# Проверяем типы
print(type(car1))          # <class '__main__.Car'>
print(type(car2))          # <class '__main__.Car'>

# Каждый автомобиль уникален — свой id
print(f"Адрес car1: {id(car1)}")
print(f"Адрес car2: {id(car2)}")
print(f"Адрес car3: {id(car3)}")
print(f"Все id разные: {id(car1) != id(car2) != id(car3)}")  # True

# Проверяем принадлежность
print(isinstance(car1, Car))  # True
print(isinstance(car1, int))  # False — это явно не число

# car1 и car2 — разные объекты, хотя оба Car
print(car1 is car2)  # False
print(car1 is car1)  # True — сам с собой всегда True

Запустите этот код в своём интерпретаторе Python. Числа в id() у вас будут другими — это нормально: они зависят от конкретного запуска программы и состояния памяти вашего компьютера. Но они всегда будут различаться для разных объектов.

📋 Итоги урока

Сегодня вы сделали огромный шаг — написали первые классы и объекты на Python. Вот что теперь вы знаете:

  • class ИмяКласса: — синтаксис объявления класса
  • Имена классов пишутся в PascalCase — каждое слово с заглавной буквы
  • pass — заглушка для пустого тела класса (и не только)
  • obj = MyClass() — создание объекта (экземпляра) класса
  • Объект и экземпляр — это синонимы
  • type(obj) — показывает класс объекта
  • id(obj) — уникальный адрес объекта в памяти
  • isinstance(obj, Class) — проверяет принадлежность классу (предпочтительнее type() ==)
  • Каждый вызов класса создаёт новый уникальный объект с уникальным id

🚀 В следующем уроке мы оживим наши объекты: добавим атрибуты через __init__ — специальный метод инициализации. Вы поймёте, как каждый объект получает свои собственные данные, и наш класс Dog наконец научится хранить имя, породу и возраст каждой конкретной собаки.

На следующий урок