Updating object values in class - python

I have a question about how to return the update value of an object in a class and then use that in another function in the same class. Here is my old code.
class Vector:
def __init__(self, a):
self.a = a
assert type(self.a) == list
for i in self.a:
assert type(i) == int or type(i) == float
def dim(self):
return len(self.a)
def __getitem__(self, i):
assert i >= 1 and i <= self.dim()
return self.a[i-1]
def __setitem__(self, i, x):
assert i >= 1 and i <= self.dim()
self.a[i-1] = x
return self.a[i-1]
def __str__(self):
return 'Vector: ' + str(self.a)
def __add__(self, other):
assert type(other.a) == list and other.dim() == self.dim()
n = []
for j in range(self.dim()):
n.append(self.a[j]+other.a[j])
self.a = n
return self.a
so when i'm running this test case:
v1 = Vector([2, 3, 4])
v2 = Vector([1, 2, 3])
str(v1 + v2)
my output is '[3, 5, 7]' which means it is only following return self.a and not the __str__ function however i want my output to be 'Vector: [3, 5, 7]' as it should be following the __str__ function. I fixed this by returning Vector(self.a) in the __add__ function but i dont know why this works. Can anyone explain why that works, and why return self.a does not simply update the object value and run the __str__ function instead?
Note: Python uses following equivalent notations:
v[i] == v.__getitem__(i)
v[i] = x == v.__setitem__(i, x)
str(v) == v.__str__()
v + other == v.__add__(other)

Related

Vector addition and multiplication, adding error

I'm supposed to create a program that is used to multiply or and/or add vectors. I'm supposed to do this using classes and overloading the built in functions like "+" and "str". I've done most of it but my problem is when I run the cases
v1 = Vector([2, 3, 4])
v2 = Vector([1, 2, 2])
v2[3] = 3
print(str(v2) == 'Vector: [1, 2, 3]')
print(str(v1 + v2) == 'Vector: [3, 5, 7]')
print(str(v2 * 2) == 'Vector: [2, 4, 6]')
print(str(2 * (v1 + v2)) == 'Vector: [6, 10, 14]')
For the last case I receive false, I did some poking around and found that my function is storing the data from the previous cases and is using them to compute the last case.
using print(str(v1 + v2) == 'Vector: [3, 5, 7]')
print(str(v2 * 2) == 'Vector: [2, 4, 6]')
as the 2 vectors instead and getting Vector: [10, 18, 26] as an output
my code is below:
class Vector:
def __init__(self,l):
if (isinstance(l,list) == False):
raise TypeError
elif(isinstance(l,list)):
for i in l:
if (isinstance(i, int) == False and isinstance(i,int) == False):
raise TypeError
else:
self.l = l
def dim(self):
return len(self.l)
def __getitem__ (self,i):
if i > len(self.l) or i < 1:
raise IndexError
return (self.l[i-1])
def __setitem__(self, i, x):
if i > len(self.l) or i < 1:
raise IndexError
self.l[i-1] = x
def __str__(self):
print ("Vector: "+ str(self.l))
return ("Vector: "+ str(self.l))
def __add__(self, other):
if (not isinstance(other, Vector)):
raise ValueError
elif(other.dim() != self.dim()):
raise ValueError
for i in range(0,len(self.l)):
self.l[i] = self.l[i] + other[i+1]
return Vector(self.l)
def __mul__(self, other):
if (isinstance(other,float)) or (isinstance(other,int)):
for j in range (0, len(self.l)):
self.l[j] = self.l[j] * other
return Vector(self.l)
elif (isinstance(other, Vector)):
for i in range(0,len(self.l)):
self.l[b] = self.l[b] * other[i+1]
return sum(self.l)
else:
raise AssertionError
def __rmul__(self,other):
if (isinstance(other,float)) or (isinstance(other,int)):
for k in range (0, len(self.l)):
self.l[k] = self.l[k] * other
return Vector(self.l)
elif (isinstance(other, Vector)):
for i in range(0,len(self.l)):
self.l[b] = self.l[b] * other[i+1]
return sum(self.l)
else:
raise AssertionError
How can I fix this unwanted overwriting?

