Рубрики
Без рубрики

Не пробуйте это на работе: Исключающий Fizz Buzz

Итак, я догонял некоторые из переговоров с Pycon 2020. Во -первых, я посмотрел Стивен Лотт – Тип подсказки … Tagged с Python, Dattaw.

Не пробуйте это на работе (серия 2 частей)

Итак, я догонял некоторые из переговоров с Pycon 2020. Сначала я смотрел Стивен Лотт – Тип подсказки: вкладывая больше гудений в свой Fizz а затем Элизавета Шашкова – скрытая сила времени выполнения Python Анкет Я думаю, что оба разговора были действительно интересными, однако, вместе они вдохновили меня на написание этой мерзости в реализации Fizz Buzz. Если вы не слышали о Fizz Buzz, Смотрите эту страницу Википедии Анкет

Итак, из Elizavetas Talk я немного узнал о том, как рамы стеков Python легко доступны во время выполнения. Самое главное для этого поста, когда вы захватываете исключение, используя кроме -Keyword Вы можете получить текущий кадр стека из Traceback в исключении.

try:
    raise ValueError()
except ValueError as e:
    tb = e.__traceback__
    current_stack_frame = tb.tb_frame

После немного экспериментов я также обнаружил, что вы можете использовать tb.tb_next , чтобы получить следующий объект Traceback в цепочке. Итак, если вы итерация до тех пор, пока не появится tb_next, то вы достигли нижней части трассировки. Вот где была вызвана ошибка.

Реализация

Теперь давайте перейдем к фактической реализации. Во -первых, мы определим три функции: Fizz, Buzz и Fizzbuzz:

def fizzbuzz(val):
    if val % 3 == 0 and val % 5 == 0: 
        raise ValueError()
    fizz(val)

def fizz(val):
    if val % 3 == 0: 
        raise ValueError()
    buzz(val)

def buzz(val):
    if val % 5 == 0: 
        raise ValueError()

Fizzbuzz это единственная функция, которую мы позвоним из другой части кода. Поэтому мы можем думать об этом как о нашей входной точке в этот стек вызовов. В Fizzbuzz мы делаем нашу первую проверку, чтобы увидеть, делится ли значение на 5 и 3, и в этом случае мы должны напечатать Fizzbuzz. Мы доберемся до того, как мы немного распечатываем значения. Однако, если значение не выполнило состояние, которое мы называем Fizz. Здесь снова проверяется кондиционирование шипа, и если условие не удается, оно называет Buzz, который проверяет кондиционер.

Теперь посмотрим, как мы пишем это на консоли:

def exception_driven_fizzbuzz(val):
    try:
        fizzbuzz(val)
        print(val)
    except ValueError as e:
        tb = e.__traceback__
        while tb.tb_next:
            tb = tb.tb_next
        print(tb.tb_frame.f_code.co_name)

Учитывая некоторую ценность, мы называем Fizzbuzz. Это запускает стек вызовов, на которые мы только что посмотрели. Идея состоит в том, что функция, которая поднимает исключение, должна быть написано свое имя на консоли. Это то, что мы делаем в исключении блока этой функции. Если ни одна из функций в стеке вызовов не вызвала ошибку, функция печати после запуска вызова Fizzbuzz, написание только номера на консоли. Поскольку не было никакой ошибки, кроме блока, кроме блока не оценивается. Тем не менее, если один из функций выдвигает ошибку, мы будем повторять, пока не достигнем последнего следа. Этот трасей соответствует функции, которая подняла ошибку. Поэтому мы извлекаем кадр стека из этого Traceback и доступ к нему-объекту ( f_code ), который содержит имя, f_name . f_name это имя функции или модуля объекта кода. В этом случае это будет либо: Fizz; Buzz или Fizzbuzz, в зависимости от того, какая функция подняла исключение.

Давайте возьмем пример, чтобы увидеть, как это оценивается. Мы называем функцию с val = 3 . Это не запускает ошибку в Fizzbuzz, но это запускает один в Fizz. Программа входит в за исключением блока, не оценивая печать в блоке Try. Первое значение TB это трассировка в этой функции exception_driven_fizzbuzz Анкет Мы набираем один круг в цикле, туберкулез теперь соответствует Fizzbuzz . Затем мы наступаем последний круг в цикле, а туберкулез теперь Fizz . Из туберкулеза мы затем извлекаем имя Fizz и напишите это на консоли. Если мы делаем то же самое для val = 2 , это не вызовет ошибки в нашем стеке вызовов. Поэтому будет выполнено только блок пробуки, но на этот раз он достигает функции печати.

Теперь нам просто нужно пощечить петлю вокруг этого, и наш Fizzbuzz сделан:

for val in range(1, 16):
    exception_driven_fizzbuzz(val)

выход:

1
2
fizz
4
buzz
fizz
7
8
fizz
buzz
11
fizz
13
14
fizzbuzz

Слова предупреждения

Я думаю, что это интересный способ бросить вызов себе и узнать что -то новое о языке. Тем не менее, я бы не стал делать это на своем следующем собеседовании, если бы я был вами.

Не пробуйте это на работе (серия 2 частей)

Оригинал: “https://dev.to/fronkan/don-t-try-a-this-at-work-exception-driven-fizz-buzz-4j8d”