Атрибут класса vs атрибут экземпляра: где создаётся, где виден, как экранируется
less_35__class_instance_attributes/theory_01__class_attribute__vs__instance_attribute.md
Пошаговый разбор различий на классе A с атрибутом класса general и атрибутом экземпляра x: атрибут класса создаётся вне __init__ и виден одинаково через любой экземпляр и через сам класс, атрибут экземпляра — только внутри своего объекта. Ключевая ловушка раздела 4: присваивание a1.general = 999 не меняет атрибут класса, а создаёт новый атрибут экземпляра, который экранирует видимость атрибута класса именно для a1 — это лечится del a1.general. Также показаны два способа менять сам атрибут класса (через A.general и через a1.__class__.general) и объяснено, почему PEP 8 не одобряет добавление атрибутов экземпляра вне __init__.
- class A: general = 100 (атрибут класса) вне __init__, self.x внутри __init__
- a1.general/a2.general/A.general — все три показывают 100 одновременно
- A.general = 500 и a1.__class__.general = 777 — два способа изменить атрибут класса сразу для всех
- a1.general = 999 — ловушка: создаёт свой атрибут экземпляра, экранирующий класс
- del a1.general — атрибут класса снова становится виден
- PEP 8: атрибуты экземпляра всегда объявлять внутри класса (в __init__ или методах)
Показать начало файла (174 строк всего)
### 1. Создание атрибута класса `general` и атрибута экземпляра класса
* **Атрибут класса** создаётся ВНЕ `__init__()`
* **Атрибут экземпляра класса** создаётся ВНУТРИ `__init__()`
```python
class A:
general = 100 # атрибут класса
def __init__(self, x):
self.x = x # атрибут экземпляра
a1 = A(5)
a2 = A(10)
```
### 2. Где "виден" каждый из атрибутов?
* **Атрибут класса** виден и в класса, и в каждом экземпляре класса
* **Атрибут экземпляра класса** виден ИСКЛЮЧИТЕЛЬНО внутри ТОЛЬКО этого экземпляра
```python
# class attribute
print(a1.general) # 100
print(a2.general) # 100
print(A.general) # 100
# instance attribute
print(a1.x) # 5
print(a2.x) # 10
```
---
### 3. Как изменить атрибут класса `general`?
* 3.1. Через имя класса:
```python
A.general = 500
print(a1.general) # 500
print(a2.general) # 500
```
* 3.2. Через экземпляр класса с помощью метода `__class__`:
```python
a1.__class__.general = 777
print(a1.general) # 777
print(a2.general) # 777
```
### 4. Что будет, если написать `a1.general = ...`
Вот важная ловушка:
* это НЕ меняет атрибут класса.
…