В чем разница между list и tuple?
list изменяемый, поддерживает добавление/удаление; tuple неизменяемый, можно хешировать и использовать в ключах словарей.
lst = [1, 2]; lst.append(3)
tpl = (1, 2, 3) # tpl[0] = 5 -> TypeError
Ответы на частые вопросы по Python
list изменяемый, поддерживает добавление/удаление; tuple неизменяемый, можно хешировать и использовать в ключах словарей.
lst = [1, 2]; lst.append(3)
tpl = (1, 2, 3) # tpl[0] = 5 -> TypeError
dict — хеш-таблица; доступ/вставка/удаление в среднем O(1), в худшем O(n).
d = {'a': 1}; d['b'] = 2; val = d['a']
set хранит уникальные элементы без порядка и дает O(1) поиск по хешу; list упорядочен и допускает дубликаты.
s = {1, 2, 2}; len(s) == 2
lst = [1, 2, 2] # длина 3
Синтаксический сахар для генерации списка в одной строке с фильтрами и вложенными циклами.
[x*x for x in range(5) if x % 2 == 0] # [0, 4, 16]
Генератор ленивый и не хранит все элементы в памяти; list хранит все сразу.
(x*x for x in range(10)) # генератор
list(x*x for x in range(10)) # сразу список
Объект с __iter__ и __next__, выдающий элементы по одному и завершающийся StopIteration.
it = iter([1,2]); next(it) # 1; next(it) # 2; next(it) -> StopIteration
Объект, по которому можно итерироваться (__iter__ или __getitem__ с индексом).
for ch in "abc": print(ch)
class C: __getitem__ = lambda self,i: (1 if i<3 else (_ for _ in ()).throw(StopIteration))
__iter__ возвращает итератор; __next__ возвращает следующий элемент или StopIteration.
class C:
def __iter__(self): return self
def __next__(self): raise StopIteration
Global Interpreter Lock — мьютекс CPython, разрешающий байткод только одному потоку одновременно.
import threading
# CPU-bound в двух потоках не ускорится из-за GIL
При I/O-bound задачах, при multiprocessing, либо когда C-расширения временно отпускают GIL.
requests.get(...) в нескольких потоках — параллельное I/O
multiprocessing.Pool для CPU-bound
threading делит память и упирается в GIL; multiprocessing создает процессы с отдельной памятью, обходя GIL.
threading.Thread(target=io_task)
multiprocessing.Process(target=cpu_task)
При множестве I/O-задач с малой нагрузкой CPU: сокеты, HTTP, файлы; не подходит для чистого CPU-bound.
async def main():
async with aiohttp.ClientSession() as s:
await s.get(url)
async/await — кооперативная многозадачность в одном потоке; threads — системные потоки, планируются ОС.
await coro() # не блокирует event loop
threading.Thread(target=func).start()
Функция, принимающая функцию/метод и возвращающая обертку с доп. логикой.
def log(f):
def wrap(*a, **k): print(f.__name__); return f(*a, **k)
return wrap
@log
def hello(): pass
Использовать functools.wraps для копирования __name__, __doc__ и др.
from functools import wraps
@wraps(func)
def wrapper(*a, **k): ...
Объект с __enter__/__exit__, гарантирующий освобождение ресурсов в блоке with.
with open('f.txt') as f:
data = f.read()
Через contextlib.contextmanager и генератор с yield.
from contextlib import contextmanager
@contextmanager
def cm():
res = open('f'); yield res; res.close()
Быстрые итераторы для комбинаторики, группировки, бесконечных последовательностей.
from itertools import chain, product
list(chain([1,2],[3])) # [1,2,3]
Shallow копирует контейнер, но вложенные ссылки общие; deepcopy рекурсивно копирует всё.
import copy
b = copy.copy(a)
c = copy.deepcopy(a)
Синтаксический сахар для классов данных: автогенерация __init__, __repr__, сравнения.
from dataclasses import dataclass
@dataclass
class P: x:int; y:int
__slots__ экономит память и ускоряет доступ, запрещая произвольные атрибуты (__dict__ не создается).
class P:
__slots__ = ('x','y')
def __init__(self,x,y): self.x=x; self.y=y
@staticmethod не получает self/cls; @classmethod получает cls и работает с классом/наследниками.
class C:
@staticmethod
def s(x): return x
@classmethod
def c(cls): return cls
== сравнивает значения (__eq__), is сравнивает идентичность (один объект).
a = [1]; b = [1]; a == b # True; a is b # False
Нужен __hash__ и неизменяемое состояние, чтобы hash(a)==hash(b) при a==b сохранялось.
hash((1,2)) # ок; hash([1,2]) -> TypeError
try/except; в except logger.exception или exc_info=True; освобождение ресурсов через finally/with.
try:
1/0
except Exception:
logger.exception("fail")
Подсказки типов для статпроверки (mypy/pyright), автодополнения и документации.
def add(x: int, y: int) -> int:
return x + y
Описывает структурный тип (duck typing) для статической проверки интерфейсов.
class R(Protocol):
def read(self, n: int) -> str: ...
MutableSequence требует методы мутации; Sequence — только чтение/итерацию/len.
from collections.abc import MutableSequence, Sequence
Стиль кода: отступ 4 пробела, длина строки 79/99, имена, пробелы вокруг операторов.
# хорошо: value = func(arg1, arg2)
# плохо: value=func( arg1,arg2 )
venv встроен (3.3+); virtualenv старше, часто быстрее создаёт окружение, имеет доп. фичи.
python -m venv .venv
source .venv/bin/activate
requirements.txt или lock-файлы (poetry.lock/Pipfile.lock) для воспроизводимости версий.
pip freeze > requirements.txt
pip install -r requirements.txt
Команда выводит установленные пакеты и версии; часто используют для requirements.txt.
pip freeze > requirements.txt
pip ставит в текущее окружение; pipx ставит CLI-инструменты изолированно и добавляет в PATH.
pipx install black
black --version
Использовать with open(...) для гарантии закрытия; указывать encoding; ловить IOErrors.
with open('data.txt', 'r', encoding='utf-8') as f:
data = f.read()
ООП-обертка путей с удобными методами и оператором / для join.
from pathlib import Path
p = Path('data')/'file.txt'
text = p.read_text()
json.dumps/json.dump; для нестандартных типов использовать default или приведение.
import json
json.dumps({'x': 1})
pickle.dump/load; не грузить непроверенные данные из-за RCE рисков.
import pickle
pickle.dump(obj, open('f.pkl','wb'))
CSV для плоских таблиц; JSON для вложенных структур. CSV компактнее, но без вложенности.
import csv
with open('f.csv','w',newline='') as f: csv.writer(f).writerow(['a',1])
Использовать time.perf_counter; можно завернуть в контекст/декоратор.
import time
start = time.perf_counter(); ...; dt = time.perf_counter()-start
cProfile + pstats/snakeviz; для строк — line_profiler; для async — yappi/py-spy.
python -m cProfile -o out.prof script.py
snakeviz out.prof
tracemalloc, objgraph, memory_profiler для строк.
import tracemalloc
tracemalloc.start()
# ...
print(tracemalloc.get_traced_memory())
Декоратор мемоизации с ограничением размера и счётчиками hit/miss.
from functools import lru_cache
@lru_cache(maxsize=128)
def fib(n): ...
Файлы test_*.py, функции test_*; фикстуры через @pytest.fixture, параметризация через parametrize.
def test_sum():
assert 1+2 == 3
Контекст/декоратор, проверяющий, что код поднимает ожидаемое исключение.
with self.assertRaises(ValueError):
int('abc')
Использовать unittest.mock: patch/MagicMock/autospec/side_effect; патчить точку использования.
from unittest.mock import patch
with patch('pkg.mod.func', return_value=1): ...
Передача зависимостей через параметры/конструктор вместо жестких импортов, упрощает тестирование и подмены.
def handler(repo: Repo): repo.save(...)
handler(MockRepo())
property создает дескриптор для геттеров/сеттеров, позволяя вызывать метод как атрибут.
class P:
@property
def x(self): return 1
Объект с __get__/__set__/__delete__, контролирующий доступ к атрибуту.
class D:
def __get__(self, obj, owner): return 42
class C: x = D()
super ищет следующий класс в MRO и делегирует вызов.
class A: def f(self): print('A')
class B(A):
def f(self): super().f(); print('B')
Method Resolution Order — порядок поиска атрибутов (C3-линеаризация).
C.__mro__ показывает порядок
В 3.x все классы — новый стиль (наследуются от object); в 2.x нужно было явно наследоваться.
class A: pass # уже новый стиль в 3.x
Подсчет ссылок + поколенческий GC для циклов (поколения 0/1/2).
import gc; gc.get_threshold()
Редко; вручную при контролируемых пиках/циклах или профилировании.
import gc
gc.collect()
Слабые ссылки не увеличивают счётчик и позволяют GC собрать объект; полезно для кэшей.
import weakref
w = weakref.ref(obj)
map применяет функцию, filter отбирает по предикату, reduce сворачивает в одно значение.
list(map(str, [1,2]))
list(filter(lambda x: x%2, [1,2,3]))
*args собирает позиционные аргументы, **kwargs — именованные.
def f(*a, **k): print(a, k)
f(1,2,x=3)
Позволяет присвоить и использовать значение внутри выражения, снижая дублирование.
if (n := len(data)) > 0: print(n)
Именованный tuple с полями, неизменяемый и хешируемый.
from typing import NamedTuple
class P(NamedTuple): x:int; y:int
str — Unicode, bytes — сырые байты; преобразование через encode/decode.
b = 'привет'.encode('utf-8'); s = b.decode('utf-8')
dict1 == dict2 сравнивает ключи и значения; подмножества — через сравнение sets of items/keys.
d1 == d2
set(d1.items()) <= set(d2.items())
Итерирует с парами (index, value); удобнее range(len(...)).
for i, v in enumerate(['a','b']): print(i, v)
slicing seq[::-1] или reversed(seq); in-place — list.reverse().
lst[::-1]
lst.reverse()
sorted возвращает новый список; list.sort сортирует на месте и возвращает None.
sorted(lst)
lst.sort()
Указать key=функция, можно reverse=True.
sorted(users, key=lambda u: u.age, reverse=True)
Комбинирует элементы итерируемых в кортежи по позиции, обрывается по кратчайшему.
list(zip([1,2],["a","b","c"])) # [(1,'a'),(2,'b')]
* для позиционных, ** для именованных при вызове функции.
f(*[1,2], **{'x':3})
Форматирование через f"...{expr}...", быстро и читаемо, поддерживает выражения.
name = 'Bob'; f"Hi {name}"
f-строки короче и быстрее; str.format гибче для динамических шаблонов.
"{x}".format(x=1)
f"{1+1}"
round(x, n) — банковское округление; для денег лучше Decimal.quantize.
from decimal import Decimal
Decimal('1.235').quantize(Decimal('0.01'))
Десятичная арифметика с контролем точности/округления, полезна для денег.
from decimal import Decimal, getcontext
getcontext().prec = 28
Decimal('0.1') + Decimal('0.2')
datetime/date/time/timedelta; таймзоны — zoneinfo/pytz; формат/парсинг через strftime/strptime.
from datetime import datetime
now = datetime.now().strftime('%Y-%m-%d')
Считает частоты элементов, есть most_common и арифметика счетчиков.
from collections import Counter
Counter('abba').most_common(1)
Сохраняет порядок вставки; dict в 3.7+ тоже упорядочен, но OrderedDict дает move_to_end и др.
from collections import OrderedDict
od = OrderedDict(); od['a']=1; od.move_to_end('a')
Двусторонняя очередь, O(1) добавление/удаление с концов.
from collections import deque
d = deque([1,2]); d.appendleft(0)
Для приоритетных очередей/top-k; push/pop O(log n).
import heapq
h=[]; heapq.heappush(h, 3); heapq.heappush(h,1); heapq.heappop(h)
heapq.nlargest/nsmallest быстрее полной сортировки при малом k.
heapq.nlargest(3, data)
Бинарный поиск позиции вставки в отсортированной последовательности.
import bisect
idx = bisect.bisect_left([1,3,5], 4)
Сравнивает float с учетом относит./абсолютной погрешности.
math.isclose(0.1+0.2, 0.3, rel_tol=1e-9)
NaN != NaN по ==; is сравнивает объект; использовать math.isnan.
import math
math.isnan(float('nan'))
Параллельный запуск корутин с ожиданием всех; результаты в порядке аргументов.
await asyncio.gather(coro1(), coro2())
asyncio.wait_for(coro, timeout) или комбинация first_completed.
await asyncio.wait_for(coro(), timeout=1.0)
create_task планирует корутину конкурентно; await ждет завершения.
task = asyncio.create_task(coro()); await task
signal.signal для обработчиков; ограничения на Windows; в asyncio add_signal_handler (не Windows).
import signal
signal.signal(signal.SIGINT, handler)
argparse (stdlib) или click/typer; для простого — sys.argv.
import argparse
p=argparse.ArgumentParser(); p.add_argument('--x'); args=p.parse_args()
Поиск файлов по шаблону (включая ** для рекурсии).
for p in Path('.').glob('**/*.py'): print(p)
pathlib — ООП API с / оператором; os.path — процедурные функции.
Path('a')/'b'
os.path.join('a','b')
os.environ для чтения/установки; dotenv для загрузки .env; не хранить секреты в коде.
import os
os.environ.get('TOKEN')
Быстрая настройка логирования: уровень, формат, хендлеры.
import logging
logging.basicConfig(level=logging.INFO)
logger.exception или logger.error(..., exc_info=True); в stdout — traceback.print_exc.
try:
1/0
except Exception:
logger.exception('fail')
Управляет показом предупреждений (ignore/error/default) по категориям/модулям.
import warnings
warnings.filterwarnings('ignore', category=DeprecationWarning)
Валидация/парсинг данных по аннотациям типов, генерирует модели.
from pydantic import BaseModel
class User(BaseModel): name: str; age: int
FastAPI асинхронный с автодокой/схемой; Flask минималистичный синхронный.
app = FastAPI(); @app.get('/') async def root(): return {'ok':True}
WSGI — синхронный протокол веб-приложений; ASGI — асинхронный, поддерживает WebSocket/фоновые задачи.
gunicorn (WSGI) vs uvicorn (ASGI)
Параметризованные запросы, избегать конкатенации строк; для сложного использовать ORM.
cur.execute('SELECT * FROM t WHERE id=%s', (id_,))
Object-Relational Mapping: отображение таблиц в классы; напр. SQLAlchemy, Django ORM.
class User(Base): __tablename__='users'; id=Column(Integer, primary_key=True)
Контекстные переменные для изоляции состояния в async/greenlet, аналог thread-local.
from contextvars import ContextVar
user = ContextVar('user')
Токен-бакеты/семафоры/счетчики (Redis), задержки в клиентах.
sem = asyncio.Semaphore(5)
async with sem: await fetch()
Хешировать с солью (bcrypt/argon2/scrypt), не хранить в открытом виде.
bcrypt.hashpw(pwd, bcrypt.gensalt())
copy.copy — поверхностная копия; deepcopy копирует рекурсивно.
copy.copy(obj)
copy.deepcopy(obj)
__enter__ возвращает объект; __exit__ получает тип/значение/traceback ошибки и решает, подавлять ли её.
class CM:
def __enter__(self): return self
def __exit__(self, exc_type, exc, tb): return False
Динамическая подмена атрибутов/функций во время исполнения; удобно в тестах, рискованно в проде.
module.func = lambda: 1
namedtuple — легкий неизменяемый tuple с именами; dataclass — полноценный класс с автогенерацией методов.
from collections import namedtuple
P = namedtuple('P','x y')
from dataclasses import dataclass
@dataclass
class D: x:int; y:int
__all__ определяет, что экспортируется при from module import *.
__all__ = ['foo', 'Bar']
Блок выполняется при прямом запуске скрипта, не при импорте.
if __name__ == '__main__':
main()
Встроенный отладчик: pdb.set_trace() стартует интерактивную сессию.
import pdb; pdb.set_trace()
typing.TypeGuard позволяет предикатами уточнять типы для статанализа.
def is_int(x) -> TypeGuard[int]: return isinstance(x, int)
functools.singledispatch реализует диспетчеризацию по типу первого аргумента.
from functools import singledispatch
@singledispatch
def f(x): ...
@f.register(int)
def _(x): ...
Для функций — lru_cache; для объектов — dict + инвалидация.
from functools import lru_cache
@lru_cache
def calc(x): ...
argparse или click/typer для лаконичного синтаксиса и автодоки.
import click
@click.command()
@click.option('--x')
def main(x): ...
__getattribute__ вызывается всегда; __getattr__ — только если атрибут не найден.
class C:
def __getattribute__(self, name): ...
def __getattr__(self, name): ...
Нужно объявлять __slots__ во всех классах; слоты предков объединяются.
class A: __slots__=('x',)
class B(A): __slots__=('y',)
__enter__ может вернуть ресурс, присваиваемый после as.
with open('f') as f: ... # f из __enter__
Итерироваться по файлу или использовать fileinput; не читать целиком.
for line in open('big.txt', 'r'): process(line)
Модули stdlib для работы с zip/tar: чтение/запись/список содержимого.
import zipfile
with zipfile.ZipFile('a.zip','w') as z: z.write('file.txt')
Не использовать eval/exec на непроверенных данных; запускать изолированно (subprocess, контейнер).
subprocess.run(['python','script.py'])
Запускает команду, может ждать завершения и вернуть CompletedProcess; для потоков ввода/вывода использовать pipes.
subprocess.run(['ls','-l'], check=True, capture_output=True)
Модуль для динамического импорта/перезагрузки модулей: import_module, reload.
import importlib
mod = importlib.import_module('math')
Декуплировать модули, переносить импорты внутрь функций, выделять общее в отдельный модуль.
def func():
from . import other
...
Включают поведение будущих версий (division, annotations и др.) для совместимости.
from __future__ import annotations
NumPy/Numba/Cython; избегать питонских циклов, использовать векторизацию/JIT.
import numpy as np
np.array([1,2,3]) * 2
multiprocessing или ProcessPoolExecutor, либо C/Numba без GIL.
from concurrent.futures import ProcessPoolExecutor
with ProcessPoolExecutor() as ex: ex.map(f, data)
add_signal_handler на Unix; на Windows ловить KeyboardInterrupt и ставить Event/flag.
loop.add_signal_handler(signal.SIGINT, cb) # Unix