Recursive division within a class - python

I'm trying to practice OOP and recursion but I'm having some trouble. I think the recursive aspects of it are correct but the way I'm structuring class is wrong.
How it should work:
It should subtract 1 from 6, until x = 0. Each time adding 1 to index. When x is equal to 0 the function should return index.
Where I'm Getting Errors:
The following code says I have an error because divide accepts three arguements while I've only supplied two. But I thought that self wasn't really an argument. It was just something that had to be done in a class.
How do I make the below code work as intended?
class Division(object):
def __init__(self, x, y):
self.index = 0
self.x = x
self.y = y
def divide(self, x, y):
self.index += 1
if self.x <= 0:
return self.index
return divide(self.x-self.y, self.y)
print(Division.divide(6,1))
Edit (Revised Code):
Now I'm getting an error that divide is not defined?
class Division(object):
def __init__(self):
self.index = 0
def divide(self, x, y):
self.index += 1
if x <= 0:
return self.index
return divide(x-y, y)
print(Division().divide(6,1))
Second Edit:
I think I figured it out. I had to add create an instance of Division again on the divide methods recursive return. My output is wrong though. It's saying self.index is equal to one. Probably because when I create a new instance of the class the index is set to 0. How do I overcome this problem?
Final Code:
class Division(object):
def __init__(self):
self.index = 0
def divide(self, x, y):
self.index += 1
if x <= y:
return self.index
return self.divide(x-y, y)
print(Division().divide(6,1))

I don't understand why you want to have an object here... What does it models ? So here is a solution without object
def divide(a, b, q = 0):
if a < b:
return q
return divide(a-b, b, q+1)

Related

Skip duplicated dots based generated by randint() function

I am still learning Python programming and currently struggling to achieve one goal. I got a class Dot that is used to create coordinates and compare them later on. Also, I got a class Player with two other child classes that are inherited from the Parent class.
class Dot:
def __init__(self, x, y):
self.x = x
self.y = y
def __eq__(self, other):
return self.x == other.x and self.y == other.y
def __repr__(self):
return {self.x, self.y}
class Player:
def __init__(self, board, enemy):
self.board = board
self.enemy = enemy
def ask(self):
raise NotImplementedError()
def turn(self):
while True:
try:
target = self.ask()
repeat = self.enemy.shoot(target)
return repeat
except BoardExceptionError as e:
print(e)
class Viki(Player):
def ask(self):
answer = Dot(randint(0, 5), randint(0, 5))
time.sleep(3)
print(f'Turn of Viki: {answer.x} {answer.y}')
return answer
class Human(Player):
def ask(self):
while True:
h = input('Your turn: ').split()
if len(h) != 2:
print('Add 2 coordinates...')
continue
x, y = h
if not (x.isdigit()) or not (y.isdigit()):
print('Add numbers from 0 to 6...')
continue
x, y = int(x), int(y)
return Dot(x - 1, y - 1)
What I would like to expect is that class "Viki(Player)" kind of an AI, forcing it to not use the same coordinates(Dots) that are already used(generated) previously. So, every time it should use none used cells on the board.
I understand that it might help in this case logical operators or count function. For example,
Example 1:
a = Dot(1, 2)
b = Dot(1, 3)
c = Dot(1, 4)
abc_list = [Dot(1, 2), Dot(2, 2), Dot(2, 3)]
print(a in abc_list)
Output
True
Example 2:
print(abc_list.count(a))
Output
1
I tried to play with both options but gettings different types of errors when I try to use loops and blocks. I understand that the bottleneck here is my knowledge :) Your help is much appreciated if someone can help me to sort this out. Thanks in advance!
Here is a generator that produces all the dots in random order (no repeats):
from itertools import product
from random import shuffle
def random_dots():
dots = [Dot(*p) for p in product(range(6), repeat=2)]
shuffle(dots)
yield from dots
rd = random_dots()
Now, you can use it in you code:
dot = next(rd)
If pre-generating all dots is not an option because there are too many, you could use the following which is lighter on memory/time:
dots = set()
def random_dot():
while (tpl := (randint(0, 5), randint(0, 5))) in dots:
pass
dots.add(tpl)
return Dot(*tpl)
And use like:
dot = random_dot()

