In the operator
module, the binary functions comparing objects take two parameters. But the contains
function has them swapped.
I use a list of operators, e.g. operator.lt
, operator.ge
.
They take 2 arguments, a
and b
.
I can say operator.lt(a, b)
and it will tell me whether a
is less than b
.
But with operator.contains
, I want to know whether b
contains a
so I have to swap the arguments.
This is a pain because I want a uniform interface, so I can have a user defined list of operations to use (I'm implementing something like Django QL).
I know I could create a helper function which swaps the arguments:
def is_contained_by(a, b):
return operator.contains(b, a)
Is there a "standard" way to do it?
Alternatively, I can implement everything backwards, except contains
. So map lt
to ge
, etc, but that gets really confusing.
CodePudding user response:
If your goal is uniformity, we can go way more general than a helper function that works specifically for contains
.
def flip(f):
return lambda y, x: f(x, y)
Now flip(operator.gt)
will behave (on any sane class) just like operator.lt
, and flip(operator.contains)
is the function you want.
CodePudding user response:
If either of them posts an answer, you should accept that, but between users @chepner and @khelwood, they gave you most of the answer.
The complement of operator.contains
would be something like operator.does_not_contain
, so that's not what you're looking for exactly. Although I think a 'reflection' isn't quite what you're after either, since that would essentially be its inverse, if it were defined.
At any rate, as @chepner points out, contains
is not backwards. It just not the same as in
, in
would be is_contained_by
as you defined it.
Consider that a in b
would not be a contains b
, but rather b contains a
, so the signature of operator.contains
makes sense. It follows the convention of the function's stated infix operation being its name. I.e. (a < b) == operator.lt(a, b)
and b contains a == operator.contains(b, a) == (a in b)
. (in a world where contains
would be an existing infix operator)
Although I wouldn't recommend it, because it may cause confusion with others reading your code and making the wrong assumptions, you could do something like:
operator.in_ = lambda a, b: b.__contains__(a)
# or
operator.in_ = lambda a, b: operator.contains(b, a)
That would give you an operator.in_
that works as you expect (and avoids the in
keyword), but at the cost of a little overhead and possible confusion. I'd recommend working with operator.contains
instead.