> For the complete documentation index, see [llms.txt](https://pavel-karateev.gitbook.io/intermediate-python/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://pavel-karateev.gitbook.io/intermediate-python/struktury-dannykh/classes.md).

# Классы

Классы - это ядро Python. Они дают широкие возможности, но их легко неправильно использовать. В этой главе я расскажу про некоторые трюки в работе с классами и сделаю несколько предостережений. Давайте начнем!

## Переменные экземпляра и класса

Большинство начинающих, а иногда и опытных Python разработчиков не понимают до конца различия между переменными экземпляра и переменными класса. Это приводит к некорректному использованию этих различных типов переменных. Давайте разберемся.

Основное различие:

* Переменные экземпляров предназначены для данных уникальных для каждого

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

Посмотрим на пример:

```python
class Cal(object):
    # pi - переменная класса
    pi = 3.142

    def __init__(self, radius):
        # self.radius - переменная экземпляра
        self.radius = radius

    def area(self):
        return self.pi * (self.radius ** 2)

a = Cal(32)
a.area()
# Вывод: 3217.408
a.pi
# Вывод: 3.142
a.pi = 43
a.pi
# Вывод: 43

b = Cal(44)
b.area()
# Вывод: 6082.912
b.pi
# Вывод: 3.142
b.pi = 50
b.pi
# Вывод: 50
```

С использованием изменяемых переменных класса редко бывают проблемы. Поэтому разработчики обычно не стараются изучить тему подробнее - все и так работает! Если вы тоже уверены в надежности использования таких переменных, то следующий пример для вас:

```python
class SuperClass(object):
    superpowers = []

    def __init__(self, name):
        self.name = name

    def add_superpower(self, power):
        self.superpowers.append(power)

foo = SuperClass('foo')
bar = SuperClass('bar')
foo.name
# Вывод: 'foo'

bar.name
# Вывод: 'bar'

foo.add_superpower('fly')
bar.superpowers
# Вывод: ['fly']

foo.superpowers
# Вывод: ['fly']
```

Красота неправильного использования изменяемых переменных класса. Для предотвращения подобных ошибок - не храните изменяемые структуры данных в переменных класса или понимайте зачем вам это нужно.

## Классы нового стиля

Классы нового стиля были представлены в Python 2.1, но не так много разработчиков знает о них даже сейчас! Отчасти это связано с сохранением поддержки классов старого стиля для обратной совместимости. Давайте рассмотрим разницу между двумя стилями:

* Классы старого стиля ничему не наследуют
* Классы нового стиля наследуют `object`

Базовый пример:

```python
class OldClass():
    def __init__(self):
        print('Я старый класс')

class NewClass(object):
    def __init__(self):
        print('Я новый модный класс')

old = OldClass()
# Вывод: Я старый класс

new = NewClass()
# Вывод: Я новый модный класс
```

Наследование от `object` дает новым классам доступ к определенной *магии*. Например, вы можете использовать оптимизацию `__slots__`, вызов `super()` и дескрипторы. Резюме? Всегда используйте классы нового стиля.

**Примечание:** в Python 3 все классы нового стиля. Не важно наследует ли ваш класс `object` или нет. Тем не менее, хорошей идеей будет явно прописывать наследование.

## Магические методы

Классы в Python известны за свои магические методы, их отличительная черта - двойное нижнее подчеркивание с двух сторон от имени. Давайте рассмотрим несколько из них.

### `__init__`

Это конструктор класса. Конструктор вызывается каждый раз при создании экземпляра класса. Например:

```python
class GetTest(object):
    def __init__(self):
        print('Приветствую!')

    def another_method(self):
        print('Я другой метод, который не вызывается автоматически')

a = GetTest()
# Вывод: Приветствую!

a.another_method()
# Вывод: Я другой метод, который не вызывается автоматически
```

Как вы видите `__init__` вызывается при создании экземпляра класса. Вы также можете передавать аргументы конструктору для инициализации экземпляра:

```python
class GetTest(object):
    def __init__(self, name):
        print('Приветствую! {0}'.format(name))

    def another_method(self):
        print('Я другой метод, который не вызывается автоматически')

a = GetTest('Yasoob')
# Output: Приветствую! Yasoob

# Попробуем создать экземпляр без аргумента "name"
b = GetTest()
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
TypeError: __init__() takes exactly 2 arguments (1 given)
```

Надеюсь в общих чертах логика работы `__init__` понятна.

### `__getitem__`

Реализация метода `__getitem__` в классе позволяет использовать на его экземплярах `[]` оператор. Пример:

```python
class GetTest(object):
    def __init__(self):
        self.info = {
            'name':'Yasoob',
            'country':'Pakistan',
            'number':12345812
        }

    def __getitem__(self,i):
        return self.info[i]

foo = GetTest()

foo['name']
# Вывод: 'Yasoob'

foo['number']
# Вывод: 12345812
```

Без реализации `__getitem__` вы бы получили следующую ошибку:

```
>>> foo['name']

Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
TypeError: 'GetTest' object has no attribute '__getitem__'
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://pavel-karateev.gitbook.io/intermediate-python/struktury-dannykh/classes.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