Python: Iterator returns None

Here is my code:
class Prizes(object):
def __init__(self, purchases, n, d):
self.p = purchases
self.n = n
self.d = d
self.x = 1
def __iter__(self):
return self
def __next__(self):
print(self.x)
if self.x % self.n == 0 and self.p[self.x - 1] % self.d == 0:
self.x = self.x + 1
return self.x - 1
elif self.x > len(self.p):
raise StopIteration
self.x = self.x + 1
def superPrize(purchases, n, d):
return list(Prizes(purchases, n, d))
An example of usage:
superPrize([12, 43, 13, 465, 1, 13], 2, 3)
The output should be:
[4]
But actual output is:
[None, None, None, 4, None, None].
Why does it happen?
Your problem is your implementation of __next__. When Python calls __next__, it will always expect a return value. However, in your case, it looks like you may not always have a return value each call. Thus, Python uses the default return value of a function - None:
You need some way to keep program control inside of __next__ until you have an actually return value. This can be done using a while-loop:
def __next__(self):
while True:
if self.x % self.n == 0 and self.p[self.x - 1] % self.d == 0:
self.x = self.x + 1
return self.x - 1
elif self.x > len(self.p):
raise StopIteration
self.x = self.x + 1
Wrap it with while so that your method doesn't return a value until you found one:
def __next__(self):
while True:
if self.x % self.n == 0 and self.p[self.x - 1] % self.d == 0:
self.x = self.x + 1
return self.x - 1
elif self.x > len(self.p):
raise StopIteration
self.x = self.x + 1
Things working with iterators call __next__ expecting it to return a value, but the method returns a value only under a condition, otherwise it reaches the end of the method and it returns None.

how to remove a object in a python list

I create a class named point as following:
class point:
def __init__(self):
self.x = 0
self.y = 0
and create a list of point instances:
p1 = point()
p1.x = 1
p1.y = 1
p2 = point()
p2.x = 2
p2.y = 2
p_list = []
p_list.append(p1)
p_list.append(p2)
Now I'd like remove from the list the instance which x = 1 and y = 1, how can I do this?
I try to add a __cmp__ method for class point as following:
class point:
def __init__(self):
self.x = 0
self.y = 0
def __cmp__(self, p):
return self.x==p.x and self.y==p.y
But the following code does not work
r = point()
r.x = 1
r.y = 1
if r in p_list:
print('correct')
else:
print('wrong') # it will go here
p_list.remove(r) # it reports 'ValueError: list.remove(x): x not in list'
Your __cmp__ function is not correct. __cmp__ should return -1/0/+1 depending on whether the second element is smaller/equal/greater than self. So when your __cmp__ is called, it returns True if the elements are equal, which is then interpreted as 1, and thus "greater than". And if the elements are non-equal, it returns False, i.e. 0, which is interpreted as "equal").
For two-dimensional points, "greater than" and "smaller than" are not very clearly defined, anyway, so you can just replace your __cmp__ with __eq__ using the same implementation. Your point class should be:
class point:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def __eq__(self, p):
return self.x==p.x and self.y==p.y
When you're checking if r is in p_list you create a new instance of point, thus that instance of point will not be in the list (it has a different location in memory).
This function works to remove a point where x and y are 1:
for idx, p in enumerate(p_list):
if p.x==1 and p.y==1:
del p_list[idx]

error when executing same loop

