Problem at Define Class Override (__not__) - python

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

__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

Python- Return true if all statements are true

I have a method and I want it to return true if all 3 statements are true. In case any of them is false the method should return false.
def check_valid(self, a, b):
statement1 = self.x == 0
statement2 = self.y == a
statment3 = self.z = b
return statement1 ^ statement2 ^ statement3
I am using xor to validate if all statements have the same value but if all statements are false then the method will return true, which is not the intended behavior.
In order to fix this I am thinking in adding a true to the return statement like this:
return true ^ statement1 ^ statement2 ^ statement3
But I don't think that it is the best approach.
Is there a cleaner/better way to do this?
This way would be a better approach and much more readable:
def check_valid(self, a, b):
if not self.x == 0: return False
if not self.y == a: return False
if not self.z == b: return False
return True

Reuse logic in Python functions that involve Return

I have a long list of functions that all have the same initial part.
default_value = 123
def func_1(input):
if apply_some_check(input):
return default_value
return do_something_1(input)
def func_2(input):
if apply_some_check(input):
return default_value
return do_something_2(input)
def func_3(input):
if apply_some_check(input):
return default_value
return do_something_3(input)
......
Is there any way to reuse the
if apply_some_check(input):
return default_value
part of the code, while keeping this list of functions (required by my code reviewer for readability)?
You can use decorators for this.
def checked(f):
def inner(inp):
if apply_some_check(inp):
return default_value
return f(inp)
return inner
# checked takes a function and returns a function, we can now use it as a function decorator
#checked
def some_func(inp):
return do_something(inp)
You could also try to use partial if it fits to your needs as follows:
from functools import partial
default_value = 123
def apply_some_check(a):
return False
def func_template(do_something, a):
if apply_some_check(a):
return default_value
return do_something(a)
def do_something_1(a):
return "test1" == a
def do_something_2(a):
return "test2" == a
def do_something_3(a):
return "test3" == a
if __name__ == '__main__':
a = "test2"
funcs = []
for i in range(1, 4):
funcs.append(partial(func_template, eval(f"do_something_{i}"), a))
for f in funcs:
print(f())
Result:
False
True
False

Manipulating Python Magic Methods

I have more of a background with data science libraries or calling methods and attributes from classes. I am experimenting with manipulating magic methods. I am having a difficult time getting bool types and returning their opposites.
I did something with str and datetime objects that worked but can't seem to to the same with __cmp__, __lt__, __eq__ or `gt'. Here is my code:
class Opposite:
def __cmp__(self, other):
if other.__class__.__name__ == 'bool':
return other
def __lt__(self, other):
if other.__class__.__name__ == 'bool':
return other
def __eq__(self, other):
if other.__class__.__name__ == 'bool':
return other
def __gt__(self, other):
if other.__class__.__name__ == 'bool':
return other
if __name__=="__main__":
""" test class Compare """
a = 1
b = 1
c = a < b
d = a > b
e = a == b
print("Results:\na\t{}\nb\t{}\nc\t{}\nd\t{}\ne\t{}\n".format(a,b,c,d,e))
print("\nType:\na-type\t{}\nb-type\t{}\nc-type\t{}\nd-type\t{}\ne-type\t{}\n"
.format(type(a),type(b),type(c),type(d),type(e)))
This prints the following:
Results:
a 1
b 1
c False
d False
e True
Type:
a-type <class 'int'>
b-type <class 'int'>
c-type <class 'bool'>
d-type <class 'bool'>
e-type <class 'bool'>
As you can see, the results are the same as not using the class at all. I added an __init__ method to print using Opposite and it only prints that if I instantiate the object with something like a = Opposite().
I would like to enter something like a > b, a < b, or a == b, and return the opposite boolean value, True, or False, as an exercise.
I tried several things such as placing the methods under the __init__ method I created, which didn't work either. I read on this and still don't quite understand how to do this with booleans, integers and floats for that matter. The way the methods are above is how I was able to turn datetime objects into strings with __add__, __radd__ and __rsub__ methods.
Thank you for your help.
EDIT
Thanks to your help, I have a better understanding and have completed my small experiment with this code:
class Opposite:
def __init__(self, x):
self._x = x
def __lt__(self, other):
return not self._x < other._x
def __eq__(self, other):
return not self._x == other._x
def __gt__(self, other):
return not self._x > other._x
def __le__(self, other):
return not self._x <= other._x
def __ge__(self, other):
return not self._x >= other._x
def tester(w, x, y, z):
try:
# Original values
a = w < x
b = w > x
c = w == x
d = w <= x
e = w >= x
# Opposite values
f = y < z
g = y > z
h = y == z
i = y <= z
j = y >= z
# Results
k = 'Fail' if a == f else 'Success'
l = 'Fail' if b == g else 'Success'
m = 'Fail' if c == h else 'Success'
n = 'Fail' if d == i else 'Success'
o = 'Fail' if e == j else 'Success'
print('\nComparing {} and {}:\t<\t>\t==\t<=\t>='.format(w, x))
print('Original Values:', end='\t')
print('{0}\t{1}\t{2}\t{3}\t{4}'.format(a, b, c, d, e))
print('Opposite Values:', end='\t')
print('{0}\t{1}\t{2}\t{3}\t{4}'.format(f, g, h, i, j))
print('Comparisons:', end='\t')
print('\t{0}\t{1}\t{2}\t{3}\t{4}'.format(k, l, m, n, o))
except(Exception) as err:
print(err)
if __name__=="__main__":
""" test class Compare """
a = 1
b = 2
c = Opposite(a)
d = Opposite(b)
tester(a, b, c, d)
This prints the following:
Comparing 1 and 2: < > == <= >=
Original Values: True False False True False
Opposite Values: False True True False True
Comparisons: Success Success Success Success Success
If you mean that you want to return the negation of the boolean resulting from the comparison you could do something like
class T:
def __init__(self, x):
self._x = x
def __lt__(self, other):
return not self._x < other._x
t1 = T(1)
t2 = T(2)
print(t1 < t2) #False
Note that in the comparison self._x < other._x you are using the __lt__ method of the int class.

