Problem at Define Class Override (__not__)

Viewed 60

Context

As an exercise, I am creating a Variable class with the intention of representing a logical variable. It is declared as

class Variable(object):
    """ Class for emulate logical variables. """

    def __init__(self, valor, /, name='std var'):

        self.name = name
        if isinstance(valor, bool):
            self.valor = valor
        else:
            raise Exception("Class Error: Constructor must receive a bool as first arg. ")

and within this class I override some standar operators and create the essential logical functions; such as and, or, not

    def truth(self):
        """ Overload de operacion de verdad. """
        return self.valor

    def __eq__(self, other):
        """ Overload del operador =. """
        return True if self.valor == other else False

    def __not__(self):
        """ Overload del operador (not). """
        return True if self.valor else False

    def __and__(self, other):
        """ Overload del operador & (and). """
        return True if (self.valor and other) else False

    def __or__(self, other):
        """ Overload del operador | (or).  """
        return True if (self.valor or other) else False

    def show(self):
        return "{} => {}".format(self.name, self.valor)

Problem

Finally I created a test that raises an interesting error that I can't figure it out. This is the test code

def test():
    """ Testing proves. """

    q = Variable(True, 'q')
    p = Variable(False, 'p')
    print("\nDadas {} y {} se da que".format(q.show(), p.show()))

    # Checking __eq__
    assert (q == q) == True
    assert (q == p) == False
    
    # Checking __and__
    assert (q and q) == True
    assert (q and p) == False
    assert (p and p) == False
    # checking __or__
    assert (q  or p) == True
    assert (q  or q) == True
    assert (p  or p) == False
    # checking __not__
    assert (not q) == False
    assert (not p) == True, f'{p.show()=}'

and it run smoothly until it raises the next error

assert (not p) == True, f'{p.show()=}'
AssertionError: p.show()='p => False'

I know that the error raises cause the sentence (not p) == True is false. The question is, Why?

What I have thought and tried

First I thought that the truth override it wasn't working. So i change al the p entries for p.valor and do

>>> from Module import Variable
>>> 
>>> p = Variable(False)
>>> if p.valor:
>>>     print("Not works")
>>> else:
>>>     print("Or yes")
Or yes

and it works. Then it occurred to me that the problem might be with __not__. So I rewrote it several times without success. So i tried this

>>> p = Variable(True)
>>> # check if its set correctly
>>> print("Y" if p.valor else "N")
Y
>>> # so p.valor its True. Check __not__
>>> not p
False
>>> # here it seems that `__not__` does work, but
>>> p = L.Variable(False)
>>> p.valor
False
>>> print("Y" if p.valor  else "N")
N
>>> not p
False

it looks like the function only works when p.valor = True ...

(Edit)

I ... was lost, but not any more.

After DeepSpace's answer, I rewrote the overload functions. So that they were

    def __bool__(self):
        return self.valor

    def __eq__(self, other):
        return True if self.valor == other else False

    def __not__(self):
        return not(self.valor) 


    def __and__(self, other):
        return True if (self and other) else False

    def __or__(self, other):
        return True if (self or other) else False

And with this, successfully pass all the tests

1 Answers

__not__ is not a magic method, it is not part of the data model and it will not be called by anything automagically.

In other words, not p does not call p.__not__. Instead, it just negates what p.__bool__ returns.

class Foo:
    def __bool__(self):
        print('In Foo.__bool__')
        return True

print(not Foo())

outputs

In Foo.__bool__
False
Related