Метка: print

Quine на Python

Программисты тоже умеют развлекаться, так что давайте сегодня развлечемся и напишем quine (квайн). Квайн – это такая программа, которая выводит на экран свой же код, ни больше, ни меньше. Сразу договоримся, что пустая программа на Python, которая ничего не выводит, не считается квайном; это не интересно.

В Python у нас есть чудо-переменная, которая хранит путь к текущему интерпретируемому файлу, поэтому можно сделать так:

print(open(__file__).read())

Эта программа открывает свой же файл, читает и печатает его целиком. Но это жульничество, потому что в квайнах не принято читать файлы. Хорошо, а что если назвать файл print(__file__), записать в него print(__file__) и выполнить python "print(__file__)". Будет работать, но можешь вот без этих трюков, чисто кодом? Да без проблем!

Нам нужно что-то печатать, значит берем print:

>>> print('?')
?

Программа начинается с print…, значит и печатать будем тоже самое:

>>> print('print()')
print()

Не получается, потому что у нас тут уже два print да кавычки, а печатается только один. Так можно плодить print до бесконечности, но все равно не будет хватать одного в выводе. Будем решать поэтапно. Давайте заведем переменную s с кодом нашей программы.

>>> s='print()';print(s)
print()

Но код теперь начинается с s=, исправим:

>>> s='s=?;print(s)';print(s)
s=?;print(s)

Смотрите, уже похоже, осталось только на место знака вопроса воткнуть содержимое строки s из оригинального кода. Это самый важный момент. Используем format, а точнее s.format(s), который в определенном месте строки s вставит саму же строку s, таким образом, мы «разрываем рекурсию»:

>>> s='s={};print(s)';print(s.format(s))
s=s={};print(s);print(s)

Отлично! Но тут два недостатка: во-первых, не забыть добавить s.format(s) в саму строку s:

>>> s='s={};print(s.format(s))';print(s.format(s))
s=s={};print(s.format(s));print(s.format(s))

Во-вторых, нужно вернуть на место кавычки. Не зря я недавно рассказывал о флагах преобразования строк. Используем флаг {!r} в формате, чтобы вывести repr(s), который для строк содержит одинарные кавычки:

>>> s='s={!r};print(s.format(s))';print(s.format(s))
s='s={!r};print(s.format(s))';print(s.format(s))

Ура! Квайн готов и работает!

Вы можете сделать квайн короче, используя другой стиль форматирования строк через процент: {!r} заменяется на %r, s.format(s) на s%s, плюс экранируется процент внутри самой строки s%%s (%% понимается как сам знак процента, а не как место для подстановки):

>>> s='s=%r;print(s%%s)';print(s%s)
s='s=%r;print(s%%s)';print(s%s)

🐉 Специально для канала @pyway. Подписывайтесь на мой канал в Телеграм @pyway 👈 

Счастливой отладки

Человек чинит наклоненный на 45 градусов автомобиль

Python не запрещает создавать переменные и функции с именами, идентичными встроенным. Шутки ради переопределим print:

import sys

# счастилвой отладки!
def print(*values, sep=' ', end='\n', file=sys.stdout, flush=False):
    # шутка
    def joke(value):
        if type(value) is str:
            value = value[::-1]
        elif type(value) is int:
            value += 1
        return value

    # отсюда достанем исходную версию print
    import builtins
    return builtins.print(*map(joke, reversed(values)),
                          sep=sep, end=end, file=file, flush=flush)


print('Hello, world!', '2 x 2 =', 4)  # 5 = 2 x 2 !dlrow ,olleH

Мораль такова. Во-первых, нужно быть внимательным, когда даешь имена своим переменным и функциям, чтобы случайно не перекрыть встроенные имена, что может нарушить работу программы. Хорошая IDE вас, конечно, предупредит о перекрытии имен. Во-вторых, это иногда применимо для отладки или тестирования. Но помните, что программист, читающий ваш код, ожидает от встроенных функций их обычного нормального поведения, а не того, которое вы придумали. Лучше создать обертку с явно другим именем.

🤩 Специально для канала @pyway. Подписывайтесь на мой канал в Телеграм @pyway!👈

Все о функции print()

Старый печатный пресс

print – одна из первый функций, с которой знакомятся новички, изучающие Python.

>>> print("Hello world!")
Hello world!

Однако, print умеет больше, чем просто печатать через пробел. Взглянем на сигнатуру:

print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)

Именованные параметры управляют поведением функции.

Во-первых, обратим внимание на параметр sep – это строка-разделитель, она будет вставлена между каждым из неименованных параметров переданным в print (по умолчанию – одиночный пробел).

>>> print(1, 2, 3, 4, sep=" and ")
1 and 2 and 3 and 4

Если передать sep=’\n’, то каждый параметр будет выведен с новой строки.

Во-вторых, параметр end – будет выведен после печати последнего аргумента. По умолчанию, перевод строки. Например, иногда требуется печатать в одну строку: тогда передим end=»:

>>> print("Same", end=''); print("Line")
SameLine

Параметр file указывает файл или поток, в который будет выводится информация, по умолчанию, это стандартный вывод sys.stdout. Можно печатать в файл:

>>> f = open('1.txt', 'w')
>>> print("hello", file=f)
>>> f.close()

Параметр flush=True заставляет систему немедленно сбросить содержимое буфера в поток вывода. Изредка данные застревают в буфере, и этим мы их проталкиваем. Например, при end=», «1» появится только через 5 секунд сразу с «2».

>>> print('1', end=''); time.sleep(5); print('2')

Исправим это:

>>> print('1', end='', flush=True); time.sleep(5); print('2')

Наконец, не забудем, что бывает удобно печатать коллекции, передав их в print со звездочкой.

>>> arr = ["Apple", "pear", "orange"]
>>> print(*arr, sep=", ")
Apple, pear, orange