My __eq__() function is not returning the right values

I have the following code to build an array ADT but my __eq__() function is not working
class Array:
def __init__(self, max_capacity):
self.array = build_array(max_capacity)
self.size = 0
self.index = 0
self.maxsize = max_capacity
def __str__(self):
string = "["
for i in range(self.size):
string += str(self.array[i])
string += ', '
string += ']'
return string
def __eq__(self, other):
if isinstance(other, self.__class__):
return self.__dict__ == other.__dict__
return False
if __name__ == "__main__":
test_array = Array(6)
test_array1 = Array(6)
print(test_array.__eq__(test_array1))
print(test_array)
print(test_array1)
Right now, test_array.__eq__(test_array1) is returning False when it should be clearly True, I'm even printing everything out to make sure. I've no idea why it's returning False, any help is appreciated.
Here's the build_array function code
import ctypes
def build_array(size):
if size <= 0:
raise ValueError("Array size should be larger than 0.")
if not isinstance(size, int):
raise ValueError("Array size should be an integer.")
array = (size * ctypes.py_object)()
array[:] = size * [None]
return array
You are asking Python to compare two ctypes arrays (all other key-value pairs are objects that do compare equal).
A ctypes array is only equal if it is referencing the same object
>>> a = build_array(6)
>>> b = build_array(6)
>>> a == b
False
>>> a == a
True
There is no support for testing if they have the same length and contain the same elements. You'll have to do so manually:
def __eq__(self, other):
if not isinstance(other, type(self)):
return False
if (self.index != other.index or self.size != other.size or
self.maxsize != other.maxsize):
return False
return all(a == b for a, b in zip(self.array, other.array))

Repeating a function: Check the return result and `not None`

So I' using a repeat function to repeat calling a function n times:
def repeat_function(sleep_time, times, expected_result, function, *args):
for i in range(times):
time_to_sleep = sleep_time/times
sleep(time_to_sleep)
result = function(*args)
if result == expected_result:
break
return result
This works as a polling mechanism where it continuously calls a function till expected_result is received.
Now I need to use the same function (modify if needed) to check if result of a function is not None as well
something like:
repeat_function(4, 4, not None, func)
the problem is obviously if result == expected_result where I can not use not None as the expected_result
modifying the repeat function to do if result == expected_result or result is expected_result does not seems that logical as well (which may have side effects).
Is there any way to check if the return of a method is
not None using == operator?
Any suggestions on how to address the problem is appreciated.
Pass a function that checks the expected result instead:
def repeat_function(sleep_time, times, is_expected_result, function, *args):
for i in range(times):
time_to_sleep = sleep_time/times
sleep(time_to_sleep)
result = function(*args)
if is_expected_result(result):
break
return result
Call it like this:
repeat_function(4, 4, lambda x: x != None, func)
repeat_function(4, 4, lambda x: x == "expected_result", func)
repeat_function(4, 4, lambda x: x == 1234, func)
Ok, here's another go at it. My solution would be to define a class within your function:
class bool_check:
def __init__(self, value):
self.value = value
def __eq__(self, value):
if self.value or self.value == value:
return True
else:
return False
Here's what a bool_check object would return when compared to another value. This by no means covers all instances but covers specifically your problem.
>>> t = bool_check(2)
>>> t == 2
True
>>> f = bool_check(None)
>>> f == True
False
>>> f = bool_check(False)
>>> f == True
False
>>> f == False
True
What you see is that when you compare bool_check(None) == True, you get False, which is what you want. When you compare bool_check(2) == True, you get True, which is also what you want.
Here's how it's used:
def repeat_function(sleep_time, times, expected_result, function, *args):
for i in range(times):
time_to_sleep = sleep_time/times
sleep(time_to_sleep)
result = function(*args)
if bool_check(result) == expected_result:
break
return result
If you pass True into expected_result, then if function(*args) returns None then the check resolves to False and does not break. If it returns something, then the __eq__ method of the bool_check class will return True.
This will work for your needs (I think) but won't cover all possibilities.
You can pass a python function or use lambda expression, below is an example using the later:
def repeat_function(sleep_time, times, eval_result, function, *args):
for i in range(times):
time_to_sleep = sleep_time/times
sleep(time_to_sleep)
result = function(*args)
if eval_result(result):
break
return result
eval_result = lambda result: result is not None
eval_result = lambda result: result == 4

Categories