Random Notes

Случайные заметки по ходу изучения Python'a путем решения задач с codeforces.com

08.07.2024

Input

Когда в коде вызывается функция input(), программа останавливается и ждет пользовательского ввода. Это встроенная функция
Функция input() конвертирует ввод в строку по умолчанию (python2 задает тип данных автоматически и не требует явно задавать тип (если в ответ на input() введешь число, то получится int, а если строку, то str))

Еще в Python2 была функция raw_input(), она как раз работает как input() в Python3

Эта функция возвращает строку

>>> input("-> ")
-> test
'test'

Как видно единственно возможный опциональный параметр (prompt) выводится перед приглашением к вводу без переноса строки

>>> input("multiline\nprompt: ")
multiline
prompt: string
'string'

Чтобы твоя программа с использованием функции input() была эффективной:

Exceptions

В Python все исключения это экземпляры класса который отнаследован от класса BaseException
Классы могут наследоваться друг от друга. Так ZeroDivisionError происходит от ArithmeticError, который происходит от Exception, который происходит от BaseException

Два не связанных общим родителем класса не являются эквивалентными, даже если у них одинаковое имя
То есть если мы укажем в except имя родительского класса, например LookupError, то нам не важно произошел у нас IndexError или KeyError

Ниже код демонстрирующий, что под except B подпадает и сам B, и его сын, и его внук

>>> class B(Exception):
...     pass
...
>>> class C(B):
...     pass
...
>>> class D(C):
...     pass
...
>>> for cls in [B, C, D]:
...     try:
...         raise cls()
...     except B:
...         print("B: " + str(cls))
...
B: <class '__main__.B'>
B: <class '__main__.C'>
B: <class '__main__.D'>

Встроенные классы исключений могут быть родительскими для классов определенных программистом. Для описания своих классов исключений рекомендуется наследоваться от класса Exception, а не от BaseException

BaseException - это базовый класс для всех встроенных исключений
Exception - это базовый класс для всех нефатальных исключений и он наследуется от BaseException (именно от Exception нужно наследовать свои кастомные исключения)

Пример: исключение KeyboardInterrupt вызывается когда пользователь завершает нашу программу с помощью Control-C, так как это фатальное исключение, то оно наследуется от BaseException, а не от Exception

Могут быть обработаны все перечисленные исключения (а не только нефатальные)
Пример подтверждающий это:

>>> import time
>>> try:
...   time.sleep(60)
... except KeyboardInterrupt:
...   time.ctime()
...   time.sleep(5)
...   time.ctime()
...   print("KeyboardInterrupt: CTRL-C was pressed")
...
^C'Tue Jul  9 02:13:25 2024'
'Tue Jul  9 02:13:30 2024'
KeyboardInterrupt: CTRL-C was pressed

Иерархия наследования классов исключений:

BaseException
 ├── BaseExceptionGroup
 ├── GeneratorExit
 ├── KeyboardInterrupt
 ├── SystemExit
 └── Exception
      ├── ArithmeticError
      │    ├── FloatingPointError
      │    ├── OverflowError
      │    └── ZeroDivisionError
      ├── AssertionError
      ├── AttributeError
      ├── BufferError
      ├── EOFError
      ├── ExceptionGroup [BaseExceptionGroup]
      ├── ImportError
      │    └── ModuleNotFoundError
      ├── LookupError
      │    ├── IndexError
      │    └── KeyError
      ├── MemoryError
      ├── NameError
      │    └── UnboundLocalError
      ├── OSError
      │    ├── BlockingIOError
      │    ├── ChildProcessError
      │    ├── ConnectionError
      │    │    ├── BrokenPipeError
      │    │    ├── ConnectionAbortedError
      │    │    ├── ConnectionRefusedError
      │    │    └── ConnectionResetError
      │    ├── FileExistsError
      │    ├── FileNotFoundError
      │    ├── InterruptedError
      │    ├── IsADirectoryError
      │    ├── NotADirectoryError
      │    ├── PermissionError
      │    ├── ProcessLookupError
      │    └── TimeoutError
      ├── ReferenceError
      ├── RuntimeError
      │    ├── NotImplementedError
      │    └── RecursionError
      ├── StopAsyncIteration
      ├── StopIteration
      ├── SyntaxError
      │    └── IndentationError
      │         └── TabError
      ├── SystemError
      ├── TypeError
      ├── ValueError
      │    └── UnicodeError
      │         ├── UnicodeDecodeError
      │         ├── UnicodeEncodeError
      │         └── UnicodeTranslateError
      └── Warning
           ├── BytesWarning
           ├── DeprecationWarning
           ├── EncodingWarning
           ├── FutureWarning
           ├── ImportWarning
           ├── PendingDeprecationWarning
           ├── ResourceWarning
           ├── RuntimeWarning
           ├── SyntaxWarning
           ├── UnicodeWarning
           └── UserWarning

Try Except

В Python есть два вида ошибок:

Имена встроенных исключений это встроенные идентификаторы, а не зарезервированные ключевые слова (значит можно и переопределить)

Конструкция try-except:

Внутри except задается имя класса исключения, будут обработаны также все производные от указанного класса (но не наоборот). То есть когда мы указываем BaseException, то под это условие подпадают вообще все исключения, а если указываем ArithmeticError, то будут обработаны только FloatingPointError, OverflowError и ZeroDivisionError

Будут обработаны не только исключения произошедшие непосредственно внутри блока try, но и исключения произошедшие внутри функций, вызванных внутри try


Если произойдет исключение внутри секции except, то будет получена цепочка исключений

>>> try:
...   1 / 0
... except ZeroDivisionError() as err: # из-за скобок около имени класса произойдет исключение
                                       # потому что скобками мы вызываем конструктор и получаем экземпляр класса
                                       # а без скобок передаем идентификатор класса
...   print("Handling run-time error:", err)
...
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
ZeroDivisionError: division by zero

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 3, in <module>
TypeError: catching classes that do not inherit from BaseException is not allowed

Raise

Ключевое слово raise позволяет искуственно стриггерить указанное исключение

>>> raise KeyboardInterrupt
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyboardInterrupt

>>> raise BrokenPipeError
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
BrokenPipeError

>>> raise BaseException
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
BaseException

Будет вызван конструктор указанного класса (туда можно передать аргументы)

Форма raise ValueError это сахар для полной записи raise ValueError()

24.07.24

if

Может быть ноль и более частей elif, часть else опциональна
Ключевое слово elif было введено воизбежание избыточной индентации
Вместо:

if aeou:
    aeu
else:
    if aeu:
        aoeu
    else:
        aoeu

Мы можем писать:

elif aoeu:
  aoeu
elif aeouaeu:
  aoeua

if...elif...elif... - это аналог конструкции switch...case из других языков
Однако есть в python и прямой аналог - match...case

break, continue and else

Оператор break прерывает выполнение for или while

for и while могут иметь секцию else
При for секция else будет выполнена после финальной итерации
При while секция else будет выполнена когда условие станет истинным
Если цикл прерван через break, то else выполнен не будет

for n in range(2, 10):
    for x in range(2, n):
        if n % x == 0:
            print(n, 'equals', x, '*', n//x)
            break
    else:
        # loop fell through without finding a factor
        print(n, 'is a prime number')

Оператор continue заставляет цикл перейти на следующую итерацию

pass

Оператор pass не делает ничего
Он нужен когда синтаксически должны быть описаны какие-то действия, но логически они нам не нужны
Тогда можно воткнуть pass как заглушку