Проверьте, равны ли две функции Python
мне интересно, как я могу проверить, совпадают ли две функции. Примером может служить (lambda x: x) == (lambda y: y)
оценивая значение true. Насколько я знаю, Python проверит, занимают ли функции одно и то же место в памяти, но не имеют ли они одну и ту же операцию. Я знаю, что это кажется непрактичным иметь такую функциональность.
другим решением будет какой-то метод, который я могу запустить на функции, чтобы увидеть, что она содержит или как она работает. Такая (lambda x: x).what()
это вернет, как метод работает, может быть, в словаре или что-то в этом роде.
Я хотел бы получить ответ, но я сомневаюсь, что это возможно.
2 ответов
если вы действительно хотите знать, всегда ли две функции делают одно и то же для всех входов, вам придется запускать их на всех входах (что займет бесконечное время), а также перехватывать все возможные побочные эффекты (что фактически невозможно).
вы могли бы, конечно, придумать некоторые эвристики, бросая на них набор различных значений, которые для вашей области приложения, скорее всего, будут генерировать разные выходы, если функции разные. Но есть очевидно, что это не решение общего назначения-иначе все модульные тесты будут генерироваться автоматически, экономя нам всем много работы, верно?
и наоборот, вы можете просто узнать, имеют ли две функции одну и ту же реализацию. Для этого, ответил Мартин Питерс является очевидной отправной точкой, и, возможно, даже конечную точку (в зависимости от того, вы заботитесь о закрытие, глобальные переменные и т. д.).
но то, что вы просили это что-то отличное от любого из них; вы, по-видимому, хотите просмотреть код вручную, чтобы увидеть "как это работает":
другим решением будет какой-то метод, который я могу запустить на функции, чтобы увидеть, что он содержит или как он работает. Так что своего рода (лямбда x: x).what (), который вернет, как работает метод, возможно, в словаре или что-то еще.
эта функция уже существует: dis.dis
. Когда вы запускаете его на функции, он говорит вам, как эта функция работает. Не в словаре (словаре чего?) но в последовательности строк байт-кода для интерпретатора Python (который является относительно простой машиной стека с некоторыми материалами более высокого уровня, добавленными сверху, в основном описанными прямо там в dis
docs).
или, еще проще, вы можете получить источник inspect.getsource
.
вот как они выглядят с вашими примерами:
>>> f1 = lambda x: x
>>> f2 = lambda y: y
>>> def f3(z):
... return z
>>> dis.dis(f1)
1 0 LOAD_FAST 0 (x)
3 RETURN_VALUE
>>> dis.dis(f2)
1 0 LOAD_FAST 0 (y)
3 RETURN_VALUE
>>> dis.dis(f3)
1 0 LOAD_FAST 0 (z)
3 RETURN_VALUE
>>> inspect.getsource(f1)
'f1 = lambda x: x\n'
>>> inspect.getsource(f2)
'f2 = lambda y: y\n'
>>> inspect.getsource(f3)
'def f3(z):\n return z\n'
в первом случае, вам нужно знаю достаточно о dis
чтобы понять, что (x)
, etc., не являются частью байт-кода, а скорее частью списка локальных имен функции. (Это объясняется в inspect
документы на dis
документы.) Во-вторых, вам нужно знать достаточно о Python, чтобы понять, что def
и lambda
определяют ту же самую функцию. Так что, в любом случае, нет никакого способа автоматизация это (или, на самом деле, что-то гораздо большее, чем ответ Мартийна).
единственное, что вы можете проверить, это равенство объектов кода:
>>> x = lambda x: x
>>> y = lambda y: y
>>> x.__code__.co_code
'|\x00\x00S'
>>> x.__code__.co_code == y.__code__.co_code
True
здесь байт-код для обеих функций одинаков. Возможно, вам нужно будет проверить больше аспектов объектов кода (константы и замыкания приходят на ум), но равный байт-код должен равняться тому же пути выполнения.
конечно, есть способы создания функций, которые возвращают одно и то же значение для одного и того же ввода, но с другим байт-кодом; всегда есть больше способов снять кожу с рыбы.