Думайте об этом как об удивительном языке программирования внутри языка
Недавно я обнаружил кое-что очень интересное, работая над своей следующей книгой - сборником коротких программ на Python для портативного калькулятора Casio fx-9750GIII. Я поделюсь полученной программой здесь (она отлично работает в любой версии Python) и объясню, как замечательная функция eval () спасла меня.
Язык внутри языка
Программа, над которой я работал, позволяет студентам находить корни любой функции от x или точки, в которых функция пересекает ось x, когда она отображается на графике. Вместо того, чтобы заставлять пользователя редактировать программу для определения некоторой функции x, я задавался вопросом, можно ли найти способ, позволяющий пользователю вводить функцию динамически во время выполнения, точно так же, как при вводе значения любой другой переменной с использованием ввода Python ( ) функция. Функция eval () позволяет нам делать именно это и многое другое!
Как работает eval ()
Строка, переданная в eval (), обрабатывается Python как выражение Python. Например, внимательно посмотрите на этот короткий сценарий:
from math import * s = input("? ") print(eval(s))
Здесь пользователь может ввести во время выполнения широкий спектр вычислений, например, этот для определения площади круга с радиусом 17:
? pi * 17 ** 2 907.9202768874502
Этот простой пример намекает на то, насколько легко с помощью eval () создать крутой и мощный калькулятор Python всего в несколько строк кода или, возможно, создать совершенно новый язык сценариев с использованием Python в качестве оболочки.
Casio MicroPython
Версия MicroPython, которая работает в нескольких калькуляторах Casio, включая экономичный FX-9750GIII, на который нацелена моя новая книга, очень хорошо справляется с математическими задачами. Одно ограничение заключается в том, что есть только три библиотеки, которые можно импортировать - math, random и casioplot, но большинство встроенных функций и структур данных есть, включая функцию eval (). Версия eval () Casio для MicroPython имеет небольшое ограничение, которое отличает ее от некоторых других версий Python. Переменные, названные в строке, переданной в eval (), не обрабатываются должным образом. Я нашел простой обходной путь, который я покажу и объясню с помощью этой короткой программы, которая находит корни введенной во время выполнения функции x:
from math import * def f(g,x): g=g.replace('x','('+str(x)+')') return eval(g) def zero(g,x1,x2): lst=0 y1=f(g,x1) y2=f(g,x2) while 1: if y1*y2>0: return float("nan") x=(x1+x2)/2 y=f(g,x) if y1*y>0: x1=x y1=f(g,x1) else: x2=x y2=f(g,x2) if x1-x2!=lst: lst=x1-x2 else: return x g=input('\nf(x)? ').lower() while 1: try: x1=float(input('\nx1? ')) x2=float(input('x2? ')) x0=zero(g,x1,x2) print('root: ',x0) print('f(x)=',g) except: break
Первые несколько строк выше представляют основное действие. В функцию f () передается введенная пользователем строка с именем g, которая содержит функцию x в стандартном синтаксисе Python и значение x, которое должно быть оценено с использованием этой строки. Он возвращает значение y, вычисленное с использованием данной функции x.
Замена «x» в строке
Строка, такая как «2 * x», не может вернуть удвоенное значение x, потому что функция eval (), очевидно, не знает, как сделать правильную подстановку значения x в строку. Итак, вторая строка приведенного выше кода позволяет обойти эту проблему, используя функцию replace () строки для вставки строкового представления значения x в строку. Чтобы избежать случайных проблем с отрицательными значениями x, добавляются круглые скобки, чтобы обернуть и изолировать значение.
Корнеплоды
Функция zero () принимает функцию x в строковой форме, введенной пользователем, плюс два значения x, и выполняет двоичный поиск, чтобы найти значение x, где функция равна нулю. Пока два начальных значения x оцениваются как величины с противоположными знаками, непрерывная функция x всегда будет иметь корень где-то между этими двумя значениями.
Рабочий пример
Рассмотрим эту функцию от x:
Быстрый график этой функции показывает, что есть три корня в районе -5, -1 и +1. Этот график, взятый из моего калькулятора HP Prime, показывает один из корней при x = 0,828427124746.
Вот как программа Python, представленная выше, находит эти корни, используя IDLE на настольном компьютере Windows (она работает так же в моих калькуляторах Casio или Numworks):
Первая строка показывает, как функция вводится во время выполнения в стандартном синтаксисе Python. Затем программа зацикливается, чтобы запросить значения x для нахождения каждого корня в скобках. Обратите внимание, что значения x можно вводить в любом порядке, где второе значение может быть больше или меньше первого.
Компактный код
Эта программа была создана для моего калькулятора Casio. Вы могли заметить, что уровень отступа установлен на 2 вместо 4, и между различными математическими операциями нет пробелов. Этот стиль компактного кода экономит байты в ограниченном пространстве памяти калькулятора, о чем нам не нужно думать в мире настольных компьютеров и ноутбуков, оставаясь при этом легко читаемым - отличительной чертой всего кода Python.
Еще идеи для eval ()
Функция eval () в Python открывает дверь к очень мощным возможностям программирования. Очевидным является создание интерактивной программы-калькулятора, которая действует аналогично среде оболочки Python, но, возможно, оформлена в творческом окне tKinter или Pygame. Можно было бы создать версию языка, подобного BASIC, где обработка строк могла бы использоваться для синтаксического анализа команд в эквивалентном синтаксисе Python, а функция eval () могла бы выполнять тяжелую работу в основных вычислениях. И, конечно, было бы интересно создать калькулятор RPN, аналогичный мощным ранним калькуляторам HP, но, возможно, обновленный новыми командами для обработки строк и других типов переменных.
Осторожность!
Имейте в виду, что при некоторых обстоятельствах функция eval () может вызвать проблемы. Например, если вы импортируете модуль ОС и запускаете eval () для определенных строковых команд, можно удалить целые каталоги или вызвать другие проблемы. Будь осторожен. Но получайте удовольствие. Вы можете сделать и то, и другое!
Если вы хотите получить уведомление, когда моя следующая книга будет готова, нажмите здесь. Или, если вы хотите проверить мою аналогичную книгу о калькуляторе NumWorks, она доступна сейчас на Amazon по этой ссылке.
Спасибо за чтение!
Страсть и миссия Джона - делиться кодом Python, чтобы помочь развенчать загадки жизненных проблем и повеселиться. Джон является автором Python для NumWorks, Python для OpenSCAD и многих других книг.