Feature Request: `operator.not_in`

Matthew Gilson m.gilson1 at gmail.com
Fri Apr 19 15:23:19 EDT 2013


On 4/19/13 2:27 PM, Terry Jan Reedy wrote:
> On 4/19/2013 10:27 AM, Matthew Gilson wrote:
> ) It seems to me that the operator module should have a `not_in` or
>> `not_contains` function.  It seems asymmetric that there exists a
>> `is_not` function which implements `x is not y` but there isn't a
>> function to represent `x not in y`.
>
> There is also no operator.in.

True.  I'm not arguing that there should be ...
> There is operator.contains and operator.__contains__.

Thankfully :-)
>
> There is no operator.not_contains because there is no __not_contains__ 
> special method. (Your point two, which I disagree with.)
>
But there's also no special method `__is_not__`, but there's a 
corresponding `is_not` in the operator module so I don't really see that 
argument.  It's a matter of functionality that I'm thinking about in the 
first part.

      itertools.starmap(operator.not_in,x,y)

vs.

     itertools.starmap(lambda a,b: a not in b,x,y)

Pretty much every other operator in python (that I can think of) has an 
analogous function in the operator module.

>> 2) I suspect this one might be a little more controversial, but it seems
>> to me that there should be a separate magic method bound to the `not in`
>> operator.
>
> The reference manual disagrees.
> "The operator not in is defined to have the inverse true value of in."

I would still leave that as the default behavior.  It's by far the most 
useful and commonly expected.  And I suppose if you *can't* have default 
behavior like that because that is a special case in itself, then that 
makes this second part of the request dead in the water at the outset 
(and I can live with that explanation).
>
>>  Currently, when inspecting the bytecode, it appears to me
>> that `not x in y` is translated to `x not in y` (this supports item 1
>> slightly).  However, I don't believe this should be the case. In
>> python, `x < y` does not imply `not x >= y` because a custom object can
>> do whatever it wants with `__ge__` and `__lt__` -- They don't have to
>> fit the normal mathematical definitions.
>
> The reason for this is that the rich comparisons do not have to return 
> boolean values, and do not for numarray arrays which, I believe, 
> implement the operators itemwise.
>
Yes, you're correct about numpy arrays behaving that way.  It can be 
very useful for indexing them.

It would also be fine for a special method `__not_contains__` to be 
expected to return a boolean value as well.  It could still be very 
useful.  Consider a finite square well from quantum mechanics.  I could 
define `in` for my particle in the square well to return `True` if there 
is a 70% chance that it is located in the well (It's a wave-function, so 
it doesn't have a well defined position -- the particle could be anyway, 
but 7 out of 10 measurements will tell me it's in the well).  It might 
be nice if I could define `not in` to be  `True` if there is only a 30% 
chance that it is in the well.  Of course, this leaves us with a 
no-man's land around the 50% mark.  Is it in the well or not?  There's 
no telling.  I'm sure you could argue that this sort of thing *could* be 
done with rich comparisons, but I would consider that a deflection from 
the point at hand.  It seems it should be up to the user to design the 
API most suited for their task.  Or what about a `Fraternity` class.  
Are the new pledges in the fraternity or not?  Maybe they should be 
considered neither in, nor out until pledge season is over.

> > I don't see any reason why containment should behave differently.
>
> 'Design by analogy' is tricky because analogies often leave out 
> important details. __contains__ *is* expected to return true/false.
>
> " object.__contains__(self, item)
>     Called to implement membership test operators. Should return true 
> if item is in self, false otherwise"
>
> -- 
> Terry Jan Reedy
>
>




More information about the Python-list mailing list