0

I am not a programming genius, but just in the beginning of this year, when being taught propositional logic my teacher told me (and it was quite obvious) that if P is True, not(P) or ~P was False, and the opposite if P was False.

Reading the Python docs about creating custom objects, I found that they claim that a==b being True does not imply that a!=b is False. This confused my mind as I thought that != was the negation of == and therefore, whenever evaluating with == returned a boolean result, the expression != would always evaluate to the opposite... And as far as I know, not(True) evaluates to False and not(False) evaluates to True. Can someone please help me understand how this happens? Perhaps with an example?

I read about this right here

quoting:

The truth of x==y does not imply that x!=y is false.

RGS
  • 964
  • 2
  • 10
  • 27

2 Answers2

3

It's because they are operators which can be custom implemented separately, and the operators themselves (at a high level) don't dictate that if x==y is true then x!=y is false (one could implement them such that that relationship does not follow).

The key is the statement in the doc that follows that:

Accordingly, when defining __eq__(), one should also define __ne__() so that the operators will behave as expected

When both are implemented, then there is an explicit relationship between the operators.

Veedrac
  • 58,273
  • 15
  • 112
  • 169
khampson
  • 14,700
  • 4
  • 41
  • 43
  • So does this mean that that behaviour is not self exclusive just when we are talking about custom objects? – RGS May 24 '14 at 23:06
  • No. While customization is essentially the reason there are no implied relationships, since there are no implied relationships, one should always keep the documented behavior in mind. (Behind the scenes, both `__eq__()` and `__ne__()` need to be defined to get the expected behavior. – khampson May 24 '14 at 23:11
  • Ok. so would it be "correct" to have `__ne__()` defined as `not(self.__eq__())`? – RGS May 24 '14 at 23:12
  • Sure. The key is that if you define it that way, you're explicitly making the relationship; it's just not made for you implicitly. – khampson May 24 '14 at 23:13
  • 2
    FYI if you want python to fill in the "implied relationships", use [`functools.total_ordering`](https://docs.python.org/2/library/functools.html#functools.total_ordering) – roippi May 24 '14 at 23:18
0

Largely this is just because we can do silly stuff:

class MessedUpShizzle:
    def __eq__(self, other):
        return True

    def __ne__(self, other):
        return True

MessedUpShizzle() == MessedUpShizzle()
#>>> True

MessedUpShizzle() != MessedUpShizzle()
#>>> True

If you're wondering what this if for, I'd imagine it's largely for symmetry (and thus a pretty implementation). Consider that x < y and x >= y are not inverses:

{1} < {2}
#>>> False

{1} >= {2}
#>>> False

so we need both __ge__ and __le__ separately defined.

Veedrac
  • 58,273
  • 15
  • 112
  • 169