Skip to content

Commit 6b9cf91

Browse files
committed
Add classes python
1 parent 330f412 commit 6b9cf91

File tree

2 files changed

+326
-0
lines changed

2 files changed

+326
-0
lines changed

src/SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
- [Асимптотическая сложность](./dev/python/o-notation.md)
4040
- [Функции](./dev/python/functions.md)
4141
- [Декораторы и functools](./dev/python/decorators.md)
42+
- [Классы](./dev/python/classes.md)
4243

4344
# Учимся у других
4445

src/dev/python/classes.md

Lines changed: 325 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,325 @@
1+
# Классы в Python. Основы
2+
3+
## Введение в ООП
4+
5+
Прежде чем погружаться в синтаксис классов Python, давайте вспомним, что такое **объектно-ориентированное программирование (ООП)**.
6+
7+
ООП — это парадигма программирования, где код организуется в виде объектов, содержащих данные (атрибуты) и поведение (методы). Основные концепции ООП:
8+
9+
- **Инкапсуляция** — объединение данных и методов в одном объекте
10+
- **Наследование** — создание новых классов на основе существующих
11+
- **Полиморфизм** — возможность использовать объекты разных классов одинаковым образом
12+
13+
Python реализует все эти концепции через классы!
14+
15+
## Базовый синтаксис классов
16+
17+
```python
18+
class Counter:
19+
"""Я считаю. И это всё."""
20+
21+
def __init__(self, initial=0): # конструктор
22+
self.value = initial
23+
24+
def increment(self):
25+
self.value += 1
26+
27+
def get(self):
28+
return self.value
29+
30+
# Использование
31+
c = Counter(42)
32+
c.increment()
33+
print(c.get()) # 43
34+
```
35+
36+
### Зачем нужен self?
37+
38+
В отличие от Java и C++, в Python нет ключевого слова `this`. Первый аргумент методов — это сам объект, который принято называть `self`:
39+
40+
```python
41+
class Noop:
42+
def __init__(self):
43+
self.data = "hello"
44+
45+
# Технически можно назвать иначе, но не стоит!
46+
class StrangeNoop:
47+
def __init__(ego): # пожалуйста, не делайте так
48+
ego.data = "world"
49+
```
50+
51+
## Атрибуты: экземпляра vs класса
52+
53+
```python
54+
class Counter:
55+
# Атрибут класса - общий для всех экземпляров
56+
all_counters = []
57+
58+
def __init__(self, initial=0):
59+
# Атрибут экземпляра - уникальный для каждого объекта
60+
self.value = initial
61+
Counter.all_counters.append(self)
62+
63+
# Добавить атрибут можно и после объявления класса
64+
Counter.some_other_attribute = 42
65+
```
66+
67+
## Инкапсуляция и соглашения об именовании
68+
69+
Python не имеет строгих модификаторов доступа, но использует соглашения:
70+
71+
```python
72+
class Noop:
73+
public_attribute = 42 # публичный атрибут
74+
_internal_attribute = [] # внутренний (для разработчиков)
75+
__private_attribute = [] # "приватный" (name mangling)
76+
77+
noop = Noop()
78+
print(noop.public_attribute) # 42
79+
print(noop._internal_attribute) # [] (но не стоит!)
80+
# print(noop.__private_attribute) # Ошибка!
81+
print(noop._Noop__private_attribute) # Работает (но не делайте так!)
82+
```
83+
84+
## Свойства (Properties)
85+
86+
Свойства позволяют контролировать доступ к атрибутам:
87+
88+
```python
89+
class Temperature:
90+
def __init__(self, celsius=0):
91+
self._celsius = celsius
92+
93+
@property
94+
def celsius(self):
95+
return self._celsius
96+
97+
@property
98+
def fahrenheit(self):
99+
return (self._celsius * 9/5) + 32
100+
101+
@celsius.setter
102+
def celsius(self, value):
103+
if value < -273.15:
104+
raise ValueError("Температура ниже абсолютного нуля!")
105+
self._celsius = value
106+
107+
temp = Temperature(25)
108+
print(f"{temp.celsius}°C = {temp.fahrenheit}°F")
109+
temp.celsius = 30 # работает setter
110+
```
111+
112+
## Наследование
113+
114+
```python
115+
class Animal:
116+
def __init__(self, name):
117+
self.name = name
118+
119+
def speak(self):
120+
raise NotImplementedError("Подклассы должны реализовать этот метод")
121+
122+
class Dog(Animal):
123+
def speak(self):
124+
return f"{self.name} говорит: Гав!"
125+
126+
class Cat(Animal):
127+
def speak(self):
128+
return f"{self.name} говорит: Мяу!"
129+
130+
animals = [Dog("Бобик"), Cat("Мурка")]
131+
for animal in animals:
132+
print(animal.speak())
133+
```
134+
135+
### Функция super()
136+
137+
```python
138+
class Person:
139+
def __init__(self, name, age):
140+
self.name = name
141+
self.age = age
142+
143+
class Student(Person):
144+
def __init__(self, name, age, student_id):
145+
super().__init__(name, age) # вызов родительского конструктора
146+
self.student_id = student_id
147+
```
148+
149+
## Множественное наследование
150+
151+
Python поддерживает множественное наследование, но используйте его осторожно!
152+
153+
```python
154+
class Flyer:
155+
def fly(self):
156+
return "Лечу!"
157+
158+
class Swimmer:
159+
def swim(self):
160+
return "Плыву!"
161+
162+
class Duck(Flyer, Swimmer):
163+
pass
164+
165+
donald = Duck()
166+
print(donald.fly()) # Лечу!
167+
print(donald.swim()) # Плыву!
168+
```
169+
170+
### Проблема ромбовидного наследования
171+
172+
```python
173+
class A:
174+
def method(self):
175+
return "A"
176+
177+
class B(A):
178+
def method(self):
179+
return "B"
180+
181+
class C(A):
182+
def method(self):
183+
return "C"
184+
185+
class D(B, C):
186+
pass
187+
188+
print(D().method()) # Каков результат?
189+
print(D.mro()) # Показывает порядок разрешения методов
190+
```
191+
192+
## Декораторы классов
193+
194+
Декораторы могут преобразовывать классы:
195+
196+
```python
197+
import functools
198+
199+
def singleton(cls):
200+
"""Декоратор, превращающий класс в singleton"""
201+
instance = None
202+
203+
@functools.wraps(cls)
204+
def wrapper(*args, **kwargs):
205+
nonlocal instance
206+
if instance is None:
207+
instance = cls(*args, **kwargs)
208+
return instance
209+
210+
return wrapper
211+
212+
@singleton
213+
class DatabaseConnection:
214+
def __init__(self):
215+
print("Создано соединение с БД")
216+
217+
db1 = DatabaseConnection() # Создано соединение с БД
218+
db2 = DatabaseConnection() # (ничего не выводится)
219+
print(db1 is db2) # True
220+
```
221+
222+
## Магические методы
223+
224+
Магические методы (dunder methods) позволяют определить поведение объектов в различных ситуациях.
225+
226+
### Строковое представление
227+
228+
```python
229+
class Book:
230+
def __init__(self, title, author):
231+
self.title = title
232+
self.author = author
233+
234+
def __str__(self):
235+
return f"'{self.title}' by {self.author}"
236+
237+
def __repr__(self):
238+
return f"Book('{self.title}', '{self.author}')"
239+
240+
book = Book("Война и мир", "Л. Толстой")
241+
print(str(book)) # 'Война и мир' by Л. Толстой
242+
print(repr(book)) # Book('Война и мир', 'Л. Толстой')
243+
```
244+
245+
### Операторы сравнения
246+
247+
```python
248+
import functools
249+
250+
@functools.total_ordering
251+
class Money:
252+
def __init__(self, amount, currency):
253+
self.amount = amount
254+
self.currency = currency
255+
256+
def __eq__(self, other):
257+
return (self.amount == other.amount and
258+
self.currency == other.currency)
259+
260+
def __lt__(self, other):
261+
if self.currency != other.currency:
262+
raise ValueError("Нельзя сравнивать разные валюты")
263+
return self.amount < other.amount
264+
265+
m1 = Money(100, "USD")
266+
m2 = Money(150, "USD")
267+
print(m1 < m2) # True
268+
```
269+
270+
### Вызываемые объекты
271+
272+
```python
273+
class Multiplier:
274+
def __init__(self, factor):
275+
self.factor = factor
276+
277+
def __call__(self, x):
278+
return x * self.factor
279+
280+
double = Multiplier(2)
281+
triple = Multiplier(3)
282+
283+
print(double(5)) # 10
284+
print(triple(5)) # 15
285+
```
286+
287+
## Практический пример: Умный словарь
288+
289+
```python
290+
from collections import deque
291+
292+
class MemorizingDict(dict):
293+
"""Словарь, который запоминает историю изменений"""
294+
295+
def __init__(self, *args, **kwargs):
296+
super().__init__(*args, **kwargs)
297+
self.history = deque(maxlen=10)
298+
299+
def __setitem__(self, key, value):
300+
self.history.append(key)
301+
super().__setitem__(key, value)
302+
303+
def get_history(self):
304+
return list(self.history)
305+
306+
# Использование
307+
md = MemorizingDict()
308+
md["a"] = 1
309+
md["b"] = 2
310+
md["c"] = 3
311+
print(md.get_history()) # ['a', 'b', 'c']
312+
```
313+
314+
## Заключение
315+
316+
Классы в Python предоставляют мощный и гибкий инструмент для организации кода. Они сочетают в себе:
317+
318+
- **Простоту** — интуитивно понятный синтаксис
319+
- **Гибкость** — динамическое добавление атрибутов, множественное наследование
320+
- **Мощь** — магические методы для кастомизации поведения
321+
- **Элегантность** — декораторы и свойства для читаемого кода
322+
323+
Помните: классы — это инструмент, а не серебряная пуля. Используйте их там, где они действительно упрощают код и делают его более понятным!
324+
325+
> "Простота — залог надежности." — Эдсгер Дейкстра

0 commit comments

Comments
 (0)