<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Уроки программирования - Системный блог</title>
	<atom:link href="https://system-blog.ru/category/uroki-programmirovaniya/feed/" rel="self" type="application/rss+xml" />
	<link>https://system-blog.ru/category/uroki-programmirovaniya/</link>
	<description>Всё о твоём Windows и Android</description>
	<lastBuildDate>Tue, 11 Nov 2025 21:44:52 +0000</lastBuildDate>
	<language>ru-RU</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.1</generator>

<image>
	<url>https://system-blog.ru/wp-content/uploads/2025/08/cropped-cropped-security-180x180-1-32x32.png</url>
	<title>Уроки программирования - Системный блог</title>
	<link>https://system-blog.ru/category/uroki-programmirovaniya/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Изучение языка программирования Python Django</title>
		<link>https://system-blog.ru/izuchenie-yazyika-programmirovaniya-python-django/</link>
					<comments>https://system-blog.ru/izuchenie-yazyika-programmirovaniya-python-django/#respond</comments>
		
		<dc:creator><![CDATA[Vit90]]></dc:creator>
		<pubDate>Tue, 11 Nov 2025 21:44:52 +0000</pubDate>
				<category><![CDATA[Уроки по Python]]></category>
		<guid isPermaLink="false">https://system-blog.ru/?p=1837</guid>

					<description><![CDATA[<p>Django — один из самых востребованных фреймворков для Python, применяемый в веб-разработке по всему миру. Спрос на специалистов, владеющих этой технологией, стабильно высок. Если вы только начинаете изучать программирование, то сочетание Python + Django — отличная отправная точка. Рассмотрим, с чего начать и как выстроить процесс обучения. Почему стоит выбрать Python Python — универсальный язык&#8230;&#160;<a href="https://system-blog.ru/izuchenie-yazyika-programmirovaniya-python-django/" rel="bookmark"><span class="screen-reader-text">Изучение языка программирования Python Django</span></a></p>
<p>Сообщение <a href="https://system-blog.ru/izuchenie-yazyika-programmirovaniya-python-django/">Изучение языка программирования Python Django</a> появились сначала на <a href="https://system-blog.ru">Системный блог</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p><b>Django</b> — один из самых востребованных фреймворков для Python, применяемый в веб-разработке по всему миру. Спрос на специалистов, владеющих этой технологией, стабильно высок. Если вы только начинаете изучать программирование, то сочетание <b>Python + Django</b> — отличная отправная точка. Рассмотрим, с чего начать и как выстроить процесс обучения.</p>
<h2>Почему стоит выбрать Python</h2>
<p>Python — универсальный язык программирования, известный своей простотой и гибкостью. Его преимущества:</p>
<ul>
<li><b>Простота изучения.</b> Интуитивно понятный синтаксис делает язык доступным даже для новичков.</li>
<li><b>Хорошая читаемость кода.</b> Код на Python легко понимать и поддерживать, что особенно важно в командных проектах.</li>
<li><b>Объектно-ориентированность и высокий уровень абстракции.</b> Позволяет сосредоточиться на логике, а не на технических деталях.</li>
<li><b>Огромное количество библиотек и модулей.</b> Есть решения для аналитики, веб-разработки, машинного обучения, автоматизации и многого другого.</li>
<li><b>Кроссплатформенность.</b> Код на Python без изменений работает на Windows, macOS и Linux.</li>
</ul>
<h2>Как начать изучение Python</h2>
<p>Первым делом стоит подобрать учебные материалы. Среди лучших книг для старта:</p>
<ul>
<li>Марк Лутц — <b>«Изучаем Python»</b> (4-е издание);</li>
<li><b>«Язык программирования Python»</b> (официальное руководство, python.org).</li>
</ul>
<p>Важно разработать план изучения и не перескакивать через непонятные темы. Каждый пропущенный момент позже приводит к ошибкам при написании кода. Освоив основы, начинайте практику: ставьте конкретные задачи — например, написать простое приложение. Такой подход помогает закрепить знания.</p>
<p>Запуск программ можно выполнять в любой удобной среде: <b>Visual Studio Code, PyCharm</b> или встроенной консоли Python. Отладка и поиск ошибок — неотъемлемая часть обучения, поэтому важно относиться к ней спокойно и системно.</p>
<h2>Переход к Django</h2>
<p>Когда базовые принципы Python усвоены, можно переходить к фреймворку <b>Django</b>. Это мощный каркас для быстрой разработки веб-приложений. Он подходит как для небольших сайтов, так и для крупных корпоративных систем.</p>
<h3>Основные преимущества Django</h3>
<ul>
<li><b>Быстрая разработка.</b> Django содержит множество готовых инструментов и шаблонов для типовых задач.</li>
<li><b>Гибкость в работе с данными.</b> Поддерживает разные форматы и базы данных.</li>
<li><b>Высокий уровень безопасности.</b> Защищает пароли, сессии и пользовательские данные.</li>
<li><b>Модульная архитектура.</b> Легко расширяется и адаптируется под конкретные задачи.</li>
<li><b>Минимум дублирования кода.</b> Принцип DRY («Don’t Repeat Yourself») заложен в основу фреймворка.</li>
</ul>
<h2>Пошаговое изучение Django</h2>
<p>Обучение Django стоит начинать с практики. После установки среды разработки рекомендуется двигаться по следующему плану:</p>
<ol>
<li>Создание структуры сайта и базового проекта.</li>
<li>Изучение моделей данных (ORM).</li>
<li>Настройка панели администратора.</li>
<li>Создание страниц, списков и маршрутов.</li>
<li>Реализация авторизации и регистрации пользователей.</li>
<li>Работа с формами и шаблонами.</li>
<li>Тестирование и отладка приложения.</li>
<li>Вопросы безопасности и развертывания.</li>
</ol>
<p>Большинство задач в Django решаются практическими примерами, а теории здесь гораздо меньше, чем при изучении самого Python. Благодаря этому переход от обучения к созданию реальных сайтов происходит быстро.</p>
<h2>Заключение</h2>
<p>Изучение Python и Django — это путь от простоты к профессионализму. Начните с основ языка, переходите к практике, затем погружайтесь во фреймворк. Django открывает широкие возможности для веб-разработки и позволяет не только создавать проекты, но и строить успешную карьеру в IT. Уделяйте время практике — и первые результаты не заставят себя ждать.</p>
<p>Сообщение <a href="https://system-blog.ru/izuchenie-yazyika-programmirovaniya-python-django/">Изучение языка программирования Python Django</a> появились сначала на <a href="https://system-blog.ru">Системный блог</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://system-blog.ru/izuchenie-yazyika-programmirovaniya-python-django/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Генераторы в Python: полное руководство с практикой</title>
		<link>https://system-blog.ru/generatory-v-python-polnoe-rukovodstvo-s-praktikoj/</link>
					<comments>https://system-blog.ru/generatory-v-python-polnoe-rukovodstvo-s-praktikoj/#respond</comments>
		
		<dc:creator><![CDATA[Vit90]]></dc:creator>
		<pubDate>Wed, 05 Nov 2025 20:33:47 +0000</pubDate>
				<category><![CDATA[Уроки по Python]]></category>
		<guid isPermaLink="false">https://system-blog.ru/?p=1123</guid>

					<description><![CDATA[<p>Генераторы — способ писать итераторы просто и эффективно. Они отдают элементы по требованию, сберегают память и делают код короче. В основе — оператор yield, который приостанавливает выполнение функции и сохраняет её локальное состояние до следующего вызова next(). В этом расширенном руководстве вы разберёте базовый синтаксис и протокол итератора, генераторные выражения, конвейеры (pipeline), управление генератором через&#8230;&#160;<a href="https://system-blog.ru/generatory-v-python-polnoe-rukovodstvo-s-praktikoj/" rel="bookmark"><span class="screen-reader-text">Генераторы в Python: полное руководство с практикой</span></a></p>
<p>Сообщение <a href="https://system-blog.ru/generatory-v-python-polnoe-rukovodstvo-s-praktikoj/">Генераторы в Python: полное руководство с практикой</a> появились сначала на <a href="https://system-blog.ru">Системный блог</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Генераторы — способ писать итераторы просто и эффективно. Они отдают элементы по требованию, сберегают память и делают код короче. В основе — оператор <b>yield</b>, который приостанавливает выполнение функции и сохраняет её локальное состояние до следующего вызова <b>next()</b>. В этом расширенном руководстве вы разберёте базовый синтаксис и протокол итератора, генераторные выражения, конвейеры (pipeline), управление генератором через <b>send</b>/<b>throw</b>/<b>close</b>, делегирование <b>yield from</b>, тестирование и производительность, типичные ошибки, работу с файлами и сетевыми потоками, а также интеграцию с <b>itertools</b> и приёмы для production-кода.</p>
<h2>1. Что такое генератор и зачем он нужен</h2>
<p>Генератор — функция, внутри которой есть <b>yield</b>. Каждый вызов <b>next()</b> продолжает исполнение до ближайшего <b>yield</b>, возвращая очередной элемент и «замораживая» стек. Это позволяет строить ленивые конвейеры обработки данных и обходиться без промежуточных списков.</p>
<pre><code>def countdown(n):
    while n &gt; 0:
        yield n
        n -= 1

it = countdown(3)
print(next(it))  # 3
print(next(it))  # 2
print(list(it))  # [1] </code></pre>
<ul>
<li><b>Ленивость:</b> вычисление происходит в момент потребления.</li>
<li><b>Экономия памяти:</b> держим в памяти только текущий элемент.</li>
<li><b>Простота:</b> протокол итератора реализован «сам собой» без классов.</li>
</ul>
<h2>2. Разница между return и yield</h2>
<p><b>return</b> завершает функцию один раз и навсегда, возвращая единственное значение. <b>yield</b> «режет» результат на порции — сколько запросили, столько и отдали. Если в генераторе сделать <b>return value</b>, это приведёт к завершению с <b>StopIteration(value)</b> — полезно при делегировании через <b>yield from</b>.</p>
<pre><code>def once():
    yield 1
    return 99  # значение окажется в StopIteration.value

g = once()
print(next(g))           # 1
try:
next(g)
except StopIteration as e:
print(e.value)       # 99 </code></pre>
<h2>3. next(), завершение и StopIteration</h2>
<p>Цикл <b>for</b> сам вызывает <b>next()</b> и ловит <b>StopIteration</b>. Вручную это выглядит так:</p>
<pre><code>def pair():
    yield "A"
    yield "B"

g = pair()
print(next(g))  # A
print(next(g))  # B
try:
print(next(g))      # генератор исчерпан
except StopIteration:
print("done") </code></pre>
<p><b>Правило PEP 479:</b> не поднимайте <b>StopIteration</b> внутри генератора вручную для выхода — используйте <b>return</b>. Явный <b>StopIteration</b> в теле генератора может быть преобразован в <b>RuntimeError</b>.</p>
<h2>4. Генератор вместо класса-итератора</h2>
<p>Тот же эффект можно получить классом с <b>__iter__</b> и <b>__next__</b>, но генератор проще:</p>
<pre><code># Классический итератор
class Squares:
    def __init__(self, n):
        self.n = n
        self.i = 1
    def __iter__(self):
        return self
    def __next__(self):
        if self.i &gt; self.n:
            raise StopIteration
        v = self.i * self.i
        self.i += 1
        return v

print(list(Squares(5)))

# Эквивалент генератором

def squares(n):
i = 1
while i <= n:
yield i * i
i += 1

print(list(squares(5))) </code></pre>
<h2>5. Генераторные выражения и списковые включения</h2>
<p>Списковое включение создаёт список немедленно. Генераторное выражение создаёт итератор, который выдаёт элементы по мере надобности.</p>
<pre><code># Список: память ∝ числу элементов
data = [x*x for x in range(1_000_000)]

# Генератор: память почти константная

data_gen = (x*x for x in range(1_000_000))

print(sum(data_gen))  # потоковое потребление </code></pre>
<ul>
<li>Если результат нужен целиком и многократно — список уместнее.</li>
<li>Если нужен одноразовый проход — генератор экономит ресурсы.</li>
</ul>
<h2>6. Ленивые вычисления на больших данных</h2>
<p>Генераторы особенно полезны для больших файлов и потоков. Вы читаете по строке, фильтруете, преобразуете и агрегируете без промежуточных структур.</p>
<pre><code>def read_lines(path):
    with open(path, "r", encoding="utf-8") as f:
        for line in f:
            yield line.rstrip("n")

def grep(lines, needle):
for line in lines:
if needle in line:
yield line

def to_fields(lines, sep=";"):
for line in lines:
yield line.split(sep)

for fields in to_fields(grep(read_lines("app.log"), "ERROR")):
print(fields[:3]) </code></pre>
<h2>7. Конвейеры (pipeline) из генераторов</h2>
<p>Стройте небольшие одноцелевые генераторы и комбинируйте их:</p>
<pre><code>def numbers():
    i = 0
    while True:
        yield i
        i += 1

def only_even(it):
for x in it:
if x % 2 == 0:
yield x

def square(it):
for x in it:
yield x * x

pipe = square(only_even(numbers()))
for x in pipe:
if x > 100:
break
print(x) </code></pre>
<p>Достоинство такого подхода — читаемость и лёгкая тестируемость каждого звена.</p>
<h2>8. Управление генератором: send, throw, close</h2>
<p>Генератор поддерживает двустороннее взаимодействие. Через <b>send(value)</b> можно передать значение в точку последнего <b>yield</b>. <b>throw(exc)</b> вбрасывает исключение внутрь. <b>close()</b> завершает генератор с <b>GeneratorExit</b>.</p>
<pre><code>def accumulator():
    total = 0
    try:
        while True:
            x = (yield total)  # получаем число через send
            if x is None:
                break
            total += x
    finally:
        # здесь можно освободить ресурсы
        pass

g = accumulator()
print(next(g))    # 0
print(g.send(10)) # 10
print(g.send(5))  # 15
g.close() </code></pre>
<p>Не подавляйте <b>GeneratorExit</b> и не делайте в блоке finally долгих операций — генератор закрывается как часть механизма очистки.</p>
<h2>9. Делегирование: yield from и возврат значения</h2>
<p><b>yield from</b> проксирует итерацию и методы управления в подгенератор, а также возвращает его итоговое значение (через <b>return</b> в подгенераторе).</p>
<pre><code>def sub():
    total = 0
    while True:
        x = (yield)
        if x is None:
            return total
        total += x

def super_acc():
# получим финальный итог из подгенератора
result = yield from sub()
yield result

g = super_acc()
next(g)
g.send(3)
g.send(7)
print(g.send(None))  # 10 </code></pre>
<h2>10. Интеграция с itertools</h2>
<p>Модуль <b>itertools</b> идеально сочетается с генераторами: <b>count</b>, <b>cycle</b>, <b>repeat</b>, <b>islice</b>, <b>takewhile</b>, <b>dropwhile</b>, <b>chain</b>, <b>compress</b>, <b>groupby</b>, <b>accumulate</b>, <b>tee</b>, <b>zip_longest</b>, <b>product</b>, <b>permutations</b>, <b>combinations</b>.</p>
<pre><code>from itertools import islice, takewhile, accumulate, chain

def naturals():
i = 1
while True:
yield i
i += 1

squares = (x*x for x in naturals())
first_ten = list(islice(squares, 10))
print(first_ten)

prefix_sums = list(islice(accumulate(naturals()), 5))
print(prefix_sums)

print(list(chain([0], [1, 2], range(3, 6)))) </code></pre>
<p><b>tee</b> делает «копии» итератора, но имейте в виду, что одна копия может буферизовать элементы для другой — это может вылиться в заметное потребление памяти.</p>
<h2>11. Рецепты генераторов для production</h2>
<h3>11.1. Скользящее окно</h3>
<pre><code>from collections import deque

def sliding_window(it, size):
buf = deque(maxlen=size)
for x in it:
buf.append(x)
if len(buf) == size:
yield tuple(buf)

print(list(sliding_window(range(1, 7), 3))) </code></pre>
<h3>11.2. Пакетирование (batch) потока</h3>
<pre><code>def batched(it, n):
    batch = []
    for x in it:
        batch.append(x)
        if len(batch) == n:
            yield batch
            batch = []
    if batch:
        yield batch

for b in batched(range(1, 8), 3):
print(b) </code></pre>
<h3>11.3. Уникализация с сохранением порядка</h3>
<pre><code>def dedupe(it, key=None):
    seen = set()
    for x in it:
        k = x if key is None else key(x)
        if k not in seen:
            seen.add(k)
            yield x

print(list(dedupe(["a","b","a","c","b"]))) </code></pre>
<h3>11.4. Слияние отсортированных потоков</h3>
<pre><code>import heapq

def merge_sorted(*iters):
heap = []
for it_index, it in enumerate(map(iter, iters)):
try:
first = next(it)
heap.append((first, it_index, it))
except StopIteration:
pass
heapq.heapify(heap)
while heap:
val, idx, it = heapq.heappop(heap)
yield val
try:
nxt = next(it)
heapq.heappush(heap, (nxt, idx, it))
except StopIteration:
pass

print(list(merge_sorted([1,4,9], [2,6], [0,3,7,8]))) </code></pre>
<h3>11.5. Потоковый разбор CSV</h3>
<pre><code>import csv

def read_csv(path, encoding="utf-8"):
with open(path, newline="", encoding=encoding) as f:
rdr = csv.DictReader(f)
for row in rdr:
yield row

def select(it, *cols):
for row in it:
yield {c: row[c] for c in cols}

def where(it, pred):
for row in it:
if pred(row):
yield row

rows = where(select(read_csv("users.csv"), "id", "age"), lambda r: int(r["age"]) >= 18)
for r in rows:
print(r) </code></pre>
<h3>11.6. Хвост файла (tail -f)</h3>
<pre><code>import time

def follow(path):
with open(path, "r", encoding="utf-8") as f:
f.seek(0, 2)  # в конец
while True:
line = f.readline()
if not line:
time.sleep(0.2)
continue
yield line.rstrip("n")

for line in follow("app.log"):
if "ERROR" in line:
print(line) </code></pre>
<h3>11.7. Ограничитель скорости (rate limiter)</h3>
<pre><code>import time

def rate_limit(it, per_sec):
interval = 1.0 / per_sec
last = 0.0
for x in it:
now = time.time()
delta = now - last
if delta < interval:
time.sleep(interval - delta)
yield x
last = time.time()

for x in rate_limit(range(5), per_sec=2):
print(x, time.time()) </code></pre>
<h3>11.8. Экспоненциальный бэкофф для повторов</h3>
<pre><code>import random, time

def retries(max_tries=5, base=0.1, factor=2.0):
delay = base
for attempt in range(1, max_tries + 1):
yield attempt, delay
delay *= factor

def unreliable():
return random.random() < 0.3  # 30% «успех»

for attempt, delay in retries():
if unreliable():
print("ok on try", attempt)
break
print("fail, sleep", delay)
time.sleep(delay) </code></pre>
<h2>12. Контекстные менеджеры на основе генераторов</h2>
<p>Декоратор <b>contextlib.contextmanager</b> позволяет писать контекстные менеджеры как генераторы с одним <b>yield</b>: всё до <b>yield</b> — «вход», всё после — «выход».</p>
<pre><code>from contextlib import contextmanager

@contextmanager
def opened(path, mode="r", encoding="utf-8"):
f = open(path, mode, encoding=encoding)
try:
yield f
finally:
f.close()

with opened("file.txt") as f:
print(f.readline()) </code></pre>
<h2>13. Аннотации типов для генераторов</h2>
<p>Используйте <b>typing.Generator[Y, S, R]</b>, где <b>Y</b> — тип выдаваемых значений, <b>S</b> — тип, передаваемый через <b>send</b>, <b>R</b> — тип «return» (доступен как <b>StopIteration.value</b> при делегировании).</p>
<pre><code>from typing import Generator

def gen() -> Generator[int, None, None]:
yield 1
yield 2 </code></pre>
<h2>14. Тестирование и измерение</h2>
<p>Генераторы легко тестировать через материализацию небольших кусочков, а производительность — через <b>timeit</b>.</p>
<pre><code>import timeit

setup = "nums = range(200_000)"
code_list = "sum([x*x for x in nums])"
code_gen  = "sum(x*x for x in nums)"

print("list:", timeit.timeit(code_list, setup=setup, number=5))
print("gen :", timeit.timeit(code_gen,  setup=setup, number=5)) </code></pre>
<p>Идея: если вы в итоге всё равно строите список целиком и дважды проходите по нему — генератор преимущества не даст. Но в одноразовых потоках он выигрывает.</p>
<h2>15. Частые ошибки и подводные камни</h2>
<ul>
<li><b>Неожиданная материализация.</b> Вызов <b>list(gen)</b> или <b>sorted(gen)</b> загружает весь поток в память.</li>
<li><b>Повторное использование.</b> Исчерпанный генератор «пуст». Создавайте новый экземпляр.</li>
<li><b>StopIteration внутри тела.</b> Для выхода используйте <b>return</b>, а не <b>raise StopIteration</b>.</li>
<li><b>Выход из finally слишком тяжёлый.</b> Не задерживайте закрытие генератора долгими операциями.</li>
<li><b>tee без оглядки на память.</b> Понимайте, что одна «ветка» может буферизовать данные для другой.</li>
<li><b>Смешение ответственности.</b> Генератор должен делать одну небольшую вещь: читать, фильтровать, преобразовывать или агрегировать.</li>
</ul>
<h2>16. Сравнение с асинхронными генераторами</h2>
<p>У обычных генераторов <b>next()</b> блокирующий. Асинхронные генераторы (<b>async def</b> с <b>yield</b>) работают с <b>async for</b> и выдают элементы по мере готовности асинхронных операций. Если у вас I/O-потоки и нужен неблокирующий код — изучайте <b>async for</b> и <b>async generators</b>. Принципы ленивости и композиции схожи, но протоколы другие.</p>
<h2>17. Расширённые приёмы диагностики</h2>
<p>У генератора есть атрибуты introspection: <b>gi_frame</b> (текущий фрейм), <b>gi_running</b> (исполняется ли сейчас), <b>gi_code</b> (объект кода). Они полезны при отладке сложных конвейеров, но в проде лучше не полагаться на них.</p>
<pre><code>def gen():
    yield 1
    yield 2

g = gen()
print(g.gi_code.co_name)  # 'gen'
print(g.gi_running)       # False
print(next(g))            # 1 </code></pre>
<h2>18. Расширенные примеры, проверенные временем</h2>
<h3>18.1. Группировка по ключу (похожие на groupby)</h3>
<pre><code>def group_by_sorted(it, key):
    it = iter(it)
    try:
        first = next(it)
    except StopIteration:
        return
    cur_key = key(first)
    bucket = [first]
    for x in it:
        k = key(x)
        if k != cur_key:
            yield cur_key, bucket
            cur_key = k
            bucket = [x]
        else:
            bucket.append(x)
    yield cur_key, bucket

data = ["a1","a2","b9","b3","c0"]
print(list(group_by_sorted(data, key=lambda s: s[0]))) </code></pre>
<h3>18.2. Разворачивание (flatten) вложенных списков</h3>
<pre><code>def flatten(nested):
    for x in nested:
        if isinstance(x, (list, tuple)):
            yield from flatten(x)
        else:
            yield x

print(list(flatten([1,[2,[3,4]],5]))) </code></pre>
<h3>18.3. Генератор мини-парсера строк</h3>
<pre><code>def tokens(s, seps=" ,;"):
    buf = []
    for ch in s:
        if ch in seps:
            if buf:
                yield "".join(buf)
                buf.clear()
        else:
            buf.append(ch)
    if buf:
        yield "".join(buf)

print(list(tokens("a, b; c  d"))) </code></pre>
<h2>19. Мини-шпаргалка</h2>
<ul>
<li><b>Базовый генератор:</b> функция с <b>yield</b>.</li>
<li><b>Протокол:</b> <b>next()</b> выдаёт значение, исчерпание — <b>StopIteration</b>.</li>
<li><b>Генераторное выражение:</b> <b>(expr for x in it if cond)</b>.</li>
<li><b>Композиция:</b> объединяйте простые генераторы в конвейер.</li>
<li><b>Управление:</b> <b>send</b>, <b>throw</b>, <b>close</b>, делегирование <b>yield from</b>.</li>
<li><b>Чистый дизайн:</b> маленькие функции, минимум побочных эффектов.</li>
<li><b>Производительность:</b> не материализуйте поток без нужды; измеряйте <b>timeit</b>.</li>
</ul>
<p>Генераторы позволяют писать быстрый и прозрачный код для потоков данных: логов, файлов, сетевых ответов, бесконечных последовательностей. Освоив <b>yield</b>, генераторные выражения, <b>yield from</b> и приёмы композиции, вы получите инструмент, который масштабируется от коротких скриптов до production-пайплайнов и ETL-процессов.</p>
<p>Сообщение <a href="https://system-blog.ru/generatory-v-python-polnoe-rukovodstvo-s-praktikoj/">Генераторы в Python: полное руководство с практикой</a> появились сначала на <a href="https://system-blog.ru">Системный блог</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://system-blog.ru/generatory-v-python-polnoe-rukovodstvo-s-praktikoj/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Синтаксис регулярных выражений в Python: понятное руководство с примерами</title>
		<link>https://system-blog.ru/sintaksis-reguljarnyh-vyrazhenij-v-python-ponjatnoe-rukovodstvo-s-primerami/</link>
					<comments>https://system-blog.ru/sintaksis-reguljarnyh-vyrazhenij-v-python-ponjatnoe-rukovodstvo-s-primerami/#respond</comments>
		
		<dc:creator><![CDATA[Vit90]]></dc:creator>
		<pubDate>Wed, 05 Nov 2025 19:47:49 +0000</pubDate>
				<category><![CDATA[Уроки по Python]]></category>
		<guid isPermaLink="false">https://system-blog.ru/?p=1121</guid>

					<description><![CDATA[<p>Регулярные выражения Регулярные выражения в Python позволяют искать, извлекать и изменять фрагменты текста по гибким шаблонам. Базовый инструмент — модуль re, который даёт полный набор операций: компиляция шаблона, поиск первого совпадения, поиск всех совпадений, замены с функцией-колбэком, разбиение строки по шаблону, безопасное экранирование. В этом руководстве вы последовательно разберёте синтаксис регулярных выражений: от символов и&#8230;&#160;<a href="https://system-blog.ru/sintaksis-reguljarnyh-vyrazhenij-v-python-ponjatnoe-rukovodstvo-s-primerami/" rel="bookmark"><span class="screen-reader-text">Синтаксис регулярных выражений в Python: понятное руководство с примерами</span></a></p>
<p>Сообщение <a href="https://system-blog.ru/sintaksis-reguljarnyh-vyrazhenij-v-python-ponjatnoe-rukovodstvo-s-primerami/">Синтаксис регулярных выражений в Python: понятное руководство с примерами</a> появились сначала на <a href="https://system-blog.ru">Системный блог</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h2>Регулярные выражения</h2>
<p>Регулярные выражения в Python позволяют искать, извлекать и изменять фрагменты текста по гибким шаблонам. Базовый инструмент — модуль <b>re</b>, который даёт полный набор операций: компиляция шаблона, поиск первого совпадения, поиск всех совпадений, замены с функцией-колбэком, разбиение строки по шаблону, безопасное экранирование. В этом руководстве вы последовательно разберёте синтаксис регулярных выражений: от символов и классов до групп, ссылок, lookaround-проверок и флагов, а затем закрепите материал на практических рецептах и анти-паттернах.</p>
<h2>1. Введение: модуль re и ключевые операции</h2>
<p>Модуль <b>re</b> входит в стандартную библиотеку Python. Его функции работают либо напрямую со строкой и шаблоном, либо с заранее скомпилированным объектом паттерна.</p>
<ul>
<li><b>re.compile(pattern, flags=0)</b> — компилирует шаблон и возвращает объект паттерна.</li>
<li><b>re.search</b> — ищет первое совпадение где угодно в строке.</li>
<li><b>re.match</b> — пытается сопоставить с начала строки (эквивалент <b>re.search</b> с якорем начала).</li>
<li><b>re.fullmatch</b> — требует совпадение всей строки целиком.</li>
<li><b>re.findall</b> — возвращает список совпадений (или кортежей групп).</li>
<li><b>re.finditer</b> — даёт итератор по объектам <b>Match</b> (экономит память, удобен для больших текстов).</li>
<li><b>re.sub</b>/<b>re.subn</b> — замены по шаблону (вторая также возвращает число замен).</li>
<li><b>re.split</b> — разбивает строку по разделителю-шаблону.</li>
<li><b>re.escape</b> — экранирует все небуквенно-цифровые символы для безопасного включения в шаблон.</li>
</ul>
<pre><code>import re

m = re.search(r"d+", "abc123xyz")
print(m.group())  # 123

p = re.compile(r"w+@w+.w+")
print(bool(p.fullmatch("[mail@example.com](mailto:mail@example.com)")))  # True </code></pre>
<h2>2. Базовый алфавит и экранирование</h2>
<p>Любой «обычный» символ в шаблоне совпадает сам с собой. Спецсимволы («метасимволы») имеют особый смысл и требуют экранирования обратной косой чертой <b></b>, если вы хотите искать их буквально:</p>
<p><b>Метасимволы:</b> . ^ $ * + ? { } [ ]  | ( )</p>
<ul>
<li><b>.</b> — любой символ, кроме перевода строки (если не указан флаг <b>re.S</b>).</li>
<li>Чтобы искать точку буквально, используйте <b>.</b>, чтобы искать обратную косую — <b>\</b>.</li>
</ul>
<pre><code>import re

print(bool(re.search(r".", "3.14")))  # True — точка буквально
print(bool(re.search(r".", "n")))     # False, если нет re.S </code></pre>
<p><b>Совет:</b> почти всегда пишите шаблоны как «сырые строки» с префиксом <b>r</b>: <b>r&#187;d+&#187;</b>. Так Python не съест ваши обратные косые, оставив их для движка регулярных выражений.</p>
<h2>3. Классы символов</h2>
<p>Квадратные скобки задают набор допустимых символов на позиции:</p>
<ul>
<li><b>[abc]</b> — любой из символов a, b или c.</li>
<li><b>[a-z]</b> — любой символ из диапазона a…z.</li>
<li><b>[^0-9]</b> — отрицание: любой символ, кроме цифры.</li>
</ul>
<p>Часто используются предопределённые классы:</p>
<ul>
<li><b>d</b> — цифра; <b>D</b> — не цифра.</li>
<li><b>w</b> — «слово» (буква, цифра, подчёркивание, и в Unicode-режиме — буквенные символы национальных алфавитов); <b>W</b> — не «слово».</li>
<li><b>s</b> — пробельный символ; <b>S</b> — не пробельный.</li>
</ul>
<pre><code>import re

print(re.findall(r"[А-ЯЁ][а-яё]+", "Привет, Мир, Ёж"))  # ['Привет', 'Мир', 'Ёж']
print(re.findall(r"w+", "alpha_123 бета"))            # ['alpha_123', 'бета'] </code></pre>
<p><b>Замечание:</b> диапазоны зависят от текущего режима Unicode/ASCII. Флаг <b>re.A</b> («ASCII») ограничит <b>w</b>, <b>d</b>, <b>s</b> до ASCII-множества.</p>
<h2>4. Якоря и границы</h2>
<ul>
<li><b>^</b> — начало строки; <b>$</b> — конец строки.</li>
<li><b>b</b> — граница слова; <b>B</b> — не граница слова.</li>
<li><b>A</b>, <b>Z</b> — начало и конец всей входной строки независимо от <b>re.M</b>.</li>
</ul>
<p>Флаг <b>re.M</b> (<b>MULTILINE</b>) меняет интерпретацию <b>^</b> и <b>$</b>: они совпадают также с началом/концом каждой строки внутри текста.</p>
<pre><code>import re

text = "foonbar"
print(bool(re.search(r"^bar$", text)))            # False
print(bool(re.search(r"^bar$", text, re.M)))      # True

print(re.findall(r"bcatb", "concatenate cat scat"))  # ['cat'] </code></pre>
<h2>5. Квантификаторы: жадные и ленивые</h2>
<ul>
<li><b>*</b> — 0 или более повторений.</li>
<li><b>+</b> — 1 или более.</li>
<li><b>?</b> — 0 или 1.</li>
<li><b>{m}</b> — ровно m раз; <b>{m,}</b> — m или более; <b>{m,n}</b> — от m до n.</li>
</ul>
<p>По умолчанию квантификаторы «жадные». Добавьте <b>?</b>, чтобы сделать их «ленивыми» и брать как можно меньше символов:</p>
<pre><code>import re

s = "<tag>one</tag><tag>two</tag>"
print(re.findall(r"<tag>.*</tag>", s))    # жадно: один большой матч
print(re.findall(r"<tag>.*?</tag>", s))   # лениво: два отдельных тега </code></pre>
<p><b>Важно:</b> ленивый квантификатор всё равно найдет максимально короткий фрагмент, который позволяет шаблону в целом совпасть. «Ленивость» — не про скорость, а про «наименьшую длину», нужную для успешного сопоставления.</p>
<h2>6. Группы, альтернативы и ссылки</h2>
<p>Скобочные группы структурируют шаблон и позволяют обращаться к подстрокам:</p>
<ul>
<li><b>(&#8230;)</b> — захватывающая группа, нумеруется с 1.</li>
<li><b>(?:&#8230;)</b> — незахватывающая группа, нужна для структурирования без сохранения подмаски.</li>
<li><b>|</b> — альтернация (логическое «или»), приоритет ниже, чем у конкатенации.</li>
<li><b>1</b>, <b>2</b> — обратные ссылки на ранее захваченные группы.</li>
<li><b>(?P&lt;name&gt;&#8230;)</b> — именованная группа; <b>(?P=name)</b> — ссылка по имени.</li>
</ul>
<pre><code>import re

m = re.search(r"(w+)=([0-9]+)", "size=42")
print(m.group(1), m.group(2))         # size 42

m = re.search(r"<(w+)>.*</1>", "<b>bold</b>")
print(bool(m))                         # True

m = re.search(r"(?P<open><w+>).*(?P=open)", "<i>text<i>")
print(bool(m))                         # True — ссылка по имени </code></pre>
<p><b>Совет:</b> используйте незахватывающие группы для структурирования, если вы не планируете обращаться к содержимому группы в коде — так <b>findall</b> вернёт сами совпадения, а не кортежи из групп.</p>
<h2>7. Просмотры (lookaround)</h2>
<p>Просмотры проверяют наличие/отсутствие контекста, но не потребляют символы:</p>
<ul>
<li><b>(?=&#8230;)</b> — положительный просмотр вперёд (должно следовать).</li>
<li><b>(?!&#8230;)</b> — отрицательный просмотр вперёд (не должно следовать).</li>
<li><b>(?&lt;=&#8230;)</b> — положительный просмотр назад (должно предшествовать).</li>
<li><b>(?&lt;!&#8230;)</b> — отрицательный просмотр назад (не должно предшествовать).</li>
</ul>
<p><b>Ограничение Python:</b> содержимое lookbehind должно быть фиксированной длины. Переменная длина внутри <b>(?&lt;=&#8230;)</b> и <b>(?&lt;!&#8230;)</b> не поддерживается движком <b>re</b>.</p>
<pre><code>import re

print(bool(re.search(r"(?<=$)d+(?:.d+)?", "Цена $12.50")))  # True — числа после $
print(bool(re.search(r"d+(?=%)", "Рост 12%")))                  # True — числа перед %
print(bool(re.search(r"bcatb(?!w)", "cat!")))                 # True — после «cat» не слово </code></pre>
<h2>8. Флаги компиляции и inline-режимы</h2>
<ul>
<li><b>re.I / re.IGNORECASE</b> — регистронезависимый поиск.</li>
<li><b>re.M / re.MULTILINE</b> — <b>^</b>/<b>$</b> работают на каждую строку.</li>
<li><b>re.S / re.DOTALL</b> — точка <b>.</b> совпадает с переводом строки.</li>
<li><b>re.X / re.VERBOSE</b> — улучшенный читаемый формат с пробелами и комментариями.</li>
<li><b>re.A / re.ASCII</b> — ограничение «буквенно-цифровых» классов до ASCII.</li>
</ul>
<pre><code>import re

print(re.findall(r"(?im) ^title: (.+) $", "Title: OnenTITLE: Two"))  # ['One', 'Two']

pattern = re.compile(r"""
^              # начало строки
(?P<user>w+)  # имя пользователя
@
(?P<host>[w.]+)  # хост
$""", re.X | re.I)

print(bool(pattern.fullmatch("[USER@EXAMPLE.com](mailto:USER@EXAMPLE.com)")))  # True </code></pre>
<h2>9. API модуля re: когда что использовать</h2>
<ul>
<li><b>match</b> — «начало строки». Частая ошибка — ожидать поиска «где угодно».</li>
<li><b>search</b> — найдёт первое совпадение в любом месте строки.</li>
<li><b>fullmatch</b> — жёсткая проверка формата всей строки.</li>
<li><b>findall</b> — быстрый список результатов, удобен в простых случаях.</li>
<li><b>finditer</b> — поток совпадений, хорош для больших данных и пост-обработки.</li>
</ul>
<pre><code>import re

text = "id=17; id=42;"
print(re.findall(r"id=(d+)", text))          # ['17', '42']

for m in re.finditer(r"id=(d+)", text):
print(m.group(1), m.span())               # 17 (3,7), 42 (11,15) </code></pre>
<p><b>sub</b> принимает строку замены или функцию, которая получает объект <b>Match</b> и возвращает подставляемую строку:</p>
<pre><code>import re

def repl(m):
return str(int(m.group(0)) * 2)

print(re.sub(r"d+", repl, "a1b2c3"))  # a2b4c6 </code></pre>
<h2>10. Сырые строки и экранирование в Python</h2>
<p>Чтобы не удваивать обратные косые, используйте сырой литерал строки с префиксом <b>r</b>. Иначе вы рискуете «потерять» часть слэшей ещё на этапе интерпретации Python.</p>
<pre><code>import re

# Плохо: в Python 'd+' — это строка d+; но 'b' и 'b' — уже разные случаи

print(bool(re.search("d+", "A1")))  # True, но читать сложно

# Хорошо:

print(bool(re.search(r"d+", "A1")))  # True </code></pre>
<h2>11. Производительность и катастрофический бэктрекинг</h2>
<p>Бэктрекинг — механизм возврата и перепробования альтернатив. Некоторые шаблоны приводят к экспоненциальному росту попыток при «почти подходящих» строках. Классический пример — вложенные квантификаторы:</p>
<pre><code>import re, time

pattern = re.compile(r"(a+)+$")  # плохой паттерн
s = "a" * 30 + "b"               # почти подходит

t = time.time()
print(bool(pattern.search(s)))
print("elapsed:", time.time() - t) </code></pre>
<p>Как снизить риск:</p>
<ul>
<li>Избегайте вложенных «широких» квантификаторов.</li>
<li>Используйте точные классы и якоря вместо «всё подряд» <b>.*</b>.</li>
<li>Ставьте «узкие» альтернации раньше «широких».</li>
<li>Валидации делите на этапы: грубая проверка длины и диапазонов до regex.</li>
</ul>
<h2>12. Практикум: готовые рецепты</h2>
<h3>Email (упрощённая проверка)</h3>
<pre><code>import re

p = re.compile(r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+.[A-Za-z]{2,}$")
print(bool(p.fullmatch("[name.surname+tag@example.co.uk](mailto:name.surname+tag@example.co.uk)"))) </code></pre>
<h3>Телефон (международный вид, гибко)</h3>
<pre><code>import re

p = re.compile(r"^+?d[ds-()]{6,}d$")
print(bool(p.fullmatch("+1 (202) 555-0188"))) </code></pre>
<h3>Дата «YYYY-MM-DD»</h3>
<pre><code>import re

p = re.compile(r"^d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]d|3[01])$")
print(bool(p.fullmatch("2025-11-05"))) </code></pre>
<h3>IPv4</h3>
<pre><code>import re

octet = r"(25[0-5]|2[0-4]d|1?d?d)"
p = re.compile(rf"^{octet}.{octet}.{octet}.{octet}$")
print(bool(p.fullmatch("192.168.0.1"))) </code></pre>
<h3>Денежная сумма с копейками</h3>
<pre><code>import re

p = re.compile(r"^d+(?:.d{2})?$")
print(bool(p.fullmatch("12.50")), bool(p.fullmatch("12"))) </code></pre>
<h3>Извлечь все числа и их позиции</h3>
<pre><code>import re

s = "x=10; y=200; z=3"
for m in re.finditer(r"d+", s):
print(m.group(), m.span()) </code></pre>
<h3>Логи: уровень и сообщение</h3>
<pre><code>import re

line = "2025-11-05 12:00:01 [INFO] Server started"
m = re.search(r"^d{4}-d{2}-d{2}s+d{2}:d{2}:d{2}s+[(w+)]s+(.*)$", line)
print(m.group(1), m.group(2))  # INFO Server started </code></pre>
<h2>13. Частые ошибки и анти-паттерны</h2>
<ul>
<li><b>Ожидать, что re.match ищет «где угодно».</b> Нет, только с начала строки. Нужен <b>re.search</b>.</li>
<li><b>Использовать .*</b> без якорей и контекста. Лучше уточнить границы: классы символов, ленивые квантификаторы, lookaround.</li>
<li><b>Забывать про сырые строки r''.</b> Иначе получите ошибки экранирования.</li>
<li><b>Неправильно составленные классы и диапазоны.</b> Например, <b>[A-z]</b> включает лишние символы между Z и a; корректно <b>[A-Za-z]</b>.</li>
<li><b>Слепо верить findall.</b> Если в шаблоне есть группы, <b>findall</b> вернёт кортежи групп, а не целые совпадения. Добавьте <b>(?:...)</b> или используйте <b>finditer</b>.</li>
<li><b>Парсить HTML одной регуляркой.</b> Для сложных форматов используйте профильные парсеры, а regex — точечно.</li>
</ul>
<h2>14. Когда регулярки Python не хватает: модуль regex</h2>
<p>Сторонний модуль <b>regex</b> (устанавливается через pip) расширяет возможности: поддерживает possessive-квантификаторы, условные проверки, «правильные» пересечения классов, улучшенные свойства Unicode и др. Если вам нужны расширенные функции и строгая производительность, рассмотрите его. Однако имейте в виду различия синтаксиса и поведения при миграции шаблонов между <b>re</b> и <b>regex</b>.</p>
<h2>15. Краткая шпаргалка по синтаксису</h2>
<ul>
<li><b>Символы:</b> обычные буквы и цифры совпадают сами с собой; спецсимволы экранируйте <b></b>.</li>
<li><b>Классы:</b> <b>[...]</b>, <b>[^...]</b>, диапазоны <b>a-z</b>; предопределённые <b>d D w W s S</b>.</li>
<li><b>Якоря:</b> <b>^</b>, <b>$</b>, <b>A</b>, <b>Z</b>, границы <b>b</b>, <b>B</b>.</li>
<li><b>Квантификаторы:</b> <b>* + ? {m} {m,} {m,n}</b> и ленивые версии с <b>?</b>.</li>
<li><b>Группы:</b> <b>(...)</b>, незахватывающие <b>(?:...)</b>, именованные <b>(?P&lt;name&gt;...)</b>, ссылки <b>1</b>, <b>(?P=name)</b>.</li>
<li><b>Просмотры:</b> <b>(?=...)</b>, <b>(?!...)</b>, <b>(?&lt;=...)</b>, <b>(?&lt;!...)</b> (lookbehind — фиксированной длины).</li>
<li><b>Флаги:</b> <b>re.I</b>, <b>re.M</b>, <b>re.S</b>, <b>re.X</b>, <b>re.A</b>; inline <b>(?iLmsx)</b>.</li>
<li><b>API:</b> <b>compile</b>, <b>search</b>, <b>match</b>, <b>fullmatch</b>, <b>findall</b>, <b>finditer</b>, <b>split</b>, <b>sub</b>, <b>escape</b>.</li>
</ul>
<p>Теперь у вас есть системная картина синтаксиса регулярных выражений в Python и практические шаблоны для типовых задач. При проектировании паттернов начинайте с чётких границ и классов символов, пользуйтесь «сырыми» строками и по возможности избегайте вложенных квантификаторов. Для сложных схем держите под рукой <b>finditer</b>, именованные группы и lookaround — они делают код короче и точнее.</p>
<p>Сообщение <a href="https://system-blog.ru/sintaksis-reguljarnyh-vyrazhenij-v-python-ponjatnoe-rukovodstvo-s-primerami/">Синтаксис регулярных выражений в Python: понятное руководство с примерами</a> появились сначала на <a href="https://system-blog.ru">Системный блог</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://system-blog.ru/sintaksis-reguljarnyh-vyrazhenij-v-python-ponjatnoe-rukovodstvo-s-primerami/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Классы и объекты в Python: полное руководство по ООП с примерами для практики</title>
		<link>https://system-blog.ru/klassy-i-obekty-v-python-polnoe-rukovodstvo-po-oop-s-primerami-dlja-praktiki/</link>
					<comments>https://system-blog.ru/klassy-i-obekty-v-python-polnoe-rukovodstvo-po-oop-s-primerami-dlja-praktiki/#respond</comments>
		
		<dc:creator><![CDATA[Vit90]]></dc:creator>
		<pubDate>Wed, 05 Nov 2025 18:48:20 +0000</pubDate>
				<category><![CDATA[Уроки по Python]]></category>
		<guid isPermaLink="false">https://system-blog.ru/?p=1115</guid>

					<description><![CDATA[<p>Классы и объекты в Python: полное практическое руководство Этот материал объясняет ООП на Python последовательно и без «магии». Разберём разницу между классом и объектом, принципы ООП, синтаксис class, конструктор __init__ и роль self, атрибуты и методы, уровни доступа по соглашениям, наследование, множественное наследование и порядок разрешения методов (MRO), полиморфизм, инкапсуляцию через @property и дескрипторы, dataclasses,&#8230;&#160;<a href="https://system-blog.ru/klassy-i-obekty-v-python-polnoe-rukovodstvo-po-oop-s-primerami-dlja-praktiki/" rel="bookmark"><span class="screen-reader-text">Классы и объекты в Python: полное руководство по ООП с примерами для практики</span></a></p>
<p>Сообщение <a href="https://system-blog.ru/klassy-i-obekty-v-python-polnoe-rukovodstvo-po-oop-s-primerami-dlja-praktiki/">Классы и объекты в Python: полное руководство по ООП с примерами для практики</a> появились сначала на <a href="https://system-blog.ru">Системный блог</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h2>Классы и объекты в Python: полное практическое руководство</h2>
<p>Этот материал объясняет ООП на Python последовательно и без «магии». Разберём разницу между классом и объектом, принципы ООП, синтаксис <b>class</b>, конструктор <b>__init__</b> и роль <b>self</b>, атрибуты и методы, уровни доступа по соглашениям, наследование, множественное наследование и порядок разрешения методов (MRO), полиморфизм, инкапсуляцию через <b>@property</b> и дескрипторы, <b>dataclasses</b>, спецметоды data model, перегрузку операторов, сравнение и хеширование, <b>__slots__</b>, <b>__new__</b> и метаклассы, сериализацию, контекстные менеджеры, а также ошибки и стили кодирования. Примеры даны в минималистичной форме, чтобы вы могли сразу переносить их в рабочие проекты.</p>
<h2>1. Объекты и классы</h2>
<p><b>Класс</b> — шаблон, описывающий состояние (атрибуты) и поведение (методы). <b>Объект</b> — экземпляр класса, содержащий конкретные данные. В Python «всё — объект»: числа, функции, модули, классы.</p>
<pre><code class="language-python">class Car:
    pass

car = Car()
print(isinstance(car, Car))  # True </code></pre>
<p>Класс определяет контракт: какие поля и методы доступны, какие значения допустимы, какие инварианты должны сохраняться.</p>
<h2>2. Четыре принципа ООП</h2>
<ul>
<li><b>Абстракция</b>: скрываем детали реализации, оставляем существенное.</li>
<li><b>Инкапсуляция</b>: ограничиваем прямой доступ к состоянию, используем методы/свойства.</li>
<li><b>Наследование</b>: переиспользуем код предков.</li>
<li><b>Полиморфизм</b>: единый интерфейс — разные реализации.</li>
</ul>
<pre><code class="language-python">class Animal:
    def sound(self) -&gt; str:
        raise NotImplementedError

class Dog(Animal):
def sound(self) -> str:
return "woof"

class Cat(Animal):
def sound(self) -> str:
return "meow"

def speak(x: Animal) -> None:
print(x.sound())

speak(Dog())
speak(Cat()) </code></pre>
<h2>3. Синтаксис class и структура класса</h2>
<p>Класс можно объявить без скобок наследования или с ними. Докстрока кратко фиксирует назначение и инварианты.</p>
<pre><code class="language-python">class ClassName(Base1, Base2):
    """Краткое описание, инварианты и ожидания по использованию."""
    VERSION = 1  # атрибут класса

```
def __init__(self, x: int):
    self.x = x  # атрибут экземпляра

def method(self) -&gt; int:
    return self.x * self.VERSION
```

</code></pre>
<ul>
<li>Имена классов — <b>CapWords</b>: <code>HttpClient</code>, <code>OrderService</code>.</li>
<li>Методы и поля — <b>snake_case</b>: <code>max_items</code>, <code>load_data</code>.</li>
<li>Старайтесь создавать атрибуты только в <b>__init__</b>, чтобы структура экземпляра была очевидной.</li>
</ul>
<h2>4. Конструктор __init__ и self</h2>
<p><b>__init__</b> инициализирует состояние, <b>self</b> — ссылка на текущий объект.</p>
<pre><code class="language-python">class User:
    def __init__(self, username: str, is_active: bool = True):
        self.username = username
        self.is_active = is_active

u = User("alice")
print(u.username, u.is_active) </code></pre>
<p>Не путайте <b>__init__</b> и <b>__new__</b>: первый настраивает уже созданный объект, второй создаёт его (чаще нужен для неизменяемых типов).</p>
<pre><code class="language-python">class Percentage:
    def __init__(self, value: float):
        if not (0.0 &lt;= value &lt;= 100.0):
            raise ValueError("Процент от 0 до 100")
        self.value = value
</code></pre>
<ul>
<li>Не используйте изменяемые объекты как значения по умолчанию. Паттерн: <code>items=None</code> и внутри <code>self.items = [] if items is None else list(items)</code>.</li>
<li>Держите конструктор коротким: валидация + присваивания. Тяжёлую инициализацию выносите в методы-фабрики/класса.</li>
</ul>
<h2>5. Атрибуты: уровня класса и уровня экземпляра</h2>
<p><b>Атрибуты класса</b> общие для всех экземпляров. <b>Атрибуты экземпляра</b> — уникальны для объекта.</p>
<pre><code class="language-python">class Config:
    DEFAULT_TIMEOUT = 5  # статическое поле (уровень класса)

```
def __init__(self, timeout: int | None = None):
    self.timeout = timeout if timeout is not None else Config.DEFAULT_TIMEOUT
```

a = Config()
b = Config(timeout=10)
print(a.timeout, b.timeout, Config.DEFAULT_TIMEOUT)  # 5 10 5 </code></pre>
<p>Если вам нужно общее для всех экземпляров, держите на уровне класса. Если значение зависит от конкретного объекта — храните на <b>self</b>.</p>
<h2>6. Методы экземпляра, @classmethod и @staticmethod</h2>
<pre><code class="language-python">class Path:
    def __init__(self, parts: list[str]):
        self.parts = parts

```
def join(self, *parts: str) -&gt; "Path":      # метод экземпляра
    return Path(self.parts + list(parts))

@classmethod
def from_str(cls, s: str) -&gt; "Path":        # альтернативный конструктор
    return cls(s.split("/"))

@staticmethod
def is_abs(s: str) -&gt; bool:                 # логически относится к классу
    return s.startswith("/")
```

</code></pre>
<h2>7. Уровни доступа: public, protected, private (соглашения)</h2>
<p>В Python нет строгих модификаторов, используются соглашения:</p>
<ul>
<li><b>public</b>: <code>name</code> — обычный атрибут.</li>
<li><b>protected</b>: <code>_name</code> — «для внутреннего использования» и классов-наследников.</li>
<li><b>private</b>: <code>__name</code> — включает name mangling в <code>_Class__name</code>.</li>
</ul>
<pre><code class="language-python">class BankAccount:
    def __init__(self, owner: str, balance: int = 0):
        self.owner = owner
        self._currency = "RUB"
        self.__balance = balance

```
def deposit(self, amount: int) -&gt; None:
    if amount &lt;= 0:
        raise ValueError("Amount must be positive")
    self.__balance += amount

def get_balance(self) -&gt; int:
    return self.__balance
```

</code></pre>
<h2>8. Наследование, множественное наследование и MRO</h2>
<p>Наследование устраняет дублирование кода. При множественном наследовании порядок поиска атрибутов задаёт <b>MRO</b> (C3-линеаризация). Правильный стиль — «кооперативные» методы с <b>super()</b>, согласованные сигнатуры и отказ от «жёстких» вызовов предков.</p>
<pre><code class="language-python">class A:
    def who(self) -&gt; str:
        return "A"

class B(A):
def who(self) -> str:
return super().who() + "→B"

class C(A):
def who(self) -> str:
return super().who() + "→C"

class D(B, C):
def who(self) -> str:
return super().who() + "→D"

print(D().who())   # A→C→B→D
print(D.**mro**)   # порядок разрешения </code></pre>
<p>Миксины добавляют небольшое, локальное поведение без самостоятельной предметной роли.</p>
<pre><code class="language-python">class LoggingMixin:
    def log(self, msg: str) -&gt; None:
        print(f"[{self.__class__.__name__}] {msg}")

class Service(LoggingMixin):
def run(self) -> None:
self.log("start")
# ...
self.log("done") </code></pre>
<h2>9. Полиморфизм: утиная типизация и singledispatch</h2>
<pre><code class="language-python">from functools import singledispatch

@singledispatch
def area(shape):
raise NotImplementedError

@area.register
def _(shape: tuple):   # прямоугольник (w, h)
w, h = shape
return w * h

@area.register
def _(shape: float):   # радиус круга
import math
return math.pi * shape * shape </code></pre>
<h2>10. Инкапсуляция через @property и дескрипторы</h2>
<p><b>@property</b> позволяет валидировать доступ, сохраняя внешний интерфейс.</p>
<pre><code class="language-python">class Celsius:
    def __init__(self, value: float = 0.0):
        self._value = float(value)

```
@property
def value(self) -&gt; float:
    return self._value

@value.setter
def value(self, new: float) -&gt; None:
    if new &lt; -273.15:
        raise ValueError("Ниже абсолютного нуля")
    self._value = float(new)
```

</code></pre>
<p>Дескриптор реализует протокол <b>__get__</b>/<b>__set__</b>/<b>__delete__</b> и управляет атрибутом на уровне класса.</p>
<pre><code class="language-python">class NonEmptyStr:
    def __set_name__(self, owner, name):
        self.private_name = "_" + name
    def __get__(self, obj, objtype=None):
        return getattr(obj, self.private_name)
    def __set__(self, obj, value):
        if not isinstance(value, str) or not value.strip():
            raise ValueError("Строка должна быть непустой")
        setattr(obj, self.private_name, value)

class Person:
name = NonEmptyStr()
def **init**(self, name: str):
self.name = name </code></pre>
<h2>11. Dataclasses: field(), default_factory, post_init, frozen</h2>
<p><b>dataclasses</b> генерируют конструктор, <b>__repr__</b>, сравнение и др. по аннотациям полей. <b>frozen=True</b> делает объект иммутабельным, <b>order=True</b> — добавляет упорядочивание.</p>
<pre><code class="language-python">from dataclasses import dataclass, field

@dataclass(order=True, frozen=True)
class Point:
x: int
y: int
tags: list[str] = field(default_factory=list, compare=False)

p = Point(1, 2)
print(p)                     # Point(x=1, y=2, tags=[])

# p.x = 5  # ошибка: объект заморожен

</code></pre>
<pre><code class="language-python">from dataclasses import dataclass

@dataclass
class Rect:
    w: float
    h: float
    def __post_init__(self):
        if self.w &lt;= 0 or self.h &lt;= 0:
            raise ValueError("Положительные размеры")
</code></pre>
<h2>12. Data Model: спецметоды и перегрузка операторов</h2>
<p>Спецметоды делают объекты «нативными» для языка: итерация, сравнение, арифметика, контекстный менеджмент.</p>
<pre><code class="language-python">class Vector:
    def __init__(self, *coords):
        self._c = tuple(coords)
    def __repr__(self):
        return f"Vector{self._c!r}"
    def __str__(self):
        return "⟨" + ", ".join(map(str, self._c)) + "⟩"
    def __len__(self):
        return len(self._c)
    def __iter__(self):
        return iter(self._c)
    def __add__(self, other):
        return Vector(*[a+b for a, b in zip(self._c, other._c)])
    def __eq__(self, other):
        return self._c == other._c
    def __hash__(self):
        return hash(self._c)
</code></pre>
<h2>13. Абстрактные классы (abc) и протоколы (typing.Protocol)</h2>
<pre><code class="language-python">from abc import ABC, abstractmethod

class Shape(ABC):
@abstractmethod
def area(self) -> float: ... </code></pre>
<pre><code class="language-python">from typing import Protocol

class Sized(Protocol):
    def __len__(self) -&gt; int: ...

def total(x: Sized) -&gt; int:
    return len(x)
</code></pre>
<p>Протоколы не требуют наследования — достаточно «утино» совместимого интерфейса.</p>
<h2>14. __slots__: экономия памяти и запрет динамических атрибутов</h2>
<pre><code class="language-python">class PackedPoint:
    __slots__ = ("x", "y")  # нет __dict__
    def __init__(self, x: float, y: float):
        self.x, self.y = x, y
</code></pre>
<p>Ограничения: нельзя добавлять произвольные атрибуты; наследование со <b>__slots__</b> требует аккуратности.</p>
<h2>15. __new__ и метаклассы</h2>
<p><b>__new__</b> создаёт объект; полезен для неизменяемых типов и фабрикации. Метакласс — «класс для классов», позволяет перехватывать создание классов.</p>
<pre><code class="language-python">class Singleton(type):
    def __call__(cls, *a, **kw):
        if not hasattr(cls, "_inst"):
            cls._inst = super().__call__(*a, **kw)
        return cls._inst

class Config(metaclass=Singleton):
pass </code></pre>
<h2>16. Сериализация и копирование</h2>
<pre><code class="language-python">import copy, json, pickle

class Node:
def **init**(self, v, child=None):
self.v, self.child = v, child

root = Node(1, Node(2))
deep = copy.deepcopy(root)
blob = pickle.dumps(root)
data = json.dumps({"v": root.v}) </code></pre>
<h2>17. Контекстные менеджеры</h2>
<pre><code class="language-python">class Resource:
    def __enter__(self):
        print("acquire"); return self
    def __exit__(self, exc_type, exc, tb):
        print("release"); return False

with Resource() as r:
print("use") </code></pre>
<h2>18. Композиция против наследования</h2>
<p>Композицию выбирайте, когда «имеет» лучше, чем «является». Наследование — когда новый тип сохраняет контракт предка и расширяет поведение.</p>
<pre><code class="language-python">class Engine:
    def start(self): print("engine on")

class Vehicle:
def **init**(self, engine: Engine):
self.engine = engine

```
def go(self):
    self.engine.start()
    print("moving...")
```

</code></pre>
<h2>19. Практический пример: Human, House, SmallHouse</h2>
<pre><code class="language-python">class Human:
    def __init__(self, name: str, money: int = 0, house: "House | None" = None):
        self.name = name
        self._money = money
        self.house = house

```
def earn(self, amount: int) -&gt; None:
    if amount &lt;= 0:
        raise ValueError("amount must be positive")
    self._money += amount

def buy_house(self, house: "House", discount: float = 0.0) -&gt; bool:
    price = house.final_price(discount)
    if self._money &gt;= price:
        self._money -= price
        self.house = house
        return True
    return False

@property
def money(self) -&gt; int:
    return self._money
```

class House:
def **init**(self, area: int, price: int):
if area <= 0 or price <= 0:
raise ValueError("area/price must be positive")
self.area = area
self.price = price

```
def final_price(self, discount: float = 0.0) -&gt; int:
    return int(self.price * (1.0 - discount))
```

class SmallHouse(House):
DEFAULT_AREA = 40
def **init**(self, price: int):
super().**init**(area=SmallHouse.DEFAULT_AREA, price=price)

h = Human("Alex", money=100_000)
small = SmallHouse(price=90_000)
print(h.buy_house(small, discount=0.05))  # True
print(h.house.area, h.money)              # 40 14500 </code></pre>
<h2>20. Расширения примера</h2>
<ul>
<li>Добавьте <b>@property</b> с проверкой, чтобы площадь и цена были положительными, скидка — в [0, 1).</li>
<li>Сделайте <b>CountryHouse</b> с дополнительным полем <code>plot_area</code> и переопределением <code>final_price</code>.</li>
<li>Реализуйте сравнение домов по цене и площади через <b>functools.total_ordering</b>.</li>
<li>Сериализуйте список домов в JSON и восстановите его.</li>
</ul>
<h2>21. Типичные ошибки и приёмы</h2>
<ul>
<li>Создание атрибутов «на лету» в методах, а не в <b>__init__</b>. Симптом: неоднозначная структура экземпляров.</li>
<li>Отсутствие <b>super()</b> при множественном наследовании. Это ломает кооперативные цепочки.</li>
<li>Смешение ответственности: «боже-объект» с десятками методов. Делите на небольшие классы.</li>
<li>Неверное равенство/хеш: если определили <b>__eq__</b>, подумайте о согласованном <b>__hash__</b> и иммутабельных полях.</li>
<li>Злоупотребление наследованием там, где нужна композиция или делегирование.</li>
</ul>
<h2>22. Короткий чек-лист</h2>
<ul>
<li>Определите контракт класса словом и кодом: докстрока, аннотации, инварианты.</li>
<li>Создавайте все поля в <b>__init__</b>. Валидацию — сразу в конструкторе.</li>
<li>Отдельно решайте «что является чем» (наследование) и «что содержит что» (композиция).</li>
<li>Для согласованной иерархии используйте <b>super()</b> и единые сигнатуры.</li>
<li>Инкапсуляция: <b>@property</b> и дескрипторы вместо «жёстких» публичных полей.</li>
<li>Когда данные преобладают — подумайте о <b>dataclasses</b>.</li>
</ul>
<p><small>Структура и акценты согласованы с учебными материалами по ООП (темы: «классы и объекты», «атрибуты/поля», «методы», «уровни доступа», «конструктор __init__», «практика»). </small></p>
<p>Сообщение <a href="https://system-blog.ru/klassy-i-obekty-v-python-polnoe-rukovodstvo-po-oop-s-primerami-dlja-praktiki/">Классы и объекты в Python: полное руководство по ООП с примерами для практики</a> появились сначала на <a href="https://system-blog.ru">Системный блог</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://system-blog.ru/klassy-i-obekty-v-python-polnoe-rukovodstvo-po-oop-s-primerami-dlja-praktiki/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Работа с файлами в Python с помощью модуля OS: Полный гид</title>
		<link>https://system-blog.ru/rabota-s-fajlami-v-python-s-pomoshhju-modulja-os-polnyj-gid/</link>
					<comments>https://system-blog.ru/rabota-s-fajlami-v-python-s-pomoshhju-modulja-os-polnyj-gid/#respond</comments>
		
		<dc:creator><![CDATA[Vit90]]></dc:creator>
		<pubDate>Wed, 05 Nov 2025 17:08:17 +0000</pubDate>
				<category><![CDATA[Уроки по Python]]></category>
		<guid isPermaLink="false">https://system-blog.ru/?p=1112</guid>

					<description><![CDATA[<p>Работа с файлами в Python Работа с файлами — это одна из самых важных и распространённых задач в программировании. В Python для эффективного взаимодействия с файловой системой используется встроенный модуль os. С помощью этого модуля можно легко выполнять множество операций, таких как создание, переименование, удаление, перемещение файлов, работа с путями, каталогами, а также получение информации&#8230;&#160;<a href="https://system-blog.ru/rabota-s-fajlami-v-python-s-pomoshhju-modulja-os-polnyj-gid/" rel="bookmark"><span class="screen-reader-text">Работа с файлами в Python с помощью модуля OS: Полный гид</span></a></p>
<p>Сообщение <a href="https://system-blog.ru/rabota-s-fajlami-v-python-s-pomoshhju-modulja-os-polnyj-gid/">Работа с файлами в Python с помощью модуля OS: Полный гид</a> появились сначала на <a href="https://system-blog.ru">Системный блог</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h2>Работа с файлами в Python</h2>
<p>Работа с файлами — это одна из самых важных и распространённых задач в программировании. В Python для эффективного взаимодействия с файловой системой используется встроенный модуль <b>os</b>. С помощью этого модуля можно легко выполнять множество операций, таких как создание, переименование, удаление, перемещение файлов, работа с путями, каталогами, а также получение информации о файлах. В этой статье мы подробно рассмотрим, как использовать <b>модуль os</b> для выполнения этих операций, а также рассмотрим дополнительные особенности работы с файловой системой в Python.</p>
<h2>Зачем работать с файлами в Python?</h2>
<p>Работа с файлами является неотъемлемой частью многих программ, будь то хранение данных, взаимодействие с пользователем, запись логов или обработка больших объемов информации. В Python для таких целей отлично подходит модуль <b>os</b>, который предоставляет доступ к различным функциям работы с файловой системой, включая создание файлов и каталогов, удаление, переименование и перемещение файлов, а также работу с путями.</p>
<p>Этот модуль значительно облегчает взаимодействие с операционной системой, предоставляя кроссплатформенные инструменты. То есть код, написанный с использованием модуля <b>os</b>, будет работать как на Windows, так и на Linux или macOS без изменений. В этой статье мы подробнее рассмотрим все ключевые возможности модуля <b>os</b>, которые позволяют работать с файлами и каталогами, а также управлять путями и атрибутами файлов.</p>
<h2>Основные операции с файлами в Python</h2>
<p>Модуль <b>os</b> предоставляет множество полезных функций для работы с файлами. Давайте разберем самые важные и часто используемые из них, которые помогут вам эффективно взаимодействовать с файлами в вашем коде.</p>
<h3>Создание и открытие файлов</h3>
<p>Для работы с файлами в Python используется встроенная функция <code>open()</code>, которая предоставляет несколько режимов доступа к файлам. Однако, с помощью модуля <b>os</b>, можно расширить возможности, выполняя дополнительные операции с файлами и каталогами на уровне операционной системы.</p>
<p>При использовании <code>open()</code> важно уметь правильно выбирать режимы открытия файлов:</p>
<ul>
<li><code>'r'</code> — режим чтения (по умолчанию). Если файл не существует, будет выброшено исключение <code>FileNotFoundError</code>.</li>
<li><code>'w'</code> — режим записи. Если файл уже существует, его содержимое будет перезаписано.</li>
<li><code>'a'</code> — режим добавления данных в конец файла. Если файл не существует, он будет создан.</li>
<li><code>'rb'</code> — режим чтения бинарного файла.</li>
<li><code>'wb'</code> — режим записи в бинарный файл.</li>
</ul>
<p>После того как файл создан или открыт, его необходимо правильно закрывать, чтобы не возникало утечек памяти. Для этого можно использовать метод <code>close()</code>. Однако лучший способ — это использовать контекстный менеджер <code>with</code>, который гарантирует закрытие файла после завершения работы с ним.</p>
<pre><code>
import os

# Пример создания и записи в файл
file_path = 'example_file.txt'
with open(file_path, 'w') as file:
    file.write("Hello, world!")

# Проверка, существует ли файл
if os.path.exists(file_path):
    print(f"{file_path} существует")
else:
    print(f"{file_path} не существует")
</code></pre>
<p>В этом примере мы создаем файл, записываем в него строку и проверяем его существование с помощью функции <code>os.path.exists()</code>.</p>
<h3>Переименование и перемещение файлов</h3>
<p>С помощью функции <code>os.rename()</code> можно не только переименовывать файлы, но и перемещать их между каталогами. Эта функция очень полезна, когда нужно организовать файлы в структуре папок или при изменении имени файла.</p>
<p>Если файл с новым именем уже существует, его содержимое будет перезаписано. Важно помнить, что переименование и перемещение файла может привести к потере данных, если целевой файл уже существует в указанном месте.</p>
<pre><code>
# Переименование файла
os.rename('example_file.txt', 'new_example_file.txt')
</code></pre>
<p>Также можно использовать этот метод для перемещения файла между папками, указав в качестве нового имени путь к целевому каталогу:</p>
<pre><code>
# Перемещение файла в другой каталог
os.rename('example_file.txt', '/new_directory/example_file.txt')
</code></pre>
<h3>Удаление файлов</h3>
<p>Для удаления файлов используется функция <code>os.remove()</code>. Это довольно простая и полезная операция, однако следует быть осторожными, так как файлы удаляются без возможности восстановления. Если файл не существует, будет вызвано исключение <code>FileNotFoundError</code>.</p>
<pre><code>
# Удаление файла
os.remove('new_example_file.txt')
</code></pre>
<p>Важно, что функция <code>os.remove()</code> работает только с файлами. Если вы хотите удалить каталог, используйте <code>os.rmdir()</code> для удаления пустых каталогов или <code>shutil.rmtree()</code> для удаления каталогов с содержимым.</p>
<h3>Перемещение файлов с использованием <code>shutil</code></h3>
<p>Для более сложных операций перемещения, таких как копирование или перемещение файлов, можно использовать модуль <b>shutil</b>, который расширяет функциональность модуля <b>os</b> и предоставляет функции для перемещения и копирования файлов и каталогов.</p>
<pre><code>
import shutil

# Перемещение файла

shutil.move('example_file.txt', '/new_directory/example_file.txt')

# Копирование файла

shutil.copy('example_file.txt', '/new_directory/example_file.txt') </code></pre>
<h2>Работа с каталогами в Python</h2>
<p>Кроме работы с файлами, модуль <b>os</b> позволяет легко манипулировать каталогами. Создание, удаление и получение информации о каталогах — все это можно сделать с помощью нескольких функций модуля <b>os</b>.</p>
<h3>Получение списка файлов и каталогов</h3>
<p>Для того чтобы получить список всех файлов и каталогов в указанной директории, можно использовать функцию <code>os.listdir()</code>, которая возвращает список имен всех объектов в указанной директории. Это могут быть как файлы, так и подкаталоги.</p>
<pre><code>
# Получение списка файлов и каталогов в текущем каталоге
files = os.listdir('.')
print(files)
</code></pre>
<p>Для фильтрации результатов можно использовать такие функции, как <code>os.path.isfile()</code> для получения списка только файлов или <code>os.path.isdir()</code> для получения списка только каталогов.</p>
<h3>Создание и удаление каталогов</h3>
<p>Для создания нового каталога используйте функцию <code>os.mkdir()</code>. Эта функция создает каталог в текущем рабочем каталоге. Если необходимо создать несколько уровней каталогов, используйте <code>os.makedirs()</code>.</p>
<pre><code>
# Создание каталога
os.mkdir('new_directory')

# Создание нескольких вложенных каталогов

os.makedirs('parent_directory/child_directory') </code></pre>
<p>Для удаления каталога используется функция <code>os.rmdir()</code>, которая удаляет только пустые каталоги. Чтобы удалить каталог с содержимым, используйте <code>shutil.rmtree()</code>.</p>
<pre><code>
import shutil

# Удаление каталога с содержимым
shutil.rmtree('new_directory')
</code></pre>
<h2>Абсолютные и относительные пути в Python</h2>
<p>Работа с путями в файловой системе — важная часть взаимодействия с файлами. Понимание разницы между абсолютными и относительными путями позволит вам правильно работать с файлами и каталогами.</p>
<p><b>Абсолютный путь</b> — это полный путь к файлу, начиная с корня файловой системы. <b>Относительный путь</b> указывает путь, который относительно текущего местоположения файла или программы.</p>
<pre><code>
# Абсолютный путь
absolute_path = os.path.abspath('example.txt')
print(absolute_path)

# Относительный путь
relative_path = os.path.join('folder', 'example.txt')
print(relative_path)
</code></pre>
<p>Функция <code>os.path.abspath()</code> позволяет получить абсолютный путь к файлу, а <code>os.path.join()</code> помогает легко соединять пути, обеспечивая кроссплатформенность кода (например, правильный разделитель пути для разных операционных систем).</p>
<h2>Ошибки при работе с файлами и каталогами</h2>
<p>В процессе работы с файлами могут возникать различные ошибки, такие как отсутствие файла или каталога, недостаток прав для чтения или записи, неправильные пути и так далее. Важно обрабатывать такие ошибки с помощью конструкции <code>try/except</code>, чтобы программа не завершалась неожиданно.</p>
<pre><code>
try:
    os.remove('nonexistent_file.txt')
except FileNotFoundError:
    print("Файл не найден!")
except PermissionError:
    print("Нет прав для удаления файла.")
</code></pre>
<h2>Практические примеры работы с модулями OS</h2>
<p>Пример создания и работы с файлами для использования в различных проектах:</p>
<pre><code>
# Пример создания и работы с файлами
def create_and_write_file(filename, content):
    with open(filename, 'w') as file:
        file.write(content)
    print(f"Файл {filename} успешно создан и записан.")

create_and_write_file('test_file.txt', 'Hello, Python!')
</code></pre>
<p>В этом примере мы создаём новый файл, записываем в него данные и выводим сообщение о том, что операция выполнена успешно.</p>
<h2>Заключение</h2>
<p>Модуль <b>os</b> является неотъемлемой частью работы с файловой системой в Python. Он предоставляет все необходимые инструменты для работы с файлами и каталогами, управления путями и атрибутами файлов, а также для выполнения системных операций с файлами. Использование этого модуля значительно облегчает взаимодействие с операционной системой и помогает делать код более переносимым и надежным. <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f680.png" alt="🚀" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<h2>Часто задаваемые вопросы (FAQ)</h2>
<details>
<summary><b>1) Как работать с путями файлов в Python?</b></summary>
<p>Для работы с путями файлов используйте функции <code>os.path.join()</code> для создания путей, а <code>os.path.abspath()</code> для получения абсолютного пути.</p>
</details>
<details>
<summary><b>2) Как удалить файл с помощью модуля os?</b></summary>
<p>Для удаления файла используйте функцию <code>os.remove()</code>. Эта функция удаляет только файлы, для удаления каталога используйте <code>os.rmdir()</code>.</p>
</details>
<details>
<summary><b>3) Как создать каталог в Python?</b></summary>
<p>Для создания нового каталога используйте функцию <code>os.mkdir()</code> или <code>os.makedirs()</code>, которая позволяет создать промежуточные каталоги.</p>
</details>
<details>
<summary><b>4) Как проверить, существует ли файл или каталог?</b></summary>
<p>Для проверки существования файла или каталога используйте функцию <code>os.path.exists()</code>.</p>
</details>
<details>
<summary><b>5) Как переместить файл в Python?</b></summary>
<p>Для перемещения файла используйте функцию <code>os.rename()</code>, которая позволяет изменить имя файла или переместить его в другой каталог.</p>
</details>
<p>Сообщение <a href="https://system-blog.ru/rabota-s-fajlami-v-python-s-pomoshhju-modulja-os-polnyj-gid/">Работа с файлами в Python с помощью модуля OS: Полный гид</a> появились сначала на <a href="https://system-blog.ru">Системный блог</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://system-blog.ru/rabota-s-fajlami-v-python-s-pomoshhju-modulja-os-polnyj-gid/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Работа с файлами в Python: Полный гид по чтению, записи и обработке файлов</title>
		<link>https://system-blog.ru/rabota-s-fajlami-v-python-polnyj-gid-po-chteniju-zapisi-i-obrabotke-fajlov/</link>
					<comments>https://system-blog.ru/rabota-s-fajlami-v-python-polnyj-gid-po-chteniju-zapisi-i-obrabotke-fajlov/#respond</comments>
		
		<dc:creator><![CDATA[Vit90]]></dc:creator>
		<pubDate>Wed, 05 Nov 2025 16:48:10 +0000</pubDate>
				<category><![CDATA[Уроки по Python]]></category>
		<guid isPermaLink="false">https://system-blog.ru/?p=1109</guid>

					<description><![CDATA[<p>Работа с файлами — важная составляющая программирования, позволяющая сохранять и загружать данные на диск, а также взаимодействовать с различными форматами данных. В Python есть мощные инструменты для работы с файлами, которые позволяют читать, записывать, редактировать и обрабатывать информацию с минимальными усилиями. В этой статье рассмотрим основные аспекты работы с файлами: как правильно открывать и закрывать&#8230;&#160;<a href="https://system-blog.ru/rabota-s-fajlami-v-python-polnyj-gid-po-chteniju-zapisi-i-obrabotke-fajlov/" rel="bookmark"><span class="screen-reader-text">Работа с файлами в Python: Полный гид по чтению, записи и обработке файлов</span></a></p>
<p>Сообщение <a href="https://system-blog.ru/rabota-s-fajlami-v-python-polnyj-gid-po-chteniju-zapisi-i-obrabotke-fajlov/">Работа с файлами в Python: Полный гид по чтению, записи и обработке файлов</a> появились сначала на <a href="https://system-blog.ru">Системный блог</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Работа с файлами — важная составляющая программирования, позволяющая сохранять и загружать данные на диск, а также взаимодействовать с различными форматами данных. В Python есть мощные инструменты для работы с файлами, которые позволяют читать, записывать, редактировать и обрабатывать информацию с минимальными усилиями. В этой статье рассмотрим основные аспекты работы с файлами: как правильно открывать и закрывать файлы, какие методы чтения и записи существуют, как работать с позицией указателя в файле, а также с большими файлами и обработкой ошибок. <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f680.png" alt="🚀" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<h2>Типы файлов, с которыми можно работать в Python</h2>
<p>Python поддерживает два основных типа файлов: <b>текстовые</b> и <b>бинарные</b>.</p>
<ul>
<li><b>Текстовые файлы:</b> Эти файлы содержат текстовую информацию, такую как .txt, .csv, .log, .xml. Эти файлы можно легко открыть и прочитать с помощью стандартных текстовых методов, потому что их содержимое представлено в виде строк, кодируемых в определённой кодировке (чаще всего UTF-8).</li>
<li><b>Бинарные файлы:</b> Это файлы, содержащие данные в двоичной форме, такие как изображения (.png, .jpg), видео (.mp4), исполнимые файлы (.exe) и т.д. Эти файлы требуют специальной обработки, так как их содержимое представлено в виде байтов, а не строк.</li>
</ul>
<p>Выбор типа файла зависит от того, с какими данными вы работаете. Если вам нужно работать с текстовыми данными, текстовые файлы — это оптимальный вариант. Если же ваши данные представлены в бинарном формате (например, изображения или аудиофайлы), необходимо работать с бинарными файлами.</p>
<h2>Открытие и закрытие файлов в Python</h2>
<p>Для работы с файлом в Python необходимо его сначала <b>открыть</b>. Открытие файла осуществляется с помощью функции <code>open()</code>, в которую передаётся путь к файлу и режим доступа к файлу.</p>
<p><b>Режимы работы с файлом:</b></p>
<ul>
<li><code>'r'</code> — чтение файла (по умолчанию). Если файл не существует, будет вызвана ошибка.</li>
<li><code>'w'</code> — запись в файл. Если файл уже существует, его содержимое будет перезаписано.</li>
<li><code>'a'</code> — добавление данных в файл. Новые данные будут добавлены в конец файла.</li>
<li><code>'rb'</code> — чтение бинарного файла.</li>
<li><code>'wb'</code> — запись в бинарный файл.</li>
</ul>
<p>После завершения работы с файлом его нужно закрыть с помощью метода <code>close()</code>. Однако гораздо удобнее и безопаснее использовать контекстный менеджер <code>with</code>, который автоматически закроет файл, даже если в процессе работы возникнут ошибки.</p>
<pre><code>
# Пример открытия и закрытия файла с использованием контекстного менеджера
with open('example.txt', 'r') as file:
    content = file.read()
    print(content)  # выводим содержимое файла
# Файл будет закрыт автоматически после выхода из блока with
</code></pre>
<p>Контекстный менеджер гарантирует, что файл будет закрыт даже в случае возникновения исключений, что предотвращает утечку ресурсов.</p>
<h2>Чтение из файлов в Python</h2>
<p>После того как файл открыт, можно читать его содержимое. В Python для чтения используются следующие методы:</p>
<ul>
<li><code>read()</code> — читает весь файл целиком. Метод вернёт строку, содержащую всё содержимое файла. Это полезно, когда файл небольшой.</li>
<li><code>readline()</code> — читает одну строку за раз. Этот метод полезен, если файл очень большой и нужно читать его по частям.</li>
<li><code>readlines()</code> — читает весь файл построчно и возвращает список строк. Это удобно, если нужно работать с файлами, где строки имеют смысл, например, в CSV-файлах.</li>
</ul>
<p>Пример чтения всего содержимого файла:</p>
<pre><code>
with open('example.txt', 'r') as file:
    content = file.read()  # читаем весь файл
    print(content)  # выводим содержимое файла
</code></pre>
<p>Чтение файла построчно с использованием цикла:</p>
<pre><code>
with open('example.txt', 'r') as file:
    for line in file:  # цикл по строкам
        print(line.strip())  # удаляем лишние символы новой строки
</code></pre>
<p>Если файл слишком большой, чтобы загружать его целиком в память, чтение построчно является оптимальным вариантом, потому что это значительно снижает нагрузку на память.</p>
<h2>Запись в файлы в Python</h2>
<p>Для записи данных в файл используется метод <code>write()</code>. Этот метод позволяет записывать строку или данные в файл. Если файл открыт в режиме <code>'w'</code>, его содержимое будет перезаписано, а если в режиме <code>'a'</code>, новые данные будут добавляться в конец файла.</p>
<pre><code>
# Запись в файл
with open('output.txt', 'w') as file:
    file.write("Hello, Python!n")
    file.write("This is a test file.")
</code></pre>
<p>Для записи бинарных данных файл должен быть открыт в бинарном режиме. Например, для записи изображения или другого бинарного файла:</p>
<pre><code>
# Запись в бинарный файл
with open('image.png', 'wb') as file:
    file.write(binary_data)  # записываем данные в файл
</code></pre>
<p>Метод <code>write()</code> не добавляет символ новой строки в конце данных, поэтому если вы хотите записать несколько строк, нужно явно добавить символы новой строки или использовать <code>writelines()</code> для записи списка строк.</p>
<h2>Работа с позицией в файле: методы <code>tell()</code> и <code>seek()</code></h2>
<p>Когда файл открыт, можно управлять позицией указателя в файле с помощью методов <code>tell()</code> и <code>seek()</code>.</p>
<ul>
<li><code>tell()</code> — возвращает текущую позицию указателя в файле. Это полезно, если вам нужно узнать, на каком месте в файле вы сейчас находитесь.</li>
<li><code>seek()</code> — позволяет перемещать указатель на определённую позицию в файле. Можно использовать абсолютные позиции или смещение от текущей позиции.</li>
</ul>
<p>Пример использования <code>tell()</code> и <code>seek()</code>:</p>
<pre><code>
with open('example.txt', 'r') as file:
    file.seek(10)  # перемещаем указатель на 10 байт
    print(file.tell())  # выводим текущую позицию указателя
    content = file.read(5)  # читаем 5 байт с текущей позиции
    print(content)
</code></pre>
<p>Метод <code>seek()</code> позволяет не только изменять позицию, но и перемещать указатель в начало файла, что удобно для работы с большими файлами, когда необходимо многократно обращаться к данным в разных частях.</p>
<h2>Обработка ошибок при работе с файлами</h2>
<p>При работе с файлами важно учитывать возможные ошибки, такие как отсутствие файла, недостаток прав для записи или ошибки при чтении. Python позволяет обрабатывать такие ошибки с помощью конструкции <code>try/except</code>.</p>
<pre><code>
try:
    with open('nonexistent_file.txt', 'r') as file:
        content = file.read()
except FileNotFoundError:
    print("Файл не найден!")
except IOError:
    print("Ошибка ввода-вывода!")
</code></pre>
<p>Использование блоков <code>try/except</code> позволяет избежать неожиданных сбоев программы и предоставляет возможность корректно обработать возникшие проблемы.</p>
<h2>Работа с большими файлами</h2>
<p>При работе с большими файлами не рекомендуется загружать их в память целиком, так как это может привести к излишнему потреблению памяти и замедлению работы программы. Вместо этого можно читать файл построчно или блоками данных, что позволяет эффективно обрабатывать большие объемы информации.</p>
<p>Для этого используйте методы <code>readline()</code> или <code>readlines()</code>, а также читайте файл по частям с помощью цикла:</p>
<pre><code>
with open('large_file.txt', 'r') as file:
    while chunk := file.read(1024):  # читаем файл блоками по 1024 байта
        process(chunk)  # обработка данных
</code></pre>
<h2>Заключение</h2>
<p>Работа с файлами в Python — это важный аспект программирования, который позволяет взаимодействовать с данными на диске. Важно правильно открывать, читать и записывать файлы, использовать методы для управления позицией указателя, а также обрабатывать возможные ошибки. Контекстный менеджер <code>with</code> позволяет удобно управлять открытием и закрытием файлов, что делает код более надёжным. Следуя этим рекомендациям, вы сможете эффективно работать с файлами в Python, обрабатывать большие данные и избегать ошибок при работе с файлами.</p>
<h2>Часто задаваемые вопросы (FAQ)</h2>
<details>
<summary><b>1) Как правильно закрывать файл после его использования?</b></summary>
<p>Лучше всего использовать контекстный менеджер <code>with</code>, который автоматически закроет файл по завершению работы с ним. Это безопасно и удобно.</p>
</details>
<details>
<summary><b>2) Как прочитать файл построчно?</b></summary>
<p>Для этого используйте цикл <code>for line in file:</code>, что позволяет читать файл построчно, экономя память.</p>
</details>
<details>
<summary><b>3) Что такое метод <code>seek()</code> и как его использовать?</b></summary>
<p>Метод <code>seek()</code> позволяет перемещать указатель на указанную позицию в файле. Это полезно, когда нужно начать чтение или запись с определённого места.</p>
</details>
<details>
<summary><b>4) Как записать данные в бинарный файл?</b></summary>
<p>Для записи в бинарный файл откройте его в режиме <code>'wb'</code> и используйте метод <code>write()</code> для записи данных в формате байтов.</p>
</details>
<details>
<summary><b>5) Что делать, если файл не существует?</b></summary>
<p>Используйте обработку ошибок с конструкцией <code>try/except</code>, чтобы перехватить исключение <code>FileNotFoundError</code> и обработать его корректно.</p>
</details>
<p>Сообщение <a href="https://system-blog.ru/rabota-s-fajlami-v-python-polnyj-gid-po-chteniju-zapisi-i-obrabotke-fajlov/">Работа с файлами в Python: Полный гид по чтению, записи и обработке файлов</a> появились сначала на <a href="https://system-blog.ru">Системный блог</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://system-blog.ru/rabota-s-fajlami-v-python-polnyj-gid-po-chteniju-zapisi-i-obrabotke-fajlov/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Обработка исключений в Python</title>
		<link>https://system-blog.ru/obrabotka-iskljuchenij-v-python/</link>
					<comments>https://system-blog.ru/obrabotka-iskljuchenij-v-python/#respond</comments>
		
		<dc:creator><![CDATA[Vit90]]></dc:creator>
		<pubDate>Wed, 05 Nov 2025 16:18:55 +0000</pubDate>
				<category><![CDATA[Уроки по Python]]></category>
		<guid isPermaLink="false">https://system-blog.ru/?p=1105</guid>

					<description><![CDATA[<p>Обработка и генерация исключений в Python: полный разбор try/except, raise, else/finally и пользовательских ошибок Исключения в Python — это механизм сигнализации об ошибках во время выполнения. Правильная обработка исключений делает код надёжным и читаемым. Ниже — базовые конструкции try/except, связка else/finally, генерация ошибок raise, пользовательские исключения и практики. Что такое исключения и почему они важны&#8230;&#160;<a href="https://system-blog.ru/obrabotka-iskljuchenij-v-python/" rel="bookmark"><span class="screen-reader-text">Обработка исключений в Python</span></a></p>
<p>Сообщение <a href="https://system-blog.ru/obrabotka-iskljuchenij-v-python/">Обработка исключений в Python</a> появились сначала на <a href="https://system-blog.ru">Системный блог</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h2>Обработка и генерация исключений в Python: полный разбор try/except, raise, else/finally и пользовательских ошибок</h2>
<p>Исключения в Python — это механизм сигнализации об ошибках во время выполнения. Правильная <b>обработка исключений</b> делает код надёжным и читаемым. Ниже — базовые конструкции <b>try/except</b>, связка <b>else</b>/<b>finally</b>, генерация ошибок <b>raise</b>, пользовательские исключения и практики.</p>
<h2>Что такое исключения и почему они важны</h2>
<p><b>Исключение</b> — объект, который «выбрасывается» (raise) при ошибочной ситуации: деление на ноль, выход за пределы списка, сбой сети, неправильные данные. Если исключение не перехвачено, интерпретатор прерывает программу и печатает <b>Traceback</b>.</p>
<ul>
<li><b>Перехват исключений</b> не скрывает ошибку, а делает поведение контролируемым.</li>
<li>Обработка повышает <b>устойчивость</b> сервисов и CLI.</li>
<li>Правильный перехват упрощает <b>отладку</b>.</li>
</ul>
<h2>Иерархия исключений в Python</h2>
<p>Все исключения наследуются от <b>BaseException</b>. Для прикладного кода базовым родителем почти всегда является <b>Exception</b>. Ветвление важно для корректного перехвата: можно ловить как конкретные типы, так и целые группы.</p>
<pre><code>
# Фрагмент дерева (упрощённо)
BaseException
 ├─ SystemExit
 ├─ KeyboardInterrupt
 └─ Exception
    ├─ ArithmeticError
    │   ├─ ZeroDivisionError
    │   └─ OverflowError
    ├─ LookupError
    │   ├─ IndexError
    │   └─ KeyError
    ├─ FileNotFoundError
    ├─ ValueError
    ├─ TypeError
    ├─ OSError
    └─ RuntimeError
</code></pre>
<p>Рекомендация: перехватывайте <b>конкретные</b> исключения. Перехват «всего подряд» затрудняет диагностику и маскирует баги.</p>
<h2>Базовая конструкция try/except</h2>
<p>Используйте <b>try/except</b>, чтобы безопасно выполнить рискованный код:</p>
<pre><code>
def safe_div(x, y):
    try:
        return x / y
    except ZeroDivisionError as e:
        return float("inf")  # или логика по умолчанию
</code></pre>
<p>Можно перехватывать несколько типов исключений разными блоками <b>except</b> или одной «кортежной» записью.</p>
<pre><code>
def parse_int(value):
    try:
        return int(value)
    except (ValueError, TypeError) as e:
        return None
</code></pre>
<p>Используйте <b>as e</b>, чтобы получить объект исключения и записать сообщение в лог.</p>
<h2>Расширения: else и finally</h2>
<p>Блок <b>else</b> выполняется, если в <b>try</b> не произошло исключения. Блок <b>finally</b> выполняется всегда — несмотря ни на что.</p>
<pre><code>
def read_number(path):
    f = None
    try:
        f = open(path, "r", encoding="utf-8")
        data = f.read()
    except FileNotFoundError:
        return None
    else:
        return int(data.strip())
    finally:
        if f:
            f.close()
</code></pre>
<p>Чаще вместо ручного <b>finally</b> используйте <b>with</b>, который корректно освободит ресурсы.</p>
<h2>Генерация исключений: raise</h2>
<p>Когда входные данные некорректны или система в невалидном состоянии, выбрасывайте исключение явно с помощью <b>raise</b>. Это делает контракт функций прозрачным и предотвращает тихие сбои.</p>
<pre><code>
def sqrt_positive(x: float) -> float:
    if x &lt; 0:
        raise ValueError('x must be non-negative')
    return x ** 0.5
</code></pre>
<p>Для сохранения исходного контекста используйте <b>raise from</b>, чтобы связать исключения цепочкой (<i>exception chaining</i>) и быстрее диагностировать первопричину.</p>
<pre><code>
def load_json(path):
    import json
    try:
        with open(path, encoding="utf-8") as f:
            return json.load(f)
    except OSError as e:
        raise RuntimeError('Unable to read file') from e
</code></pre>
<p>Повторный выброс (re-raise) — просто <b>raise</b> без аргументов внутри блока <b>except</b>. Он полезен, если вы что-то залогировали и хотите передать ошибку выше.</p>
<pre><code>
try:
    risky()
except Exception:
    log_exception()  # запись в журнал
    raise
</code></pre>
<h2>Пользовательские исключения</h2>
<p>Создавайте собственные типы для доменных ошибок. Так код становится самодокументируемым, а вызывающая сторона может ловить ваши исключения отдельно от системных.</p>
<pre><code>
class PaymentError(Exception):
    'Базовая ошибка платежей.'

class CardDeclinedError(PaymentError):
pass

def charge(amount, card):
if not card.valid:
raise CardDeclinedError('Card declined') </code></pre>
<p>Совет: храните пользовательские исключения в модуле <b>exceptions.py</b> и документируйте условия их возникновения.</p>
<h2>Множественные except и порядок проверки</h2>
<p>Python сопоставляет исключение с блоками <b>except</b> сверху вниз. Узкие типы пишите раньше широких.</p>
<pre><code>
try:
    ...
except ValueError:
    handle_value()
except Exception:
    handle_generic()
</code></pre>
<h2>EAFP против LBYL</h2>
<p>Идиома Python — <b>EAFP</b> (Easier to Ask Forgiveness than Permission): «проще просить прощения, чем разрешения». Альтернатива — <b>LBYL</b> (Look Before You Leap): предварительно проверять условия.</p>
<pre><code>
# EAFP
try:
    value = mapping[key]
except KeyError:
    value = default

# LBYL

if key in mapping:
value = mapping[key]
else:
value = default </code></pre>
<p>EAFP обычно короче и масштабируется лучше в конкурентных сценариях.</p>
<h2>Практические паттерны обработки ошибок</h2>
<ul>
<li><b>Валидация входных данных</b>: выбрасывайте <b>ValueError</b>/<b>TypeError</b> для некорректного ввода.</li>
<li><b>Работа с файлами</b>: перехватывайте <b>FileNotFoundError</b>, <b>PermissionError</b>, используйте <b>with</b>.</li>
<li><b>Сеть и API</b>: ловите <b>OSError</b>, таймауты, ошибки библиотек; ретраи при нужде.</li>
<li><b>Базы данных</b>: разделяйте транзиентные и фатальные ошибки.</li>
</ul>
<pre><code>
import json
from pathlib import Path

def load_settings(path: str) -> dict:
p = Path(path)
try:
text = p.read_text(encoding='utf-8')
return json.loads(text)
except FileNotFoundError:
return {'theme': 'light', 'autosave': False}
except json.JSONDecodeError as e:
raise ValueError(f'Invalid config format: {e}') </code></pre>
<h2>Логирование исключений</h2>
<p>Используйте модуль <b>logging</b> вместо принтов. Метод <b>logging.exception</b> автоматически добавляет стек-трейс.</p>
<pre><code>
import logging

log = logging.getLogger(**name**)

def process(item):
try:
step(item)
except Exception:
log.exception('Failed to process item: %r', item)
raise </code></pre>
<h2>Короткий чек-лист лучших практик</h2>
<ul>
<li>Ловите только те ошибки, с которыми реально можете что-то сделать.</li>
<li>Сообщения делайте конкретными: указывайте проблемное значение, путь, ключ, лимит.</li>
<li>Не используйте исключения как обычные if/else — это дорого и запутывает контроль потока.</li>
<li>Для библиотек документируйте, какие типы ошибок кидаете и когда.</li>
<li>В публичных API мапьте внутренние ошибки на доменные.</li>
</ul>
<pre><code>
def fetch(user_id, repo):
    if not isinstance(user_id, int):
        raise TypeError('user_id must be int')
    try:
        return repo.get(user_id)
    except OSError as e:
        raise RuntimeError('storage error') from e
</code></pre>
<h2>Анти-паттерны: чего избегать</h2>
<ul>
<li><b>except Exception:</b> без нужды — маскирует баги.</li>
<li><b>голые except:</b> перехватывают <b>BaseException</b> включая <b>KeyboardInterrupt</b>.</li>
<li><b>молчаливый перехват:</b> пустой обработчик без логирования.</li>
<li><b>злоупотребление assert:</b> утверждения могут быть отключены.</li>
<li><b>неподходящие типы ошибок:</b> <b>ValueError</b> для значения, <b>TypeError</b> для типа и т.п.</li>
</ul>
<h2>Исключения и контекстные менеджеры</h2>
<p>Контекстные менеджеры инкапсулируют открытие/закрытие ресурсов и политику ошибок. Свой менеджер — через класс с <b>__enter__</b>/<b>__exit__</b> или декоратор <b>contextmanager</b>.</p>
<pre><code>
from contextlib import contextmanager

@contextmanager
def opened(path, mode='r', encoding='utf-8'):
f = open(path, mode, encoding=encoding)
try:
yield f
finally:
f.close() </code></pre>
<h2>Исключения в тестах</h2>
<p>В юнит-тестах проверяйте, что функция выбрасывает ожидаемое исключение. В <b>pytest</b> используйте <b>raises</b>.</p>
<pre><code>
import pytest

def test_sqrt_positive_raises():
with pytest.raises(ValueError):
sqrt_positive(-1) </code></pre>
<h2>Частые вопросы (FAQ)</h2>
<details>
<summary><b>1) В чём разница между except Exception и голым except?</b></summary>
<p><b>except Exception</b> перехватывает прикладные ошибки. Голый <b>except</b> перехватывает <b>BaseException</b>, включая <b>KeyboardInterrupt</b> и <b>SystemExit</b>. Практически всегда избегайте голого варианта.</p>
</details>
<details>
<summary><b>2) Когда использовать else и finally?</b></summary>
<p><b>else</b> — когда нужно выполнить код, только если ошибок не было. <b>finally</b> — чтобы гарантированно освободить ресурсы независимо от успеха операции.</p>
</details>
<details>
<summary><b>3) Что предпочесть: EAFP или LBYL?</b></summary>
<p>В Python чаще выбирают <b>EAFP</b> — короче и безопаснее в условиях гонок. <b>LBYL</b> уместен, когда проверка дешёвая.</p>
</details>
<details>
<summary><b>4) Как проектировать пользовательские исключения?</b></summary>
<p>Создайте базовый класс доменных ошибок, наследуйте частные классы, документируйте причины и включайте полезный контекст в сообщения.</p>
</details>
<details>
<summary><b>5) Можно ли логировать и при этом пробрасывать исключение дальше?</b></summary>
<p>Да. Логируйте в <b>except</b>, затем делайте <b>raise</b> без аргументов — стек сохранится.</p>
</details>
<blockquote>
<p>Помните: «Ловите то, что готовы обработать». Остальное должно падать быстро и громко <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f9e9.png" alt="🧩" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
</blockquote>
<p>Освоив <b>try/except</b>, <b>else/finally</b> и <b>raise</b>, вы пишете предсказуемый код. Перехватывайте конкретные типы, логируйте исключения, проектируйте свои классы там, где это повышает ясность, и придерживайтесь идиомы <b>EAFP</b>. Удачной разработки! <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4bc.png" alt="💼" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<p>&#32;</p>
<p>Сообщение <a href="https://system-blog.ru/obrabotka-iskljuchenij-v-python/">Обработка исключений в Python</a> появились сначала на <a href="https://system-blog.ru">Системный блог</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://system-blog.ru/obrabotka-iskljuchenij-v-python/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Функции в Python: определение, вызов и приёмы для построения переиспользуемого кода</title>
		<link>https://system-blog.ru/funkcii-v-python-opredelenie-vyzov-i-prijomy-dlja-postroenija-pereispolzuemogo-koda/</link>
					<comments>https://system-blog.ru/funkcii-v-python-opredelenie-vyzov-i-prijomy-dlja-postroenija-pereispolzuemogo-koda/#respond</comments>
		
		<dc:creator><![CDATA[Vit90]]></dc:creator>
		<pubDate>Wed, 05 Nov 2025 15:51:19 +0000</pubDate>
				<category><![CDATA[Уроки по Python]]></category>
		<guid isPermaLink="false">https://system-blog.ru/?p=1100</guid>

					<description><![CDATA[<p>Функция Функции — основной механизм структурирования программ в Python. Они позволяют сгруппировать логику под понятным именем, сократить дублирование, улучшить читаемость и изолировать поведение для тестирования. Ниже — полный разбор: синтаксис def и return, позиционные и именованные аргументы, значения по умолчанию, вариативные параметры *args/**kwargs, области видимости, замыкания, lambda, рекурсия, декораторы, типизация и практики качества. Всё сопровождается&#8230;&#160;<a href="https://system-blog.ru/funkcii-v-python-opredelenie-vyzov-i-prijomy-dlja-postroenija-pereispolzuemogo-koda/" rel="bookmark"><span class="screen-reader-text">Функции в Python: определение, вызов и приёмы для построения переиспользуемого кода</span></a></p>
<p>Сообщение <a href="https://system-blog.ru/funkcii-v-python-opredelenie-vyzov-i-prijomy-dlja-postroenija-pereispolzuemogo-koda/">Функции в Python: определение, вызов и приёмы для построения переиспользуемого кода</a> появились сначала на <a href="https://system-blog.ru">Системный блог</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h2>Функция</h2>
<p>Функции — основной механизм структурирования программ в Python. Они позволяют сгруппировать логику под понятным именем, сократить дублирование, улучшить читаемость и изолировать поведение для тестирования. Ниже — полный разбор: синтаксис <b>def</b> и <b>return</b>, позиционные и именованные аргументы, значения по умолчанию, вариативные параметры <b>*args</b>/<b>**kwargs</b>, области видимости, замыкания, <b>lambda</b>, рекурсия, декораторы, типизация и практики качества. Всё сопровождается примерами и упражнениями. <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f680.png" alt="🚀" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<h2>Что такое функция</h2>
<p>Функция — это именованный блок кода, который принимает аргументы, выполняет действия и возвращает результат. Ключевые свойства: абстракция деталей, инкапсуляция состояния и композиция из простых шагов. Чем меньше побочных эффектов и чем уже ответственность, тем проще сопровождать код.</p>
<figure class="code"><figcaption>Мини-пример: нормализация строки</figcaption><pre><code class="language-python">def normalize_name(raw: str) -> str:
    text = raw.strip()
    return text.capitalize()

print(normalize_name("  алиса  "))  # Алиса</code></pre>
</figure>
<h2>Синтаксис: <b>def</b>, параметры и <b>return</b></h2>
<p>Определение начинается с <b>def</b> и имени в стиле <em>snake_case</em>; список параметров заключён в скобки; тело отделяется двоеточием и отступами. Оператор <b>return</b> завершает выполнение и передаёт значение. Если <b>return</b> не указан — возвращается <b>None</b>.</p>
<figure class="code"><figcaption>Базовый шаблон и неявный None</figcaption><pre><code class="language-python">def add(a: float, b: float) -> float:
    return a + b

def greet(name: str) -> None:
print(f"Привет, {name}!")

print(add(2, 3))       # 5
print(greet("Алиса"))  # None</code></pre>
</figure>
<h2>Вызов функций: позиционные и именованные аргументы</h2>
<p>Аргументы можно передавать по позиции и по имени. Именованные аргументы повышают читаемость и снижают риск перепутать порядок.</p>
<figure class="code"><figcaption>Позиционные и именованные вызовы</figcaption><pre><code class="language-python">def connect(host: str, port: int, use_ssl: bool) -> str:
    return f"{host}:{port} ssl={use_ssl}"

print(connect("example.com", 443, True))
print(connect(host="example.com", port=443, use_ssl=True))</code></pre>
</figure>
<h3>Виды параметров в сигнатуре</h3>
<p>Python поддерживает позиционные-только, позиционные/именованные, именованные-только параметры и вариативные. Разделители: символ <b>/</b> вводит позиционные-только, символ <b>*</b> — границу, после которой параметры принимаются только по имени.</p>
<figure class="code"><figcaption>Современные сигнатуры (Python 3.8+)</figcaption><pre><code class="language-python">def f(a, b, /, c, d, *, e, f_):
    # a, b — только позиционно; c, d — позиционно или по имени; e, f_ — только по имени
    return a + b + c + d</code></pre>
</figure>
<h2>Значения по умолчанию, <b>*args</b> и <b>**kwargs</b></h2>
<p>Значения по умолчанию сокращают количество обязательных аргументов. <b>*args</b> собирает произвольное число позиционных параметров в кортеж, <b>**kwargs</b> — именованные в словарь.</p>
<figure class="code"><figcaption>Дефолты и вариативные параметры</figcaption><pre><code class="language-python">def paginate(page: int = 1, per_page: int = 20) -> tuple[int, int]:
    start = (page - 1) * per_page
    return start, per_page

def summarize(*nums: float, **opts) -> str:
total = sum(nums)
prefix = opts.get("prefix", "sum")
return f"{prefix}={total}"

print(paginate())                       # (0, 20)
print(summarize(1, 2, 3, prefix="Σ"))   # Σ=6</code></pre>
</figure>
<aside><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Опасность: изменяемые дефолты (<b>list</b>, <b>dict</b>, <b>set</b>) живут между вызовами. Используйте <b>None</b> и создавайте объект внутри.</aside>
<figure class="code"><figcaption>Антипаттерн и исправление</figcaption><pre><code class="language-python">def append_bad(item, bucket=[]):
    bucket.append(item)
    return bucket  # состояние «залипает» между вызовами

def append_ok(item, bucket=None):
if bucket is None:
bucket = []
bucket.append(item)
return bucket</code></pre>
</figure>
<h2>Распаковка аргументов и управление вызовами</h2>
<p>Последовательности можно распаковать как позиционные, словари — как именованные аргументы. Это удобно при передачах параметров «сквозь» функции.</p>
<figure class="code"><figcaption>Распаковка * и **</figcaption><pre><code class="language-python">def area(w: float, h: float) -> float:
    return w * h

args = (3, 4)
kwargs = {"w": 5, "h": 6}
print(area(*args))      # 12
print(area(**kwargs))   # 30</code></pre>
</figure>
<h2>Область видимости: локальные, глобальные, <b>nonlocal</b></h2>
<p>Имена, созданные в функции, локальны. Чтение глобальных переменных допустимо; для записи используйте <b>global</b>. Во вложенных функциях можно менять переменные внешней функции через <b>nonlocal</b>. Сократите использование <b>global</b>/<b>nonlocal</b> — чаще лучше возвращать результат или инкапсулировать состояние в объект.</p>
<figure class="code"><figcaption>global и nonlocal по необходимости</figcaption><pre><code class="language-python">counter = 0

def tick():
global counter
counter += 1

def outer():
x = 0
def inner():
nonlocal x
x += 1
inner(); inner()
return x  # 2</code></pre>
</figure>
<h2>Замыкания и функции высшего порядка</h2>
<p>Функции — объекты первого класса: их можно передавать, возвращать и хранить в структурах данных. Замыкание захватывает из внешней области используемые переменные.</p>
<figure class="code"><figcaption>Замыкание счётчика</figcaption><pre><code class="language-python">from typing import Callable

def make_counter() -> Callable[[], int]:
n = 0
def inc():
nonlocal n
n += 1
return n
return inc

c = make_counter()
print(c(), c(), c())  # 1 2 3</code></pre>
</figure>
<h2>Анонимные функции (<b>lambda</b>)</h2>
<p><b>lambda</b> задаёт короткую безымянную функцию из одного выражения. Она удобна для ключей сортировки, простых преобразований и «инлайновых» колбэков. Если логика разрастается — переходите на <b>def</b>.</p>
<figure class="code"><figcaption>Ключ сортировки и трансформации</figcaption><pre><code class="language-python">users = [{"name":"bob","age":30},{"name":"ann","age":20}]
print(sorted(users, key=lambda u: (u["age"], u["name"])))</code></pre>
</figure>
<h2>Рекурсия и итерация</h2>
<p>Рекурсивные решения естественны для деревьев и вложенных структур, но требуют базового случая и контроля глубины стека. В CPython оптимизации хвостовой рекурсии нет, поэтому для длинных последовательностей используйте циклы.</p>
<figure class="code"><figcaption>Факториал: рекурсивно и итеративно</figcaption><pre><code class="language-python">def fact(n: int) -> int:
    if n &lt; 2:
        return 1
    return n * fact(n - 1)

def fact_iter(n: int) -> int:
res = 1
for k in range(2, n + 1):
res *= k
return res</code></pre>
</figure>
<h2>Декораторы: расширяем поведение без правки исходника</h2>
<p>Декоратор принимает функцию и возвращает новую, «обёрнутую», добавляя кросс-функциональные аспекты: логирование, кеширование, авторизацию, измерение времени.</p>
<figure class="code"><figcaption>Тайминг и корректная обёртка</figcaption><pre><code class="language-python">import time
from functools import wraps

def timing(fn):
@wraps(fn)
def wrapper(*args, **kwargs):
t0 = time.perf_counter()
try:
return fn(*args, **kwargs)
finally:
dt = (time.perf_counter() - t0) * 1000
print(f"{fn.**name**} took {dt:.1f} ms")
return wrapper

@timing
def heavy():
sum(range(1_000_00))
heavy()</code></pre>
</figure>
<figure class="code"><figcaption>Кеширование результатов</figcaption><pre><code class="language-python">from functools import lru_cache

@lru_cache(maxsize=1024)
def fib(n: int) -> int:
if n < 2:
return n
return fib(n - 1) + fib(n - 2)</code></pre>
</figure>
<h2>Типизация и документация</h2>
<p>Аннотации типов помогают IDE и статическим анализаторам, а докстринги объясняют назначение и контракт функции. Придерживайтесь единого формата (Google/NumPy/reST), и описывайте параметры, возвращаемое значение и исключения.</p>
<figure class="code"><figcaption>Аннотации и докстринг</figcaption><pre><code class="language-python">def clamp(x: float, low: float, high: float) -> float:
    """Ограничивает x интервалом [low, high]."""
    return max(low, min(high, x))</code></pre>
</figure>
<h2>Ошибки и исключения</h2>
<p>Исключительные ситуации обрабатывайте через <b>try/except</b>, а не через громоздкие ветвления. Логи фиксируют контекст и ускоряют диагностику.</p>
<figure class="code"><figcaption>Валидация и логирование</figcaption><pre><code class="language-python">import logging
logging.basicConfig(level=logging.INFO)

def price_from_str(s: str) -> float:
try:
val = float(s)
if val < 0:
raise ValueError("negative")
logging.info("ok: %s", val)
return val
except ValueError as e:
logging.error("parse error: %s", e)
return 0.0</code></pre>
</figure>
<h2>Практики качества</h2>
<ul>
<li><b>SRP</b>: одна функция — одна задача.</li>
<li>Понятные имена: глаголы для действий (<em>load_user</em>), существительные для вычислений (<em>distance</em>).</li>
<li>Минимизируйте скрытые побочные эффекты; явно возвращайте новые объекты.</li>
<li>Гвард-клаусы: ранний выход упрощает чтение.</li>
<li>Покрывайте ветвления тестами; добавляйте примеры в докстринг.</li>
</ul>
<figure class="code"><figcaption>Guard-clauses вместо вложенной «лесенки»</figcaption><pre><code class="language-python">def can_access(user: dict | None) -> bool:
    if not user:
        return False
    if not user.get("active"):
        return False
    return user.get("role") == "admin"</code></pre>
</figure>
<h2>Инструменты функционального стиля</h2>
<p>Модуль <b>functools</b> предлагает полезные утилиты: <b>partial</b> для частичного применения, <b>cmp_to_key</b> для старых сравнителей, <b>lru_cache</b> для мемоизации.</p>
<figure class="code"><figcaption>Частичное применение</figcaption><pre><code class="language-python">from functools import partial

def power(base: int, exp: int) -> int:
return base ** exp

square = partial(power, exp=2)
print(square(7))  # 49</code></pre>
</figure>
<h2>Мини-практикум: 6 задач для закрепления</h2>
<h3>1) Форматтер строк с <b>*args</b> и <b>**kwargs</b></h3>
<pre><code class="language-python">def fmt(*parts, **opts):
    sep = opts.get("sep", " ")
    end = opts.get("end", "!")
    return sep.join(map(str, parts)) + end

print(fmt("Hello", "Python", sep="-", end=" &#x1f680;"))</code></pre>
<h3>2) Нормализатор коллекций</h3>
<pre><code class="language-python">from typing import Iterable, Callable, Any

def normalize(items: Iterable[Any], *, unique=False, key: Callable | None = None):
xs = [key(x) if key else x for x in items]
return list(dict.fromkeys(xs)) if unique else xs

print(normalize([" A ","A","b"], unique=True, key=lambda s: s.strip().lower()))</code></pre>
<h3>3) Глубина вложенных структур</h3>
<pre><code class="language-python">def deep_len(x) -> int:
    if isinstance(x, (list, tuple, set)):
        return sum(deep_len(i) for i in x)
    return 1

print(deep_len([1,(2,3),[4,[5,6]]]))  # 6</code></pre>
<h3>4) Декоратор повторных попыток</h3>
<pre><code class="language-python">import random, time
from functools import wraps

def retry(times=3, delay=0.1):
def deco(fn):
@wraps(fn)
def wrap(*a, **kw):
for attempt in range(times):
try:
return fn(*a, **kw)
except Exception:
if attempt + 1 == times:
raise
time.sleep(delay)
return wrap
return deco

@retry(times=5, delay=0.05)
def flaky():
if random.random() < 0.7:
raise RuntimeError("fail")
return "ok"

print(flaky())</code></pre>
<h3>5) Композиция функций</h3>
<pre><code class="language-python">from typing import Callable

def compose(f: Callable, g: Callable) -> Callable:
return lambda x: f(g(x))

strip_cap = compose(str.capitalize, str.strip)
print(strip_cap("   python  "))  # Python</code></pre>
<h3>6) Проверка контрактов</h3>
<pre><code class="language-python">def require_positive(fn):
    def wrap(x: float):
        assert x &gt;= 0, "x must be non-negative"
        return fn(x)
    return wrap

@require_positive
def sqrt_approx(x: float) -> float:
# примитивная аппроксимация Ньютона
g = x or 1.0
for _ in range(10):
g = 0.5 * (g + x / g)
return g

print(round(sqrt_approx(9), 3))</code></pre>
<h2>FAQ</h2>
<h3>Почему функция возвращает <b>None</b>?</h3>
<p>В ветке отсутствует <b>return</b> или он вызывается без значения. Проверьте условия и убедитесь, что из каждой ветви возвращаете результат.</p>
<h3>Когда использовать <b>*args</b> и <b>**kwargs</b>?</h3>
<p>Когда количество параметров заранее неизвестно или требуется гибкость. Важные аргументы делайте явными, а «настройки» передавайте через <b>**kwargs</b>.</p>
<h3>Чем <b>lambda</b> отличается от <b>def</b>?</h3>
<p><b>lambda</b> — одно выражение без имени; <b>def</b> — именованная функция с произвольным телом. Для простых ключей и однострочных преобразований подходит <b>lambda</b>, всё остальное — через <b>def</b>.</p>
<h3>Как документировать функции?</h3>
<p>Краткий докстринг с назначением, параметрами и возвратом. Для публичного API добавьте примеры. Держите формат единым по проекту.</p>
<h3>Зачем типовые аннотации?</h3>
<p>Они не влияют на выполнение, но повышают качество рецензий, снижают число ошибок и улучшают подсказки IDE.</p>
<h3>Рекурсия или цикл?</h3>
<p>Рекурсия уместна на деревьях и разборе вложенных структур; для длинных последовательностей надёжнее цикл или явный стек.</p>
<h3>Почему изменяемые дефолты — проблема?</h3>
<p>Потому что объект создаётся один раз при определении функции и «копится» между вызовами. Используйте <b>None</b> и создавайте новый контейнер внутри.</p>
<h2>Итоги</h2>
<p>Функции делают код модульным и предсказуемым. Освойте современные сигнатуры (позиционные-только, именованные-только), аккуратно используйте дефолтные значения, применяйте замыкания и декораторы, документируйте и типизируйте интерфейсы, покрывайте ветви тестами. Чем понятнее и короче функции, тем легче расширять систему и быстрее находить ошибки. <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<p>Сообщение <a href="https://system-blog.ru/funkcii-v-python-opredelenie-vyzov-i-prijomy-dlja-postroenija-pereispolzuemogo-koda/">Функции в Python: определение, вызов и приёмы для построения переиспользуемого кода</a> появились сначала на <a href="https://system-blog.ru">Системный блог</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://system-blog.ru/funkcii-v-python-opredelenie-vyzov-i-prijomy-dlja-postroenija-pereispolzuemogo-koda/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Списки в Python: что это такое и как с ними работать</title>
		<link>https://system-blog.ru/spiski-v-python-chto-jeto-takoe-i-kak-s-nimi-rabotat/</link>
					<comments>https://system-blog.ru/spiski-v-python-chto-jeto-takoe-i-kak-s-nimi-rabotat/#respond</comments>
		
		<dc:creator><![CDATA[Vit90]]></dc:creator>
		<pubDate>Tue, 04 Nov 2025 20:52:44 +0000</pubDate>
				<category><![CDATA[Уроки по Python]]></category>
		<guid isPermaLink="false">https://system-blog.ru/?p=1091</guid>

					<description><![CDATA[<p>Списки (list) в Python: полный гид по созданию, изменениям и эффективной работе Список в Python — универсальная коллекция общего назначения. Он поддерживает произвольные типы, изменяется «на месте», легко комбинируется с циклами, генераторами и функциями стандартной библиотеки. Ниже — системный разбор: от базовых операций до нюансов сортировки, копирования и производительности. Ключевая идея Список — упорядоченная и&#8230;&#160;<a href="https://system-blog.ru/spiski-v-python-chto-jeto-takoe-i-kak-s-nimi-rabotat/" rel="bookmark"><span class="screen-reader-text">Списки в Python: что это такое и как с ними работать</span></a></p>
<p>Сообщение <a href="https://system-blog.ru/spiski-v-python-chto-jeto-takoe-i-kak-s-nimi-rabotat/">Списки в Python: что это такое и как с ними работать</a> появились сначала на <a href="https://system-blog.ru">Системный блог</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h2>Списки (list) в Python: полный гид по созданию, изменениям и эффективной работе</h2>
<p>Список в Python — универсальная коллекция общего назначения. Он поддерживает произвольные типы, изменяется «на месте», легко комбинируется с циклами, генераторами и функциями стандартной библиотеки. Ниже — системный разбор: от базовых операций до нюансов сортировки, копирования и производительности.</p>
<h2>Ключевая идея</h2>
<p>Список — <b>упорядоченная</b> и <b>изменяемая</b> последовательность. Это означает:</p>
<ul>
<li>Порядок элементов сохраняется.</li>
<li>Можно добавлять, удалять и заменять элементы без пересоздания объекта.</li>
<li>Поддерживаются смешанные типы и вложенные структуры.</li>
</ul>
<figure class="code"><figcaption>Базовые примеры и мутабельность</figcaption><pre><code class="language-python">empty = []
mix = [1, "a", 3.14, True]
grid = [[1, 2], [3, 4]]        # вложенные списки

mix[0] = 42                    # изменение «на месте»</code></pre>
</figure>
<p>Важно: переменные хранят <b>ссылку</b> на объект. Присваивание создаёт вторую ссылку, а не копию.</p>
<figure class="code"><figcaption>Ссылочная семантика</figcaption><pre><code class="language-python">a = [1, 2, 3]
b = a
b.append(99)
print(a)  # [1, 2, 3, 99]</code></pre>
</figure>
<h2>Создание списков</h2>
<ul>
<li><b>Литерал</b>: <code>[]</code></li>
<li><b>Конструктор</b>: <code>list(iterable)</code></li>
<li><b>Преобразование</b> из других коллекций: tuple, set, range</li>
<li><b>Генератор списка</b> (list comprehension)</li>
</ul>
<figure class="code"><figcaption>Способы создать список</figcaption><pre><code class="language-python">L1 = [1, 2, 3]
L2 = list("abc")            # ['a', 'b', 'c']
L3 = list(range(5))         # [0, 1, 2, 3, 4]
tpl = (10, 20)
L4 = list(tpl)              # [10, 20]
squares = [x * x for x in range(6)]</code></pre>
</figure>
<aside><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f9e8.png" alt="🧨" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Подводный камень: умножение вложенных списков. Конструкция <code>[[0]*3]*2</code> создаёт две строки, указывающие на один и тот же внутренний список.</aside>
<figure class="code"><figcaption>Правильная и неправильная матрица</figcaption><pre><code class="language-python">bad = [[0] * 3] * 2
bad[0][0] = 9
print(bad)  # [[9, 0, 0], [9, 0, 0]]

good = [[0] * 3 for _ in range(2)]  # независимые строки</code></pre>
</figure>
<h2>Индексация и срезы</h2>
<p>Индексация с нуля. Отрицательные индексы отсчитываются с конца. Срезы создают новый список; присваивание срезу изменяет исходный.</p>
<figure class="code"><figcaption>Доступ, срезы и присваивание срезу</figcaption><pre><code class="language-python">L = ["a", "b", "c", "d", "e"]
L[0], L[-1]               # 'a', 'e'
L[1:4]                    # ['b', 'c', 'd']
L[::2]                    # ['a', 'c', 'e']
copy1 = L[:]              # поверхностная копия
L[1:3] = ["B", "C"]       # ['a', 'B', 'C', 'd', 'e']</code></pre>
</figure>
<aside><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2139.png" alt="ℹ" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Присваивание расширенному срезу с шагом требует совпадения длины: <code>L[::2] = [1, 2, 3]</code> — размер правой части должен соответствовать количеству заменяемых позиций.</aside>
<h2>Операции со списками</h2>
<ul>
<li><b>len(L)</b> — размер;</li>
<li><b>in/not in</b> — проверка наличия;</li>
<li><b>+</b> — конкатенация; <b>*</b> — повторение;</li>
<li>лексикографическое сравнение по элементам.</li>
</ul>
<figure class="code"><figcaption>Операции и сравнения</figcaption><pre><code class="language-python">nums = [1, 2, 3]
len(nums)              # 3
2 in nums              # True
nums + [4, 5]          # [1, 2, 3, 4, 5]
["a"] * 3              # ['a', 'a', 'a']</code></pre>
</figure>
<h2>Методы списков: практичный справочник</h2>
<h3>Добавление</h3>
<p><b>append(x)</b> — один элемент в конец; <b>extend(iterable)</b> — добавить элементы итерируемого; <b>insert(i, x)</b> — вставка по индексу.</p>
<figure class="code"><figcaption>append, extend, insert</figcaption><pre><code class="language-python">L = [1, 2]
L.append(3)                # [1, 2, 3]
L.extend([4, 5])           # [1, 2, 3, 4, 5]
L.insert(1, 100)           # [1, 100, 2, 3, 4, 5]

# типичная путаница:

L = [1, 2]; L.append([3, 4])  # [1, 2, [3, 4]] (один элемент-список)</code></pre>
</figure>
<h3>Удаление и извлечение</h3>
<p><b>remove(x)</b> — удаляет первое вхождение; <b>pop(i=-1)</b> — возвращает и удаляет элемент по индексу; <b>clear()</b> — очищает список.</p>
<figure class="code"><figcaption>remove, pop, clear</figcaption><pre><code class="language-python">L = ["a", "b", "b", "c"]
L.remove("b")         # ["a", "b", "c"]
last = L.pop()        # "c", теперь ["a", "b"]
first = L.pop(0)      # "a", теперь ["b"]
L.clear()             # []</code></pre>
</figure>
<h3>Поиск и подсчёт</h3>
<p><b>index(x[, start[, end]])</b> — индекс первого вхождения; <b>count(x)</b> — количество элементов, равных <code>x</code>.</p>
<figure class="code"><figcaption>index и count</figcaption><pre><code class="language-python">L = [10, 20, 10, 30]
L.index(10)        # 0
L.index(10, 1)     # 2
L.count(10)        # 2</code></pre>
</figure>
<h3>Порядок элементов</h3>
<p><b>sort(key=None, reverse=False)</b> — сортирует «на месте»; <b>reverse()</b> — разворачивает список; функция <b>sorted()</b> возвращает новый список.</p>
<figure class="code"><figcaption>Сортировка и разворот</figcaption><pre><code class="language-python">L = ["Bob", "alice", "Carol"]
L.sort()                 # ['Bob', 'Carol', 'alice'] (Unicode-порядок)
L.sort(key=str.lower)    # ['alice', 'Bob', 'Carol'] (без регистра)
L.reverse()              # ['Carol', 'Bob', 'alice']

nums = [3, 1, 2]
sorted(nums)             # [1, 2, 3]; исходник не меняется</code></pre>
</figure>
<aside><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Сортировка в Python <b>стабильная</b>: элементы с равным ключом сохраняют относительный порядок. Это полезно для «многоступенчатых» сортировок по нескольким признакам.</aside>
<h3>Копирование</h3>
<p>Поверхностная копия: <b>L.copy()</b> или <b>L[:]</b>. Для вложенных структур — <b>copy.deepcopy</b>.</p>
<figure class="code"><figcaption>Поверхностная vs глубокая копия</figcaption><pre><code class="language-python">import copy
L = [[1], [2]]
shallow = L.copy()
deep = copy.deepcopy(L)
L[0].append(99)
print(shallow)   # [[1, 99], [2]]
print(deep)      # [[1], [2]]</code></pre>
</figure>
<h2>Итерация и распаковка</h2>
<p>Для доступа к индексам используйте <b>enumerate</b>, для параллельного обхода нескольких коллекций — <b>zip</b>. Удобна «звёздная распаковка».</p>
<figure class="code"><figcaption>enumerate, zip, звёздная распаковка</figcaption><pre><code class="language-python">colors = ["red", "green", "blue"]
for i, c in enumerate(colors, start=1):
    print(i, c)

xs = [1, 2, 3]; ys = [4, 5, 6]
for x, y in zip(xs, ys):
print(x, y)

head, *middle, tail = [10, 20, 30, 40]
print(head, middle, tail)  # 10 [20, 30] 40</code></pre>
</figure>
<h2>Генераторы списков</h2>
<p>Лаконичный синтаксис для построения коллекций с преобразованием и фильтрацией. Когда логика становится громоздкой, лучше перейти к обычному циклу.</p>
<figure class="code"><figcaption>Шаблоны использования</figcaption><pre><code class="language-python">evens = [x for x in range(10) if x % 2 == 0]
pairs = [(x, y) for x in range(3) for y in range(2)]
labels = ["even" if x % 2 == 0 else "odd" for x in range(5)]

# эквивалент через цикл для сложных сценариев

res = []
for x in range(10):
if x % 2 == 0:
res.append(x)</code></pre>
</figure>
<h2>Вложенные списки (таблицы/матрицы)</h2>
<p>«Список списков» — удобная модель двумерных данных. Следите за независимостью строк и осторожно копируйте.</p>
<figure class="code"><figcaption>Матрица и доступ по двум индексам</figcaption><pre><code class="language-python">M = [[1, 2, 3], [4, 5, 6]]
M[1][2]  # 6

rows, cols = 2, 3
M = [[0] * cols for _ in range(rows)]</code></pre>
</figure>
<h2>Стандартные функции, которые «любят» списки</h2>
<ul>
<li><b>sum, min, max</b> — агрегирование;</li>
<li><b>any, all</b> — логические проверки с коротким замыканием;</li>
<li><b>sorted</b> — сортировка без изменения исходника;</li>
<li><b>map, filter</b> — преобразование/фильтрация (часто читаемее через генераторы).</li>
</ul>
<figure class="code"><figcaption>Агрегирование и сортировка по ключу</figcaption><pre><code class="language-python">nums = [3, 5, 1, 4]
sum(nums), min(nums), max(nums)          # 13, 1, 5
any(n % 2 == 0 for n in nums)            # есть ли чётные
all(n > 0 for n in nums)                 # все ли положительные
data = [{"name": "bob", "age": 30}, {"name": "ann", "age": 20}]
sorted(data, key=lambda d: d["age"])</code></pre>
</figure>
<h2>Производительность: что важно знать</h2>
<ul>
<li><b>append</b> — амортизированно O(1).</li>
<li>Вставки/удаления в середине — O(n).</li>
<li>Частые операции «в начале» удобнее переносить на <b>collections.deque</b>.</li>
<li>Не конкатенируйте списки в цикле через <code>+</code>; собирайте элементы и применяйте <b>extend</b> один раз.</li>
</ul>
<h2>Полезные паттерны</h2>
<ul>
<li><b>Стек</b>: <code>append</code> / <code>pop()</code>.</li>
<li><b>Очередь</b>: используйте <code>collections.deque</code> для <code>popleft</code>.</li>
<li><b>Удаление по условию</b>: создавайте новый список, а не меняйте текущий в процессе обхода.</li>
<li><b>Сохранить порядок и удалить дубликаты</b> — через «множество виденных».</li>
</ul>
<figure class="code"><figcaption>Удаление дубликатов с сохранением порядка</figcaption><pre><code class="language-python">seen, out = set(), []
for x in [1, 2, 2, 3, 1, 4]:
    if x not in seen:
        seen.add(x); out.append(x)
print(out)  # [1, 2, 3, 4]</code></pre>
</figure>
<h2>Антипаттерны и частые ошибки</h2>
<ul>
<li>Путаница <b>append</b>/<b>extend</b>.</li>
<li>Ссылки вместо копий (нужны <b>copy</b>, срез или <b>deepcopy</b> для вложенных структур).</li>
<li><code>[[0]*N]*M</code> для матриц — общие ссылки на строки.</li>
<li>Изменение списка во время итерации по нему.</li>
<li>Сравнение значений через <code>is</code> вместо <code>==</code>.</li>
</ul>
<figure class="code"><figcaption>Безопасная фильтрация без «прыгающих» индексов</figcaption><pre><code class="language-python">L = [1, 2, 3, 4, 5]
L = [x for x in L if x % 2 == 0]</code></pre>
</figure>
<h2>Практикум</h2>
<figure class="code"><figcaption>4 упражнения</figcaption><pre><code class="language-python"># 1) чётные квадраты
nums = [1, 2, 3, 4, 5, 6]
print([n * n for n in nums if n % 2 == 0])  # [4, 16, 36]

# 2) разворачивание вложенного списка

nested = [[1, 2], [3, 4, 5]]
flat = [x for sub in nested for x in sub]
print(flat)

# 3) частоты элементов

data = ["a", "b", "a", "c", "b", "a"]
freq = {}
for x in data:
freq[x] = freq.get(x, 0) + 1
print(freq)

# 4) сортировка по второму элементу кортежа (по убыванию)

items = [("a", 3), ("b", 1), ("c", 2)]
print(sorted(items, key=lambda t: t[1], reverse=True))</code></pre>
</figure>
<h2>FAQ</h2>
<h3>Чем отличаются <b>append</b> и <b>extend</b>?</h3>
<p><b>append(x)</b> добавляет один объект как единую сущность; <b>extend(iterable)</b> добавляет элементы итерируемого по одному.</p>
<figure class="code"><figcaption>append vs extend</figcaption><pre><code class="language-python">L = [1, 2]; L.append([3, 4])  # [1, 2, [3, 4]]
L = [1, 2]; L.extend([3, 4])  # [1, 2, 3, 4]</code></pre>
</figure>
<h3>Когда использовать <b>sort</b>, а когда <b>sorted</b>?</h3>
<p><b>list.sort()</b> меняет список «на месте» и возвращает <em>None</em>; <b>sorted(iterable)</b> создаёт новый список, исходник сохраняется.</p>
<h3>Почему умножение списка с вложенными данными даёт неожиданный результат?</h3>
<p>Повторяются ссылки на один и тот же вложенный объект. Для независимых строк используйте генератор списков.</p>
<h3>Как копировать списки корректно?</h3>
<p>Поверхностно: <b>L.copy()</b> или <b>L[:]</b>. Глубоко: <b>copy.deepcopy</b> для вложенных структур.</p>
<h3>Как развернуть список?</h3>
<p><b>reverse()</b> меняет порядок «на месте», срез <b>L[::-1]</b> возвращает новую перевёрнутую копию.</p>
<h2>Итоги</h2>
<p>Списки — фундаментальный инструмент Python. Освойте создание и срезы, грамотно используйте методы добавления/удаления, помните о стабильной сортировке и различии поверхностных и глубоких копий. Учитывайте стоимость операций и выбирайте подходящую структуру данных под задачу. Регулярная практика быстро превращает эти приёмы в автоматизм. <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4aa.png" alt="💪" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<p>Сообщение <a href="https://system-blog.ru/spiski-v-python-chto-jeto-takoe-i-kak-s-nimi-rabotat/">Списки в Python: что это такое и как с ними работать</a> появились сначала на <a href="https://system-blog.ru">Системный блог</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://system-blog.ru/spiski-v-python-chto-jeto-takoe-i-kak-s-nimi-rabotat/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Использование условных операторов (if, elif, else) в Python для управления потоком выполнения программы</title>
		<link>https://system-blog.ru/ispolzovanie-uslovnyh-operatorov-if-elif-else-v-python-dlja-upravlenija-potokom-vypolnenija-programmy/</link>
					<comments>https://system-blog.ru/ispolzovanie-uslovnyh-operatorov-if-elif-else-v-python-dlja-upravlenija-potokom-vypolnenija-programmy/#respond</comments>
		
		<dc:creator><![CDATA[Vit90]]></dc:creator>
		<pubDate>Tue, 04 Nov 2025 20:25:49 +0000</pubDate>
				<category><![CDATA[Уроки по Python]]></category>
		<guid isPermaLink="false">https://system-blog.ru/?p=1088</guid>

					<description><![CDATA[<p>Условные операторы в Python: от простых if до вложенных конструкций Материал разбирает ветвление в Python для новичков и практиков: от базового if и пары «if–else» до каскада if–elif–else, вложенных условий, тернарного оператора, логических и сравнительных выражений, short-circuit-оценки, а также типичных паттернов и антипаттернов. Вы научитесь писать читаемые проверки, избегать лишней вложенности и выбирать подходящую форму&#8230;&#160;<a href="https://system-blog.ru/ispolzovanie-uslovnyh-operatorov-if-elif-else-v-python-dlja-upravlenija-potokom-vypolnenija-programmy/" rel="bookmark"><span class="screen-reader-text">Использование условных операторов (if, elif, else) в Python для управления потоком выполнения программы</span></a></p>
<p>Сообщение <a href="https://system-blog.ru/ispolzovanie-uslovnyh-operatorov-if-elif-else-v-python-dlja-upravlenija-potokom-vypolnenija-programmy/">Использование условных операторов (if, elif, else) в Python для управления потоком выполнения программы</a> появились сначала на <a href="https://system-blog.ru">Системный блог</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h2>Условные операторы в Python: от простых if до вложенных конструкций</h2>
<p>Материал разбирает ветвление в Python для новичков и практиков: от базового <b>if</b> и пары «<b>if–else</b>» до каскада <b>if–elif–else</b>, вложенных условий, тернарного оператора, логических и сравнительных выражений, short-circuit-оценки, а также типичных паттернов и антипаттернов. Вы научитесь писать читаемые проверки, избегать лишней вложенности и выбирать подходящую форму условия под задачу. Поехали! <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f680.png" alt="🚀" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<h2>Зачем нужны условные операторы</h2>
<p>Условные операторы позволяют программе принимать решения на основе булевых выражений: если условие истинно — выполняется один блок кода, иначе — другой. В Python почти любые объекты могут участвовать в проверках «на истинность»: пустые контейнеры и ноль трактуются как <em>False</em>, непустые и ненулевые — как <em>True</em>. Это добавляет гибкости: валидируете входные данные, выбираете алгоритм, пропускаете лишние шаги, обрабатываете особые случаи.</p>
<ul>
<li><b>Истинность/ложность (truthy/falsy).</b> <em>False</em>, <em>None</em>, <em>0</em>, пустые <em>&#187;</em>, <em>[]</em>, <em>{}</em>, <em>set()</em> считаются ложными; остальное — истинным.</li>
<li><b>Ветвление.</b> Позволяет пройти разными путями исполнения.</li>
<li><b>Читаемость.</b> Аккуратные условия облегчают поддержку кода.</li>
</ul>
<h2>Базовый if: синтаксис, отступы и блоки</h2>
<p>Python использует <b>отступы</b> в 4 пробела для выделения блоков. После двоеточия идёт блок, который выполняется при истинности условия.</p>
<p><code># Простой if<br />temp = 21<br />if temp &gt;= 20:<br />&nbsp;&nbsp;print("Тепло, выходим без куртки")</code></p>
<p>В блоке можно выполнять несколько операторов. Держите единый стиль и не смешивайте табы с пробелами.</p>
<p><code># Несколько выражений в блоке<br />balance = 500<br />cost = 200<br />if balance &gt;= cost:<br />&nbsp;&nbsp;balance -= cost<br />&nbsp;&nbsp;print("Покупка оформлена, остаток:", balance)</code></p>
<h2>Пара if–else: двоичный выбор</h2>
<p><b>if–else</b> покрывает два взаимоисключающих сценария. Если условие ложно — срабатывает ветка <b>else</b>.</p>
<p><code>age = 17<br />if age &gt;= 18:<br />&nbsp;&nbsp;msg = "совершеннолетний"<br />else:<br />&nbsp;&nbsp;msg = "несовершеннолетний"<br />print(msg)</code></p>
<p>Совет: не пишите лишний <em>else</em>, если он не несёт пользы. Часто достаточно вернуть результат в ветке <em>if</em> и продолжить обычный ход функции.</p>
<h2>Каскад if–elif–else: множественный выбор</h2>
<p>Когда вариантов больше двух, используйте цепочку <b>if–elif–else</b>. Ветви проверяются сверху вниз до первого совпадения.</p>
<p><code>code = 404<br />if code == 200:<br />&nbsp;&nbsp;text = "OK"<br />elif code == 301:<br />&nbsp;&nbsp;text = "Moved Permanently"<br />elif code == 404:<br />&nbsp;&nbsp;text = "Not Found"<br />else:<br />&nbsp;&nbsp;text = "Other"<br />print(text)</code></p>
<p>Если вариантов очень много и они «табличные», подумайте о «таблице соответствий» на словаре — читается короче.</p>
<p><code># Таблица соответствий вместо «лестницы» elif<br />responses = {200: "OK", 301: "Moved Permanently", 404: "Not Found"}<br />text = responses.get(code, "Other")</code></p>
<h2>Вложенные условия: когда можно и когда нельзя</h2>
<p>Вложенность уместна, когда проверка одного условия логически зависит от другого. Слишком глубокие «лестницы» ухудшают читаемость.</p>
<p><code># Умеренная вложенность<br />user = {"role": "admin", "active": True}<br />if user and user.get("active"):<br />&nbsp;&nbsp;if user.get("role") == "admin":<br />&nbsp;&nbsp;&nbsp;&nbsp;print("Админский доступ открыт")<br />&nbsp;&nbsp;else:<br />&nbsp;&nbsp;&nbsp;&nbsp;print("Обычный пользователь")</code></p>
<p>Как уменьшить вложенность:</p>
<ul>
<li><b>Guard-clauses.</b> Сначала обрабатывайте «плохие» случаи и выходите из функции.</li>
<li><b>Возврат из веток.</b> <em>return</em> внутри условия делает код прямолинейнее.</li>
<li><b>Словарь-свитч.</b> Заменяет длинные цепочки <em>elif</em>.</li>
</ul>
<p><code># Guard-clauses вместо глубины<br />def can_access(user):<br />&nbsp;&nbsp;if not user: return False<br />&nbsp;&nbsp;if not user.get("active"): return False<br />&nbsp;&nbsp;return user.get("role") == "admin"</code></p>
<h2>Тернарный оператор: компактный if–else</h2>
<p>Для простых выборов используйте условное выражение — коротко и наглядно, когда обе ветки поверхностные.</p>
<p><code># syntax: A if condition else B<br />age = 20<br />status = "OK" if age &gt;= 18 else "FAIL"<br />print(status)</code></p>
<p>Не злоупотребляйте тернарным выражением: если логика разрастается, обычный <em>if</em> читается лучше.</p>
<h2>Логические и сравнительные операторы в условиях</h2>
<p>Условия часто комбинируют логику <b>and</b>, <b>or</b>, <b>not</b> и сравнения <b>==</b>, <b>!=</b>, <b>&lt;</b>, <b>&lt;=</b>, <b>&gt;</b>, <b>&gt;=</b>. В Python есть «цепочки сравнений» и short-circuit-оценка.</p>
<ul>
<li><b>Цепочки сравнений.</b> <em>0 &lt;= x &lt; 10</em> эквивалентно двум проверкам с <em>and</em>, но читается лучше.</li>
<li><b>Short-circuit.</b> В <em>A and B</em> вторая часть не вычисляется, если <em>A</em> ложна; в <em>A or B</em> — если <em>A</em> истинна.</li>
<li><b>in / not in.</b> Проверяет принадлежность элементу в коллекции.</li>
</ul>
<p><code>x = 7<br />if 0 &lt;= x &lt; 10 and x != 5:<br />&nbsp;&nbsp;print("x в допустимом диапазоне и не равен 5")</p>
<p># short-circuit для безопасного доступа<br />user = None<br />if user and user.get("email"):<br />&nbsp;&nbsp;print("Отправляем письмо")</code></p>
<p>Не путайте логические операторы с побитовыми: в Python побитовый — <em>&amp;</em>, а логический — <b>and</b>.</p>
<h2>Truthy/Falsy и проверка пустых значений</h2>
<p>Часто удобнее проверять объект «как есть», без явного сравнения.</p>
<p><code># Неудачно (шумно)<br />if len(items) &gt; 0:<br />&nbsp;&nbsp;...<br /># Лучше (питоничнее)<br />if items:<br />&nbsp;&nbsp;...</code></p>
<p>Отличайте «нет значения» от «нулевого значения». Явно проверяйте <em>None</em>, если ноль и пустая строка допустимы.</p>
<p><code># Отличайте None от нуля<br />count = 0<br />if count is None:<br />&nbsp;&nbsp;print("значение ещё не вычислено")<br />elif count == 0:<br />&nbsp;&nbsp;print("нулевое значение — это нормально")</code></p>
<h2>Паттерны: диапазоны, словари-свитчи, ранний выход, валидация</h2>
<p>Пара приёмов для ежедневных задач <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f447.png" alt="👇" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<h3>Проверка диапазонов и принадлежности</h3>
<p><code>score = 73<br />if 90 &lt;= score &lt;= 100:<br />&nbsp;&nbsp;grade = "A"<br />elif 75 &lt;= score &lt; 90:<br />&nbsp;&nbsp;grade = "B"<br />elif 60 &lt;= score &lt; 75:<br />&nbsp;&nbsp;grade = "C"<br />else:<br />&nbsp;&nbsp;grade = "D"</code></p>
<h3>Словарь вместо каскада elif (таблица соответствий)</h3>
<p><code>def op_add(a, b): return a + b<br />def op_sub(a, b): return a - b<br />def op_mul(a, b): return a * b<br />ops = {"+": op_add, "-": op_sub, "*": op_mul}<br />op = "*"<br />result = ops.get(op, lambda a, b: None)(3, 4)</code></p>
<h3>Ранний выход (guard-clauses)</h3>
<p><code>def normalize(email):<br />&nbsp;&nbsp;if not email: return None<br />&nbsp;&nbsp;email = email.strip()<br />&nbsp;&nbsp;if "@" not in email: return None<br />&nbsp;&nbsp;return email.lower()</code></p>
<h3>Валидация входных данных</h3>
<p><code>raw_age = "18"<br />age = int(raw_age) if raw_age.isdigit() else None<br />if age is None or not (0 &lt;= age &lt;= 120):<br />&nbsp;&nbsp;print("Некорректный возраст")</code></p>
<h2>Антипаттерны и типичные ошибки</h2>
<ul>
<li><b>Лишняя вложенность.</b> Выталкивайте ранние проверки наверх и используйте словари-свитчи.</li>
<li><b>Сравнение с None через ==.</b> Правильно: <em>is</em> / <em>is not</em>.</li>
<li><b>Преждевременная оптимизация.</b> Ясность важнее микровыгод.</li>
<li><b>Перегруженные условия.</b> Выносите подвыражения в именованные переменные или функции.</li>
<li><b>Смешение табов/пробелов.</b> Единый стиль отступов: 4 пробела.</li>
<li><b>&amp; вместо and.</b> Побитовые операции не для логики ветвления.</li>
</ul>
<p><code># Вынос сложного условия в именованные предикаты<br />is_email = lambda s: s and "@" in s<br />is_corporate = lambda s: s.endswith("@example.com") if s else False<br />if is_email(email) and not is_corporate(email):<br />&nbsp;&nbsp;print("только личные адреса")</code></p>
<h2>Мини-практикум: 4 задания для закрепления</h2>
<h3>1) Категории по возрасту</h3>
<p><code>age = int(input("Возраст: "))<br />if age &lt; 0: print("ошибка")<br />elif age &lt; 12: print("ребёнок")<br />elif age &lt; 18: print("подросток")<br />elif age &lt; 65: print("взрослый")<br />else: print("старше 65")</code></p>
<h3>2) Проверка високосного года</h3>
<p><code>year = int(input("Год: "))<br />if (year % 400 == 0) or (year % 4 == 0 and year % 100 != 0):<br />&nbsp;&nbsp;print("високосный")<br />else:<br />&nbsp;&nbsp;print("обычный")</code></p>
<h3>3) Маршрутизация команды (словарь-свитч)</h3>
<p><code>cmd = input("Команда: ")<br />def start(): print("стартуем")<br />def stop(): print("останавливаемся")<br />def help(): print("команды: start/stop/help")<br />router = {"start": start, "stop": stop, "help": help}<br />router.get(cmd, help)()</code></p>
<h3>4) Валидация формы</h3>
<p><code>email = input("Email: ").strip()<br />password = input("Пароль: ")<br />if not email or "@" not in email:<br />&nbsp;&nbsp;print("некорректный email")<br />elif len(password) &lt; 8:<br />&nbsp;&nbsp;print("короткий пароль")<br />else:<br />&nbsp;&nbsp;print("ок")</code></p>
<h2>Расширения темы: match/case, исключения, логирование</h2>
<p>Хотя <b>match/case</b> — сопоставление с образцом, его удобно использовать как альтернативу большому каскаду <em>elif</em>, когда проверяете конкретные значения и формы данных.</p>
<p><code># match/case (Python 3.10+)<br />status = 404<br />match status:<br />&nbsp;&nbsp;case 200: print("OK")<br />&nbsp;&nbsp;case 301: print("Moved")<br />&nbsp;&nbsp;case 404: print("Not Found")<br />&nbsp;&nbsp;case _: print("Other")</code></p>
<p>Рядом с условными конструкциями идут <b>исключения</b> и <b>логирование</b>: ловите «исключительные» ситуации через <em>try/except</em>, а не через громоздкие <em>if</em>; фиксируйте решения логами, чтобы понимать, почему условие сработало. <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f41e.png" alt="🐞" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<p><code>import logging; logging.basicConfig(level=logging.INFO)<br />try:<br />&nbsp;&nbsp;price = float(input("Цена: "))<br />&nbsp;&nbsp;if price &lt; 0: raise ValueError("отрицательная цена")<br />&nbsp;&nbsp;logging.info("ok: %s", price)<br />except ValueError as e:<br />&nbsp;&nbsp;logging.error("ошибка ввода: %s", e)</code></p>
<h2>Чек-лист читаемых условий</h2>
<ul>
<li>Пишите условия <b>коротко</b> и <b>прямо</b>; разбивайте сложные выражения.</li>
<li>Используйте <b>цепочки сравнений</b> и <b>in</b>, где это уместно.</li>
<li>Избегайте глубокой вложенности: применяйте guard-clauses и словари.</li>
<li>Разгружайте условие именованными булевыми переменными/функциями.</li>
<li>Проверяйте <b>is None</b> вместо <em>== None</em>.</li>
<li>Для простых выборов — <b>тернарный оператор</b>, но без фанатизма <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></li>
</ul>
<h2>Полезные ссылки и итоги</h2>
<ul>
<li><b>Документация Python:</b> разделы про выражения и инструкции управления.</li>
<li><b>PEP 8:</b> рекомендации по стилю условий и отступов.</li>
<li><b>Практика:</b> песочницы и задачники для тренировки логики (Codewars, LeetCode, HackerRank).</li>
</ul>
<p>Итог: условные операторы — фундамент ветвления программ. Освойте базовый <b>if</b>, двоичный выбор <b>if–else</b>, каскад <b>if–elif–else</b>, применяйте тернарный оператор для коротких присваиваний, держите условия простыми и читаемыми, избегайте глубокой вложенности и используйте «инструменты снижения сложности» — guard-clauses и словари-свитчи. Чем яснее проверки, тем надёжнее и предсказуемее поведение приложения <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<p>Сообщение <a href="https://system-blog.ru/ispolzovanie-uslovnyh-operatorov-if-elif-else-v-python-dlja-upravlenija-potokom-vypolnenija-programmy/">Использование условных операторов (if, elif, else) в Python для управления потоком выполнения программы</a> появились сначала на <a href="https://system-blog.ru">Системный блог</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://system-blog.ru/ispolzovanie-uslovnyh-operatorov-if-elif-else-v-python-dlja-upravlenija-potokom-vypolnenija-programmy/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
