2026, Jan 01 06:01
Как генерировать пароли в Python без пробелов и управляющих символов
Разбираем, почему string.printable даёт переводы строк в паролях, и показываем безопасный генератор на Python: исключаем пробел и управляющие символы [:-6].
При генерации паролей в Python из широкого набора символов легко случайно захватить управляющие символы вроде перевода строки или табуляции. В итоге строка печатается на нескольких строках, засоряет логи и её трудно читать. Если вы берёте символы из string.printable, как раз сталкиваетесь с этой проблемой.
Обзор проблемы
Простейший генератор может выглядеть так:
import random
import string
passcode = ''.join(
random.choices(string.printable, k=random.randint(8, 15))
).replace(' ', '')
Этот подход постфактум убирает пробелы, но по-прежнему пропускает символы вроде \n, \t, \r, \x0b и \x0c. Посмотрите, как ведёт себя значение с переводом строки:
raw_a = '57+%\n:cz'
shown_a = '57+%\\n:cz'
Первая строка содержит настоящий перевод строки, вторая — это тот же набор символов, только записанный так, чтобы символ перевода строки был виден как \n.
Что на самом деле происходит
Дело не в «символах экранирования» внутри пароля, а в управляющих символах, входящих в string.printable. Если посмотреть на эту константу, в ней есть цифры, буквы, знаки пунктуации, пробел, а в конце — печатные управляющие символы:
'0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ \t\n\r\x0b\x0c'
Эти замыкающие символы — пробел, за которым следуют табуляция, перевод строки, возврат каретки, вертикальная табуляция и перевод страницы. Если их разрешать, пароли неизбежно будут занимать несколько строк или содержать невидимые пробельные символы.
Важно также отличать представление строки от её значения. Обратная косая черта — это символ экранирования. В пароле обратная косая черта будет записана как 'abc\\def' в представлении, но печататься и сравниваться как abc\def. Эта тонкость заметна при выводе:
print('\'', len('\''))
print('\\', len('\\'))
Вывод покажет одинарную кавычку и один обратный слэш, и у каждого длина 1.
Решение
Проще всего выбирать символы из подмножества string.printable, исключив пробел и управляющие символы. Это как раз последние шесть элементов константы, поэтому срез на источнике полностью устраняет проблему:
import random
import string
safe_passcode = ''.join(
random.choices(string.printable[:-6], k=random.randint(8, 15))
)
Срез [:-6] удаляет ровно шесть символов в конце: пробел и пять управляющих символов. Исключив их заранее, вы гарантируете, что сгенерированный пароль не будет содержать пробелов и управляющих символов. Вдобавок вы не рискуете случайно укоротить пароль ниже минимальной длины при последующем удалении пробелов.
Если вывести отфильтрованный пул, вы увидите только видимые символы:
print(string.printable[:-6])
# 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
Почему это важно
Пароли с управляющими символами, такими как перевод строки и табуляция, неудобно отображать, копировать, хранить и визуально сравнивать. Исключив их на этапе генерации, вы получаете однострочный, предсказуемый и удобный для логов или интерфейсов результат. Заодно избегаете незаметного изменения длины из‑за удаления пробелов после выбора символов.
Дополнительные соображения
Практично ещё сильнее сузить набор: взять string.ascii_letters + string.digits и, при необходимости, несколько знаков пунктуации — например, точку и подчёркивание. Либо просто исключить обратный слэш, если он усложняет рабочий процесс.
Вывод
Создавая генератор паролей на Python, явно задавайте допустимый набор символов. Если сейчас используете string.printable, отрежьте завершающие пробел и управляющие символы через string.printable[:-6], чтобы гарантировать однострочный, чистый вывод. Понимайте разницу между представлением строки и её реальным значением, особенно в части обратных слэшей, и при необходимости сужайте пул до чётко определённого подмножества.