Как проверить пароль в Python: несколько правил и все ошибки

Python Автор: Среда и версия: CPython 3.14.5
содержание

Проверка пароля состоит из нескольких независимых вопросов: хватает ли символов, есть ли цифра, встретились ли буквы обоих регистров. Если интерфейс должен показать все замечания сразу, программа не останавливается после первой ошибки. Она проверяет каждое правило и возвращает нарушения в предсказуемом порядке. Примеры ниже выполнены на CPython 3.14.5.

Python / 01

Все правила проверяются независимо

Все правила проверяются независимо01 / вход 02 / операция 03 / результат password = "abc" длина ≥ 8 нет · нарушение тот же пароль есть цифра нет · нарушение тот же пароль есть заглавная нет · нарушение тот же пароль есть строчная да · пройдено01 / вход02 / операция03 / результатpassword = "abc"длина ≥ 8нет · нарушениетот же парольесть цифранет · нарушениетот же парольесть заглавнаянет · нарушениетот же парольесть строчнаяда · пройдено
Цепочка if — elif остановилась бы на первой ошибке. Четыре отдельных if дают полный список подсказок за одну проверку.

Сначала зафиксируйте контракт проверки

Фраза «пароль должен быть надёжным» не задаёт алгоритм. Нужны точные условия и форма результата. Например, учебный валидатор может требовать минимальную длину, хотя бы одну цифру, заглавную и строчную букву. Результатом служит список кодов ошибок; пустой список означает, что все проверки пройдены.

До написания кода ответьте на четыре вопроса:

  1. Граница длины включительная или строгая?
  2. Что считать цифрой и буквой нужного регистра?
  3. Нужно вернуть первую ошибку или все ошибки?
  4. В каком порядке должны идти коды нарушений?

Последние два пункта влияют на структуру программы. Цепочка if — elif выбирает одну ветку, поэтому подходит для взаимоисключающих случаев. Требования к паролю независимы: одна строка может одновременно оказаться короткой, не содержать цифр и не иметь заглавных букв. Для такого контракта каждое правило проверяют отдельно.

len() считает символы строки

Встроенная функция len() возвращает число элементов последовательности. Для строки это число кодовых точек Unicode, а не размер в байтах.

samples = ["code", "пароль", "🔐code"]

for sample in samples:
    print(repr(sample), len(sample))
'code' 4
'пароль' 6
'🔐code' 5

На границе легко допустить ошибку на единицу. Если минимальная длина равна восьми, строка из восьми символов проходит это правило, а из семи — нет. В тестах нужны оба случая: только так проверяется сам знак сравнения.

Есть и тонкость Unicode. Визуально одинаковые символы могут состоять из разного числа кодовых точек. Например, é бывает одним символом или сочетанием e и отдельного ударения:

composed = "é"
combined = "e\u0301"

print(len(composed), len(combined), composed == combined)
1 2 False

Для учебной задачи достаточно поведения len(), если контракт не говорит об ином. В продуктовой форме политику Unicode и нормализации задают отдельно: незаметно менять пароль перед сохранением нельзя.

Методы строки проверяют один символ без таблиц алфавита

Методы str.isdigit(), str.isupper() и str.islower() работают и с Unicode. Поэтому ручные диапазоны вроде '0' <= char <= '9' и 'A' <= char <= 'Z' задают более узкую политику, чем строковые методы Python.

characters = ["7", "٧", "²", "A", "Я", "a", "я", "-"]

for char in characters:
    print(char, char.isdigit(), char.isupper(), char.islower())
7 True False False
٧ True False False
² True False False
A False True False
Я False True False
a False False True
я False False True
- False False False

isdigit() считает цифрами не только ASCII-символы 0–9: арабско-индийская цифра ٧ и надстрочная ² тоже дают True. Если системе разрешены только ASCII-цифры, это должно быть отдельным требованием. Подмена одного правила другим без явного решения меняет контракт.

У isupper() и islower() похожая семантика. Они учитывают регистр букв разных алфавитов, а пробелы, знаки пунктуации и цифры сами по себе не считают ни верхним, ни нижним регистром.

any() отвечает на вопрос «нашёлся хотя бы один»

any() принимает последовательность логических значений и возвращает True, как только встречает первое истинное. Генераторное выражение позволяет проверить символы без промежуточного списка:

text = "Course 7"
has_space = any(char.isspace() for char in text)
print(has_space)
True

Тот же шаблон подходит для любого строкового предиката: меняется проверка одного char, а обход строки остаётся прежним. Если синтаксис выражения внутри any() пока непривычен, сначала разберите списковые включения и генераторные выражения.

Пустой ввод заслуживает отдельного теста. Для пустого генератора any() возвращает False, потому что в нём нет ни одного истинного элемента. Это естественно для вопросов «есть ли хотя бы одна цифра» и «есть ли хотя бы одна заглавная буква».

Все нарушения собирают независимые проверки

Ранний return после первого нарушения уместен, когда функция отвечает только True или False. Для списка подсказок он мешает: пользователь исправит одну ошибку, отправит форму и лишь тогда увидит следующую.

Рабочая последовательность выглядит так:

  1. Создать пустой список проблем.
  2. Выполнить правила независимо друг от друга.
  3. Добавлять код каждого нарушенного правила в оговорённом порядке.
  4. Вернуть список после всех проверок.

Это описание намеренно не содержит готовую реализацию задачи. Оно фиксирует структуру, а условия и коды остаются частью практики.

Порядок кодов — часть API. Даже если фронтенд сейчас умеет переставлять сообщения, функция должна соблюдать контракт сама. Иначе одинаковый пароль начнёт выдавать подсказки в разной последовательности после безобидного рефакторинга.

Набор случаев, который ловит типовые ошибки

Одного «хорошего» пароля недостаточно. Минимальная таблица проверок покрывает отношения между правилами:

СлучайЧто он проверяет
пустая строкасразу несколько нарушений и отсутствие особого падения
строка на один символ короче границыстрогий знак сравнения длины
строка ровно на границеотсутствие ошибки «на единицу»
только строчные буквынезависимые проверки цифры и верхнего регистра
одна цифра в начале или концеобход всей строки, а не одной позиции
одна заглавная и одна строчная букваоба регистра распознаются отдельно
несколько нарушений сразуфункция возвращает полный список в нужном порядке
не-ASCII цифра или буквавыбранная Unicode-политика работает осознанно

Функция должна возвращать данные, а не печатать сообщения. print() полезен при отладке, но его вывод вызывающий код не сможет надёжно сопоставить с полями формы. Список коротких кодов отделяет проверку от русского текста интерфейса.

Учебный валидатор не заменяет политику продукта

В реальном сервисе требования к паролю задаёт не случайный набор регулярных выражений, а единая политика регистрации и смены пароля. Клиентская проверка помогает показать подсказку, но сервер обязан повторить проверку: запрос можно отправить без браузерной формы.

Также не стоит незаметно обрезать пробелы или менять регистр. Для логина нормализация может быть частью контракта, а для пароля такое преобразование меняет секрет пользователя. Учебная функция решает более узкую задачу: применяет явно заданные правила к полученной строке.

Практика

В задаче «Валидация пароля на Python» нужно собрать все нарушения и сохранить порядок кодов. Она входит в путь «Python: валидация данных», где тот же подход применяется к другим форматам пользовательского ввода.

Источники