Skip to content

Commit 67a2f2f

Browse files
committed
Add python first chapters
1 parent 0deb0b1 commit 67a2f2f

File tree

4 files changed

+782
-0
lines changed

4 files changed

+782
-0
lines changed

src/SUMMARY.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,14 @@
3030
- [Установка Arch Linux](./linux/install-arch-linux.md)
3131
- [Внутреннее устройство Linux](./linux/structure.md)
3232

33+
34+
# Погружаемся в Python
35+
36+
- [Объекты и память](./dev/python/objects.md)
37+
- [Коллекции](./dev/python/collections.md)
38+
- [Асимптотическая сложность](./dev/python/o-notation.md)
39+
40+
3341
# Учимся у других
3442

3543
- [Коды и скрипты](./examples/intro.md)

src/dev/python/collections.md

Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
# Коллекции в Python: от основ к тонкостям
2+
3+
Коллекции — это основа хранения и обработки данных в Python. Понимание их внутреннего устройства, сильных и слабых сторон — ключ к написанию эффективного и идиоматичного кода.
4+
5+
## Что такое коллекция?
6+
7+
В Python **коллекция** — это объект, который одновременно является:
8+
- **Контейнером** (`Container`) — поддерживает оператор `in` для проверки вхождения.
9+
- **Итерируемым объектом** (`Iterable`) — его элементы можно перебирать в цикле.
10+
- **Объектом ограниченной длины** (`Sized`) — поддерживает функцию `len()`.
11+
12+
```python
13+
from collections.abc import Collection
14+
15+
# Проверим, является ли список коллекцией
16+
print(isinstance([1, 2, 3], Collection)) # True
17+
```
18+
19+
### Любопытные исключения
20+
21+
- **Интервал чисел** может быть контейнером, но не быть итерируемым или иметь длину.
22+
- **Генератор** является итерируемым, но не контейнером и не имеет длины.
23+
24+
```python
25+
# Пример: Интервал как контейнер
26+
from dataclasses import dataclass
27+
28+
@dataclass
29+
class Interval:
30+
a: float
31+
b: float
32+
33+
def __contains__(self, x):
34+
return self.a < x < self.b
35+
36+
interval = Interval(0, 1)
37+
print(0.5 in interval) # True
38+
print(len(interval)) # TypeError: object of type 'Interval' has no len()
39+
```
40+
41+
## Иерархия коллекций
42+
43+
Стандартная библиотека Python определяет абстрактные базовые классы (ABC) для классификации коллекций:
44+
45+
```
46+
Container -> Iterable -> Sized -> Collection
47+
|
48+
--------+--------
49+
| |
50+
Sequence Mapping
51+
```
52+
53+
- **Sequence** (Последовательности): элементы упорядочены и доступны по индексу (списки, кортежи, строки).
54+
- **Mapping** (Отображения): хранят пары «ключ-значение» (словари).
55+
56+
## Списки (list): универсальные и изменяемые
57+
58+
Списки — это, пожалуй, самая часто используемая коллекция.
59+
60+
### Неочевидные особенности инициализации
61+
62+
```python
63+
# Кажется, что это создаст матрицу 2x1
64+
chunks = [[0]] * 2
65+
chunks[0][0] = 42
66+
print(chunks) # [[42], [42]] Оба элемента ссылаются на один и тот же список!
67+
68+
# Правильные способы инициализации матрицы:
69+
correct_chunks = [[0] for _ in range(2)]
70+
correct_chunks = [[0]] * 2 # Так делать нельзя, если планируется изменение вложенных списков!
71+
```
72+
73+
### Эффективные операции
74+
75+
- `append(item)` и `pop()` — амортизированная сложность O(1).
76+
- `insert(0, item)` и `pop(0)` — сложность O(n), так как требуют сдвига всех элементов.
77+
- `extend(iterable)` эффективнее, чем многократный вызов `append()`.
78+
79+
**Совет:** Используйте `collections.deque`, если вам нужны частые операции с обоих концов.
80+
81+
## Кортежи (tuple): неизменяемые и хэшируемые
82+
83+
Кортежи не только защищают данные от изменений, но и могут быть использованы как ключи в словарях или элементы множеств, так как они **хэшируемы**.
84+
85+
### Распаковка кортежей — мощный инструмент
86+
87+
```python
88+
# Распаковка с упаковкой «лишних» элементов в переменную
89+
first, second, *rest = range(10)
90+
print(first, second, rest) # 0 1 [2, 3, 4, 5, 6, 7, 8, 9]
91+
92+
# Игнорирование ненужных значений
93+
x, _, z = (1, 2, 3)
94+
95+
# Распаковка в аргументы функции
96+
def greet(name, greeting):
97+
return f"{greeting}, {name}!"
98+
99+
person = ("Alice", "Hello")
100+
print(greet(*person)) # "Hello, Alice!"
101+
```
102+
103+
### Именованные кортежи (namedtuple)
104+
105+
`collections.namedtuple` — это фабрика классов, создающая подтип кортежа с именованными полями. Это делает код самодокументируемым.
106+
107+
```python
108+
from collections import namedtuple
109+
110+
Point = namedtuple('Point', ['x', 'y'])
111+
p = Point(10, y=20)
112+
print(p.x, p.y) # 10 20
113+
print(p._asdict()) # {'x': 10, 'y': 20}
114+
```
115+
116+
## Множества (set): уникальность и скорость
117+
118+
Множества реализованы как хэш-таблицы, поэтому проверка вхождения (`in`) имеет среднюю сложность O(1).
119+
120+
### Неочевидные применения множеств
121+
122+
1. **Удаление дубликатов из списка** — классика, но всегда актуально.
123+
```python
124+
unique_list = list(set(duplicated_list))
125+
```
126+
127+
2. **Подсчет общих элементов** между двумя коллекциями.
128+
```python
129+
common = set(list1) & set(list2)
130+
```
131+
132+
3. **Фильтрация «мусора»** при разборе данных.
133+
```python
134+
valid_tags = {'python', 'tutorial', 'advanced'}
135+
tags = ['python', 'beginner', 'advanced']
136+
filtered_tags = [tag for tag in tags if tag in valid_tags]
137+
# ['python', 'advanced']
138+
```
139+
140+
### frozenset: неизменяемое множество
141+
142+
Поскольку обычные множества изменяемы и, следовательно, нехэшируемы, их нельзя вложить в другие множества или использовать как ключи словаря. Для этого нужен `frozenset`.
143+
144+
```python
145+
# Множество множеств? Нет.
146+
# {set([1,2]), set([3,4])} # TypeError: unhashable type: 'set'
147+
148+
# А так — можно.
149+
fs1 = frozenset([1, 2])
150+
fs2 = frozenset([3, 4])
151+
meta_set = {fs1, fs2} # Valid
152+
```
153+
154+
## Словари (dict): сердце Python
155+
156+
Современные словари (Python 3.7+) сохраняют **порядок добавления** элементов.
157+
158+
### Малоизвестные возможности словарей
159+
160+
1. **Метод `setdefault()`** — проверяет наличие ключа и, если его нет, устанавливает значение за один проход по хэш-таблице.
161+
162+
```python
163+
data = {}
164+
# Классический, но неэффективный способ
165+
if 'key' not in data:
166+
data['key'] = []
167+
data['key'].append(1)
168+
169+
# Эффективный способ с setdefault
170+
data.setdefault('key', []).append(1)
171+
```
172+
173+
2. **Метод `popitem()`** — удаляет и возвращает пару `(ключ, значение)` в порядке LIFO (последним пришел — первым ушел). Полезно для обработки данных в обратном порядке.
174+
175+
3. **Словарные включения (Dict Comprehensions)** — компактный и выразительный синтаксис.
176+
177+
```python
178+
squares = {x: x*x for x in range(5)}
179+
# {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
180+
```
181+
182+
### Коллекции из модуля `collections`
183+
184+
Модуль `collections` предоставляет специализированные типы данных, которые расширяют возможности стандартных коллекций.
185+
186+
- **`defaultdict`** — словарь с заводской функцией для отсутствующих ключей.
187+
```python
188+
from collections import defaultdict
189+
graph = defaultdict(list)
190+
graph['a'].append('b') # Не нужно проверять, есть ли ключ 'a'
191+
```
192+
193+
- **`Counter`** — подкласс словаря для подсчета хэшируемых объектов.
194+
```python
195+
from collections import Counter
196+
words = ['apple', 'banana', 'apple', 'orange']
197+
word_count = Counter(words)
198+
print(word_count.most_common(1)) # [('apple', 2)]
199+
```
200+
201+
- **`deque`** — двусторонняя очередь. Идеальна для очередей (FIFO) и стеков (LIFO).
202+
```python
203+
from collections import deque
204+
queue = deque([1, 2, 3])
205+
queue.append(4) # O(1)
206+
queue.popleft() # O(1) - в отличие от списка!
207+
```
208+
209+
- **`OrderedDict`** — словарь, который помнит порядок. В Python 3.7+ обычный `dict` тоже упорядочен, но `OrderedDict` имеет дополнительные методы (`move_to_end`, `popitem(last=True/False)`).
210+
211+
## Заключение
212+
213+
Выбор правильной коллекции — это не просто вопрос синтаксиса. Это вопрос эффективности, читаемости и корректности вашего кода.
214+
215+
- Используйте **списки** для упорядоченных коллекций, которые могут изменяться.
216+
- Используйте **кортежи** для фиксированных данных или когда нужны хэшируемые объекты.
217+
- Используйте **множества** для проверки уникальности и быстрого поиска.
218+
- Используйте **словари** для отображений ключей на значения.
219+
- Не забывайте о **специализированных коллекциях** из модуля `collections` для решения специфических задач.
220+
221+
Глубокое понимание коллекций позволит вам писать код, который не только работает, но и работает **хорошо**.

0 commit comments

Comments
 (0)