Assigning variable = self creating a copy. Need it to be a reference (pointer)

I am working on creating a matrix class for an assignment I have and usually if I assign a variable as x = self, x is a reference to self and thus all operations are in place. I have a function that reduces the matrix, and as an optional parameter I've added inplace=False such that:
if inplace:
self = A
else:
A = self.copy()
Now normally when I do this, if I were to do an operation such as A += B, self would be modified. However, when I run A.reduce(inplace=True), A is not modified. I've included the full class below and am hoping that someone can tell my why the operations are not happening in place. Thanks in advance.
import numpy as np
class matrix:
def __init__(self, A):
self.value = np.array(A, dtype=np.float)
self.indices = np.arange(self.value.shape[0])
self.shape = self.value.shape
def swap_rows(self, r1, r2):
ind = np.arange(self.value.shape[0])
swap = (r1, r2)
ind[swap[0]] = swap[1]
ind[swap[1]] = swap[0]
temp_ind = self.indices[swap[0]]
self.indices[swap[0]] = self.indices[swap[1]]
self.indices[swap[1]] = temp_ind
self.value = self.value[ind]
def add_rows(self, operations):
# operations = [(c, row1, row2)]
# where operation will be:
# c * row1 + row2 -> row2
for c, row1, row2 in operations:
self.value[row2] += c * self.value[row1]
# ... #
def reduce(self, b_ = None, swap=True, normalize=True, return_steps=False, inplace=False, debug=False):
if inplace:
A = self
else:
A = self.copy()
if b_:
b = b_.copy()
if len(b.shape) == 1:
b.reshape((-1, 1), inplace=True)
if return_steps:
steps = []
# Normalize
if normalize:
A_max = A.row_max()
A /= A_max
if debug:
print("A after normalization:")
print(A)
print("")
if return_steps:
steps.append([('normalize', A_max)])
if b_:
b /= A_max
m, n = A.shape
for col in range(n-1):
# Swap
if swap:
# Check for max value
max_ind = np.argmax(np.abs(A[:, col]))
# Check if max is zero
if np.abs(A[max_ind, col]) < 1e-30:
print('Matrix is singular')
if b_:
return A, b
else:
return A
# Swap if necessary
if max_ind > col:
A.swap_rows(col, max_ind)
if return_steps:
steps.append([('swap', col, max_ind)])
if b_:
b.swap_rows(col, max_ind)
# Get constants
cs = -A[col+1:, col] / A[col, col]
operations = [(c, col, i+col+1) for i, c in enumerate(cs)]
if return_steps:
steps.append(operations)
A.add_rows(operations)
if b_:
b.add_rows(operations)
if debug:
print("A after row operations:")
print(A)
print("")
return_vals = np.array([A, None, None])
if b_:
return_vals[1] = b
if return_steps:
return_vals[2] = steps
if inplace:
return_vals = return_vals[1:]
if return_vals.any():
return tuple(return_vals[return_vals != None])
# ... #
def row_max(self):
return np.array([self[row, i] for row, i in enumerate(np.argmax(np.abs(self.value), axis=1))]).reshape(-1, 1)
# ... #
def copy(self):
return matrix(np.copy(self.value))
def T(self):
return matrix(self.value.T)
def inverse(self):
return matrix(np.linalg.inv(self.value))
def flip(self, axis=None, inplace=False):
if inplace:
self.value = np.flip(self.value, axis=axis)
else:
return matrix(np.flip(self.value, axis=axis))
def reshape(self, shape, inplace=False):
if inplace:
self.value = self.value.reshape(*shape)
else:
return matrix(self.value.reshape(*shape))
def __add__(self, x):
if isinstance(x, matrix):
return matrix(self.value + x.value)
else:
return matrix(self.value + x)
def __sub__(self, x):
if isinstance(x, matrix):
return matrix(self.value - x.value)
else:
return matrix(self.value - x)
def __mul__(self, x):
if isinstance(x, matrix):
return matrix(self.value * x.value)
else:
return matrix(self.value * x)
def __truediv__(self, x):
if isinstance(x, matrix):
return matrix(self.value / x.value)
else:
return matrix(self.value / x)
# ... #
def __matmul__(self, A):
if isinstance(A, matrix):
return matrix(self.value # A.value)
else:
return matrix(self.value # A)
def __repr__(self):
return str(self.value)
def __getitem__(self, item):
return self.value[item]
def __setitem__(self, i, v):
self.value[i] = v
A = matrix([ [ 5, 6, 7, 5, -1],
[ 8, -4, -1, 0, -3],
[ 2, 1, -1, 3, 6],
[-9, 10, 1, -4, 6],
[ 9, 5, -5, -8, 4] ])
print("Original A:")
print(A)
print("")
A.reduce(inplace=True, debug=True)
print("A after inplace reduce function:")
print(A)
print("")
EDIT
Here is what I am trying to recreate in a simplistic way:
class obj:
def __init__(self, value):
self.value = value
def copy(self):
return obj(self.value)
def op(self, y, inplace=False):
if inplace:
x = self
else:
x = self.copy()
x.value += y
x.value /= y
if not inplace:
return x
def __repr__(self):
return str(self.value)
x = obj(5)
x.op(3)
print("Copy:", x)
x.op(3, inplace=True)
print("Inplace:", x)
You say that operators like += modify objects in place, but that's not always true. It only happens if the type of the object on the left side of the operator has an __iadd__ method. If it only has an __add__ method, then the Python interpreter translates X += Y to X = X + Y which is generally not an in-place operation.
So the reason your code doesn't do what you expect is because you don't have an __itruediv__ operator, and when you call A /= A_max (if normalize is True), you make a copy, despite your intention to be operating in place.

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.

Dependent variable in Python

I would like to define an Integer class in python, where an Integer (called y) can be related to another Integer (called x) and get updated automatically when this Integer x changes. More concretely I would like to have the following behavior
>>> x = Integer(7)
>>> y = x + 2
>>> print y
9
>>> x.set(9)
>>> print y
11
>>> z = x + y
>>> y.set(10)
>>> print z
19
I realize that one can do this in sympy but I am interested in implementing this myself. I would be grateful if someone can please point out how one would go about this in the simplest manner? Thank you.
I've not used Sympy before but here's my attempt:
class Integer(object):
def __init__(self, value_or_callback):
if isinstance(value_or_callback, int):
self._value_callback = lambda: value_or_callback
else:
self._value_callback = value_or_callback
#property
def value(self):
return self._value_callback()
def set(self, new_value):
self._value_callback = lambda: new_value
def __add__(self, other):
if isinstance(other, int):
return Integer(lambda: self.value + other)
elif isinstance(other, Integer):
return Integer(lambda: self.value + other.value)
else:
raise TypeError(other)
def __radd__(self, other):
return self.__add__(other)
def __repr__(self):
return str(self.value)
if __name__ == '__main__':
x = Integer(7)
y = x + 2
print(y)
x.set(9)
print(y)
z = x + y
y.set(10)
print(z)
Output
9
11
19

list with infinite elments

I need to operate on two separate infinite list of numbers, but could not find a way to generate, store and operate on it in python.
Can any one please suggest me a way to handle infinite Arithmetic Progession or any series and how to operate on them considering the fact the minimal use of memory and time.
Thanks every one for their suggestions in advance.
You are looking for a python generator instead:
def infinitenumbers():
count = 0
while True:
yield count
count += 1
The itertools package comes with a pre-built count generator.
>>> import itertools
>>> c = itertools.count()
>>> next(c)
0
>>> next(c)
1
>>> for i in itertools.islice(c, 5):
... print i
...
2
3
4
5
6
This is where the iterator comes in. You can't have an infinite list of numbers, but you can have an infinite iterator.
import itertools
arithmetic_progression = itertools.count(start,step) #from the python docs
The docs for Python2 can be found here
I have another python3 solution (read SICP chapter 3.5)
class Stream:
def __init__(self, head, tail):
self.head = head
self.tail = tail
self.memory = None
self.isDone = False
def car(self):
return self.head
def cdr(self):
if self.isDone:
return self.memory
self.memory = self.tail()
self.isDone = True
return self.memory
def __getitem__(self, pullFrom):
if pullFrom < 1 or self.memory == []:
return []
return [self.car()] + self.cdr()[pullFrom - 1]
def __repr__(self):
return "[" + repr(self.car()) + " x " + repr(self.tail) + "]"
def map(self, func):
if self.memory == []:
return []
return Stream(func(self.car()), lambda: Stream.map(self.cdr(), func))
def from_list(lst):
if lst == []:
return []
return Stream(lst[0], lambda:
Stream.from_list(lst[1:]))
def filter(self, pred):
if self.memory == []:
return []
elif pred(self.car()):
return Stream(self.car(), lambda: Stream.filter(self.cdr(), pred))
else:
return self.cdr().filter(pred)
def sieve(self):
return Stream(self.car(), lambda: self.cdr().filter(lambda n: n % self.car() > 0).sieve())
def foreach(self, action, pull = None):
if pull is None:
action(self.car())
self.cdr().foreach(action, pull)
elif pull <= 0:
return
else:
action(self.car())
self.cdr().foreach(action, pull-1)and run:
a = Stream(0, lambda: a.map((lambda x: x + 1)))
print(a[10])
which returns:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] .
But streams are lazily evaluated, so:
>>> a = Stream(0, lambda: a.map((lambda x: x + 1)))
>>> print(a)
prints:
[0 x [...]]
To create an object that acts like a "mutable" infinite list, you can overload the __getitem__ and __setitem__ methods in a class:
class infinite_list():
def __init__(self, func):
self.func = func
self.assigned_items = {}
def __getitem__(self, key):
if key in self.assigned_items:
return self.assigned_items[key]
else:
return self.func(key)
def __setitem__(self, key , value):
self.assigned_items[key] = value
Then, you can initialize the "infinite list" with a lambda expression and modify an item in the list:
infinite_thing = infinite_list(lambda a: a*2)
print(infinite_thing[1]) #prints "2"
infinite_thing[1] = infinite_thing[2]
print(infinite_thing[1]) #prints "4"
Similarly, it is possible to create an "infinite dictionary" that provides a default value for each missing key.
Perhaps the natural way to generate an infinite series is using a generator:
def arith(a, d):
while True:
yield a
a += d
This can be used like so:
print list(itertools.islice(arith(10, 2), 100))
My solution is:
from hofs import *
def cons_stream(head,tail):
return [head,tail,False,False]
def stream_cdr(strm):
if strm[2]:
return strm[3]
strm[3] = strm[1]()
strm[2] = True
return strm[3]
def show_stream(stream, num = 10):
if empty(stream):
return []
if num == 0:
return []
return adjoin(stream[0], show_stream(stream_cdr(stream), num - 1))
def add_streams(a , b):
if empty(a):
return b
if empty(b):
return a
return cons_stream(a[0] + b[0] , lambda : add_streams( stream_cdr(a), stream_cdr(b)))
def stream_filter( pred , stream ):
if empty(stream):
return []
if pred(stream[0]):
return cons_stream(stream[0], lambda : stream_filter(pred, stream_cdr(stream)))
else:
return stream_filter( pred , stream_cdr( stream ))
def sieve(stream):
return cons_stream(stream[0] , lambda : sieve(stream_filter(lambda x : x % stream[0] > 0 , stream_cdr(stream))))
ones = cons_stream(1, lambda : ones)
integers = cons_stream(1, lambda : add_streams(ones, integers))
primes = sieve(stream_cdr(integers))
print(show_stream(primes))
Copy the Python code above.
When I tried it, i got [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] which is 10 of an infinite list of primes.
You need hofs.py to be
def empty(data):
return data == []
def adjoin(value,data):
result = [value]
result.extend(data)
return result
def map(func, data):
if empty(data):
return []
else:
return adjoin(func(data[0]), map(func, data[1:]))
def keep(pred, data):
if empty(data):
return []
elif pred(data[0]):
return adjoin( data[0] , keep(pred, data[1:]))
else:
return keep(pred, data[1:])
I assume you want a list of infinite numbers within a range. I have a similar problem, and here is my solution:
c = 0
step = 0.0001 # the difference between the numbers
limit = 100 # The upper limit
myInfList = []
while c <= limit:
myInfList.append(c)
c = c + step
print(myInfList)

Categories