how can i create a class inside a loop - python

Experiment
class calculator:
class add:
def __init__(self,*arg):
self.arg = arg
def display_new(self):
return sum(self.arg)
class multiply:
def __init__(self,*arg):
self.arg = arg
class multi_num:
def __init__(self,*arg):
self.arg = arg
def nature(self):
sum = 1
for x in arg:
sum=sum*x
return sum
class devide:
def __init__(self,x,y):
self.x = x
self.y = y
def display3(self):
try:
result = self.x/self.y
except ZeroDivisionError:
print("error: divided by zero")
else:
return (result)
calc = calculator()
multiply = calc.multiply(1,2,3,4,5)
multiply.display2()
its not displaying the result. how can I fix this and where am I making mistake ,add and divide is working properly but I don't know why this multiply is not working.

Change arg to self.arg:
def nature(self):
sum = 1
for x in self.arg:
sum=sum*x
return sum

Related

Name "function name" is not defined

I've been attempting to complete one of my subjects for the OOP, but I couldn't manage to figure out what's wrong with the definition of my functions. I'm a newbie in this language, already searched the forums but I couldn't find anything useful.
Error message:
Traceback (most recent call last):
File "/home/main.py", line 44, in
add(x, y)
NameError: name 'add' is not defined
This is the program I wrote.
class Complex(object):
def __init__(self, r = 0, i = 0):
self.r = r
self.i = i
def __str__ (self):
return "%s + i%s" % (self.r, self.i)
def add (self, other):
summ = Complex()
summ.r = self.r + other.r
summ.i = self.i + other.i
return "Sum is %d" % summ
def dif (self, other):
dif = Complex()
dif.r = self.r - other.r
dif.i = self.i - other.i
return dif
def multiply (self, other):
multiply = Complex()
multiply.r = self.r * other.r
multiply.i = self.i * other.i
return "%d" % (-1 * multiply.r * multiply.i)
def divide (self, other):
divide = Complex()
divide.r = self.r / other.r
divide.i = self.i / other.i
return "%d" % (divide.r / divide.i)
x = Complex()
y = Complex()
x.r = int(input("Type in real part of x: \n"))
x.i = int(input("Type in imaginary of x: \n"))
print (x, "\n")
y.r = int(input("Type in real part of y: \n"))
y.i = int(input("Type in imaginary of y: \n"))
print (y, "\n")
add(x, y)
The add() function is a member of the Complex class but you are calling it on its own.
You need to call it like this
x.add(y)
When a function is a member of a class like below:
class Complex(object):
def add (self, other):
# Do stuff
The object the function is called on automatically gets passed as self.
So if you call x.add(y), self will be x and other will be y.
If add is a method of your class Complex, then you must write x.add(y) instead of add(x, y).
I know that it is confusing in Python. You need always to apply the "self" as first argument of a method, although it is not an argument, but the object whose method you call.

Delayed Compute with Method Chaining in Python

Let say I have a class:
class MATH(object):
def __init__(self):
self.results = [0, 1, 2]
def add(self, value):
# Add amount 'value' to every element in the results list
def minus(self, value):
# Subtract amount 'value' from every element in the results list
def compute(self):
# Perform computation
Is there a way to do something like:
m = MATH()
m.add(5).minus(2).add(7) # This would be a lazy and not actually compute
m.compute() # This would actually run the computations in order
How do I do something like this in python?
Personally, I would have .add(), et al, push the operator and the operand onto a list and then have .compute() walk through the list, computing the answer as it goes.
Operator chaining is easily accomplished by having each operator return self as its final instruction.
For example:
class MATH(object):
def __init__(self):
self.results = [0, 1, 2]
self.operations = []
def add(self, value):
# Add amount 'value' to every element in the results list
self.operations.append(('+', value))
return self
def minus(self, value):
# Subtract amount 'value' from every element in the results list
self.operations.append(('-', value))
return self
def compute(self):
results = []
for x in self.results:
for op, value in self.operations:
if op == '+':
x += value
elif op == '-':
x -= value
results.append(x)
return results
m = MATH()
m.add(5).minus(2).add(7) # This would be a lazy and not actually compute
print(m.compute()) # This would actually run the computations in order
Wow, you guys are fast!
Here is another go also with a stack, but manipulating the results-list:
class MATH(object):
def __init__(self):
self.results = [0, 1, 2]
self.stack = []
def add(self, value):
self.stack.append(value)
return self
def minus(self, value):
self.stack.append(-value)
return self
def compute(self):
for s in self.stack:
for index, _ in enumerate(self.results):
self.results[index] += s
m = MATH()
m.add(5).minus(2).add(7) # This would be a lazy and not actually compute
m.compute() # This would actually run the computations in order
print m.results
[10, 11, 12]
As #Rob pointed out, you will need some way to store the operators so that the final compute method can be utilized correctly. This solution uses __add__ and __sub__, with a decorator to store the operators. Note, however, that it would be much more efficient to keep a running total of the values that have been pushed to the stack:
import operator as op
from collections import deque
def operator(f):
def wrapper(cls, _):
cls.operators.append(f.__name__.replace('__', ''))
return f(cls, _)
return wrapper
class Math:
def __init__(self):
self.stack = []
self.operators = deque()
#operator
def __sub__(self, _val):
self.stack.append(_val)
return self
#operator
def __add__(self, _val):
self.stack.append(_val)
return self
def compute(self):
_result = 0
while self.stack:
a, *c = self.stack
_result = getattr(op, self.operators.popleft())(_result, a)
self.stack = c
return _result
m = Math()
m1 = m + 5 - 2 + 7
print([m1.stack, m1.operators])
print(m1.compute())
Output:
[[5, 2, 7], ['add', 'sub', 'add']]
10
Here's a string-based approach which requires little brainpower.
class Math:
def __init__(self):
self.stack = '0'
#staticmethod
def wrap(expr):
return '(' + expr + ')'
def _op(self, other, op):
self.stack = ' '.join([Math.wrap(self.stack), op, str(other)])
def add(self, other):
self._op(other, '+')
return self
def mul(self, other):
self._op(other, '*')
return self
def compute(self):
return eval(self.stack)
m = Math()
print(m.add(2).mul(3).compute())

