1

I use Python to wrap a powerful library (from another language) which manipulates expressions and relations. For that matter, I extensively use overloading of operators and it works like a charm.

Now, I would need to define a max function that would apply on my expressions to generate a new expression intuitively representing the "max of all expressions in the iterable (these expressions being not yet evaluated)."

Since the built-in function max uses iterators and some kind of order relation implemented as __leq__, etc., (which I use for generating relations from two expressions) I end up getting nonsense when I apply the built-in max on a set of expression.

More specifically,

>>> max(e1, e2, e3)
e3

although I would love to raise some kind of exception saying "Please use my specific function I am pointing here that would generate the new expression you reasonably expect"

My bottom-line is that even if I have a different function implementing max for expressions:

  • I don't want to leave this behaviour as is and let users think they are safe doing max(e1, e2, e3).
  • I want max to work as usual with regular Python objects.

The only way-out of this issue I can think of would start by tricking the key option of max to raise an exception when it hits an object of a specific type:

def newkey(p):
    if isinstance(p, Expression):
        raise SyntaxError("Use function `foo` for computing `max`")
    # fallback to regular behaviour I know nothing about yet

max(e1, e2, e3, key=newkey)

Now I cannot force users to specify the key option each time they call max. As a matter of fact, if I could, I would tell them to use a different max function anyway...

Can you see a way out of this? (or a better workaround)

5
  • 1
    Why do you get nonsense? Why not implement __leq__ correctly? Commented Nov 20, 2015 at 21:30
  • Because __leq__ returns an instance of Relation which is not yet evaluated (as expressions are not yet evaluated) and is neither True nor False. Commented Nov 20, 2015 at 21:35
  • 1
    Define __bool__ on Relation so it will be evaluated. Or __nonzero__ if using Python 2. Commented Nov 20, 2015 at 21:39
  • I think if I were a user of your library, I would expect max(e1, e2, e3) to implicitly evaluate the expressions. You could design for this behavior, then add a lazy_max function to your module to return a LazyMax object. That covers all of your bases. Commented Nov 20, 2015 at 22:06
  • Well I am sure you wouldn't because it wouldn't make sense. :) It's not just about lazy evaluation. Commented Nov 21, 2015 at 8:16

2 Answers 2

2

Since the built-in function max uses iterators and some kind of order relation implemented as __leq__, etc., (which I use for generating relations from two expressions)

The type returned by your rich comparison methods needs to implement __nonzero__, or __bool__ in Python 3, to define what happens when you try to interpret it as a boolean. There are two reasonable possibilities for what __nonzero__ should do.

If it's reasonable to actually evaluate the underlying expressions and perform the comparison, you could design your __nonzero__ method to just do that. This would make sense if you're building some sort of lazy operation library. In that case, max would just work, but it'd implicitly force evaluation of its arguments. That might not be desirable.

Alternatively, you could have __nonzero__ raise a TypeError. In that case, when max tries to decide which of two Expressions is bigger, it'll raise a TypeError.

Sign up to request clarification or add additional context in comments.

Comments

0

you could use a decorator to override max it will provide the same behavior but raise exception when needed check the following code

def dec(ff):
    def _f(*args):
        for p in args:
            if isinstance(p, Expression):
                raise SyntaxError("Use function `foo` for computing `max`")
        else:
            return ff(*args)
    return _f

max = dec(max)

Comments

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.