I'm new to Python and I really want to understand why I get this error.
It happens in my findLargest function, while trying to execute the second for loop. The thing is that the second for loop does basically the same thing as the first one, but for some reason I get an error as I try to call on a (class)method. How can this be? Am I not allowed to have 2 for loops for same iterable in the same function?
shapeArea=shape.area()
throws:
TypeError: 'float' object is not callable
The objective of findlargest() is to loop through the set of classes twice, first in order to find the largest value(Area) while the second tries to find if there are other values that are equal.
class Shape(object):
def area(self):
raise AttributeException("Subclasses should override this method.")
class Triangle(Shape):
def __init__(self, base, height):
self.base = base
self.height = height
def area(self):
self.area = (self.base * self.height) / 2
return self.area
def __str__(self):
return "{} with base {} and height {}".format(self.__class__.__name__, self.base, self.height)
def __eq__(self, other):
return type(other) == Triangle and self.base == other.base and self.height == other.height
class ShapeSet:
def __init__(self):
self.shape_list = []
def addShape(self, sh):
if sh not in self.shape_list:
self.shape_list.append(sh)
else:
print ("{} is already existing".format(sh.__str__()))
def __iter__(self):
return (self.shape_list)
def __str__(self):
s = ''
for shape in self.__iter__():
s+= shape.__str__() + "\n"
return s
ss = ShapeSet()
ss.addShape(Triangle(1.2,2.5))
ss.addShape(Triangle(1.4,2.5))
ss.addShape(Triangle(1.3,2.5))
ss.addShape(Triangle(1.5,2.5))
def findLargest(shapes):
maxs = None
maxA = 0.0
for shape in shapes.__iter__():
shapeArea = shape.area()
if shapeArea > maxA or maxs == None:
maxs = shape
maxA = shapeArea
maxTuple = (maxs)
for shape in shapes.__iter__():
shapeArea = shape.area()
With this:
def area(self):
self.area=(self.base*self.height)/2
return self.area
You enter the method and then immediately mask it by assigning a different name to its reference. From then on, self.area refers to that number and you can no longer access that method. Fortunately, the fix is easy: don't save a reference at all.
def area(self):
return self.base * self.height / 2
Python does not separate the names for function/method objects and for other objects. Use unique reference names for any objects you'd like to retain.
I think your problem is here:
class Triangle(Shape):
def __init__(self, base, height):
self.base=base
self.height=height
def area(self):
self.area=(self.base*self.height)/2 ###################### HERE
return self.area
If you have
shape = Triangle(1.5,2.5)
shape.area() # returns float assigned at "HERE" to shape.area
shape.area() # try to call that float assigned in previous step at "HERE"

Obtaining values from dictionary in OOP: "AttributeError"

I am trying to get values from my dictionary VALUES. My program creates combination of possible positions and gets the last position. Then I want to get the value. Everything works well here except indicated .get_value method. When I execute this code I receive:
AttributeError: 'Combination' object has no attribute 'get_value'
Theoretically it should be easy but I am new to OOP and I don't see what is wrong here.
X = ['A','B','C']
Y = ['1','2','3']
VALUES = {'A':10, 'B': 50, 'C':-20}
class Combination:
def __init__(self,x,y):
if (x in X) and (y in Y):
self.x = x
self.y = y
else:
print "WRONG!!"
def __repr__ (self):
return self.x+self.y
def get_x(self):
return self.x
def get_y(self):
return self.y
class Position:
def __init__(self):
self.xy = []
for i in X:
for j in Y:
self.xy.append(Combination(i,j))
def choose_last(self):
return self.xy.pop()
def __str__(self):
return "List contains: " + str(self.xy)
class Operation1:
def __init__(self):
self.operation1 = []
def __str__(self):
s = str(self.operation1)
return s
def get_value(self):
V = VALUES.get(self)
return V
pos = Position()
print pos
last_item = pos.choose_last()
print "Last item:", last_item, pos
last_value = last_item.get_value() # <---- Here is a problem
How can I obtain value of my position? Value is determined by the X value - this is A,B or C. In the dictionary I have a numeral value for the letter.
You are appending objects of Combination into xy of Position. When you say choose_last, it will return the last Combination object inserted into xy. And you are trying to invoke get_value method on a Combination object, which doesnt have that method. Thats why you are getting that error.
Always use new style classes.

Categories