4

In python you cannot directly compare functions created by lambda expressions:

>>> (lambda x: x+2) == (lambda x: x+2)
False

I made a routine to hash the disassembly.

import sys
import dis
import hashlib
import contextlib


def get_lambda_hash(l, hasher=lambda x: hashlib.sha256(x).hexdigest()):
    @contextlib.contextmanager
    def capture():
        from cStringIO import StringIO
        oldout, olderr = sys.stdout, sys.stderr
        try:
            out=[StringIO(), StringIO()]
            sys.stdout, sys.stderr = out
            yield out
        finally:
            sys.stdout, sys.stderr = oldout, olderr
            out[0] = out[0].getvalue()
            out[1] = out[1].getvalue()

    with capture() as out:
        dis.dis(l)

    return hasher(out[0])

The usage is:

>>>> get_lambda_hash(lambda x: x+2) == get_lambda_hash(lambda x: x+1)
False

>>>> get_lambda_hash(lambda x: x+2) == get_lambda_hash(lambda x: x+2)
True

Is there any more elegant solution for this problem?

10
  • 8
    If you need comparisons, perhaps a lambda isn't the tool for the job? Commented Feb 20, 2015 at 17:03
  • Should the expressions be syntactical or semantical equal? The latter can't be done at all. Commented Feb 20, 2015 at 17:10
  • @jonrsharpe consider you have a library to read long files with rows and columns into memory. You can specify columns you want to select, and also you can specify lambdas to do some trickery when selecting e.g. select sum of two columns. Now you want to do cache where key is which columns(and lambdas!) you select. Commented Feb 20, 2015 at 17:10
  • Yes, but it's not clear why that has led you to this requirement, which seems to indicate potential for broader improvements in design. This is likely an XY problem; see e.g. meta.stackexchange.com/q/66377/248731 Commented Feb 20, 2015 at 17:11
  • @CommuSoft syntactical Commented Feb 20, 2015 at 17:11

1 Answer 1

6

If you insist on performing this insane bit of insanity, compare the bytecode and constants of each.

>>> import operator
>>> coco = operator.attrgetter('co_code', 'co_consts')
>>> coco((lambda x: x+2).__code__) == coco((lambda x: x+2).__code__)
True
>>> coco((lambda x: x+2).__code__) == coco((lambda x: x+1).__code__)
False
>>> def foo(y):
...   return y + 2
... 
>>> coco((lambda x: x+2).__code__) == coco(foo.__code__)
True
Sign up to request clarification or add additional context in comments.

2 Comments

This might be not good enough - for example for def f(x): return lambda y: x+y it would consider f(1) and f(2) to be the same function.
Also not good if data used in lambda changed, like if in lambda x: some_dict[x] dictionary some_dict changed.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.