How to replace an integer with a different class when it is assigned

I have a class called newInteger, and a variable called num, but I would like num to be a newInteger() instead of an int(). Code below.
class newInteger(int):
def __init__(self, value):
self.value = value
num = 10
I want the line num = 10 to act as if it is num = newInteger(10). Thanks to anyone who can help me with this.
You can run a small thread parallel to your main program that replaces all created integers to newInteger:
import threading
import time
class newInteger(int):
def __init__(self, value):
self.value = value
def __str__(self):
return "newInteger " + str(self.value)
def replace_int():
while True:
g = list(globals().items())
for n, v in g:
if type(v) == int:
globals()[n] = newInteger(v)
threading.Thread(target=replace_int, daemon=True).start()
num = 10
time.sleep(1)
print(num)
But this is unpythonic and will be realy hard to debug. You should just use a explicit conversion like #johnashu proposed
I am not sure if this is what you mean but if youassign the class to a variabl. then it will be an instance of that class..
example:
class newInteger(int):
def __init__(self, value):
self.value = value
num = 10
if num == 10:
num = newInteger(10)
prints:
hello

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"

Python - TypeError: object of type '...' has no len()

Here is a class:
class CoordinateRow(object):
def __init__(self):
self.coordinate_row = []
def add(self, input):
self.coordinate_row.append(input)
def weave(self, other):
result = CoordinateRow()
length = len(self.coordinate_row)
for i in range(min(length, len(other))):
result.add(self.coordinate_row[i])
result.add(other.coordinate_row[i])
return result
This is a part of my program:
def verwerk_regel(regel):
cr = CoordinateRow()
coordinaten = regel.split()
for coordinaat in coordinaten:
verwerkt_coordinaat = verwerk_coordinaat(coordinaat)
cr.add(verwerkt_coordinaat)
cr2 = CoordinateRow()
cr12 = cr.weave(cr2)
print cr12
def verwerk_coordinaat(coordinaat):
coordinaat = coordinaat.split(",")
x = coordinaat[0]
y = coordinaat[1]
nieuw_coordinaat = Coordinate(x)
adjusted_x = nieuw_coordinaat.pas_x_aan()
return str(adjusted_x) + ',' + str(y)
But I'm geting an error at "cr12 = cr.weave(cr2)":
for i in range(min(length, len(other))):
TypeError: object of type 'CoordinateRow' has no len()
You need to add a __len__ method, then you can use len(self) and len(other):
class CoordinateRow(object):
def __init__(self):
self.coordinate_row = []
def add(self, input):
self.coordinate_row.append(input)
def __len__(self):
return len(self.coordinate_row)
def weave(self, other):
result = CoordinateRow()
for i in range(min(len(self), len(other))):
result.add(self.coordinate_row[i])
result.add(other.coordinate_row[i])
return result
In [10]: c = CoordinateRow()
In [11]: c.coordinate_row += [1,2,3,4,5]
In [12]: otherc = CoordinateRow()
In [13]: otherc.coordinate_row += [4,5,6,7]
In [14]:c.weave(otherc).coordinate_row
[1, 4, 2, 5, 3, 6, 4, 7]
Iterating over a range of len(something) is very much an anti-pattern in Python. You should be iterating over the contents of the containers themselves.
In your case, you can just zip the lists together and iterate over that:
def weave(self, other):
result = CoordinateRow()
for a, b in zip(self.coordinate_row, other.coordinate_row):
result.add(a)
result.add(b)
return result
Here is the complete solution for the Cart and Item class implementation.
class Item:
def __init__(self, name, price):
self.name = name
self.price = price
def getPrice(self):
return self.price
def getName(self):
return self.name
class ShoppingCart:
def __init__(self):
self.list = []
def __len__(self):
return len(self.list)
def add(self, item):
self.list.append(item)
def total(self):
total = 0
for item in self.list:
total = total + item.getPrice()
return total
other is of type CoordinateRow, which does not have a length. Use len(other.coordinate_row) instead. This is the list that does have the length property.

Categories