How to update classes - python

class Dog(object):
def __init__(self, number):
self.number = number
def number_update(self):
self.number += 1
class Cat(object):
def __init__(self, number):
self.number = number
class1 = Dog(1)
class2 = Cat(class1.number * 0.5)
class1.number_update()
print(class1.number)
print(class2.number)
Current output: 2, 0.5
I want: 2, 1
I really simplified it, so I hope you will understand
Thank you for help

You are running class1.number_update() after you define the class2 variable, so the class1 variable has a value of 1 when you define class2, and after you define class2, class1 becomes into 2. To fix this, just switch around those two lines:
class Dog(object):
def __init__(self, number):
self.number = number
def number_update(self):
self.number += 1
class Cat(object):
def __init__(self, number):
self.number = number
class1 = Dog(1)
class1.number_update()
class2 = Cat(class1.number * 0.5)
print(class1.number)
print(class2.number)

You could return the number in number_update():
class Dog(object):
def __init__(self, number):
self.number = number
def number_update(self):
self.number += 1
return self.number
class Cat(object):
def __init__(self, number):
self.number = number
class1 = Dog(1)
class2 = Cat(class1.number_update() * .5)
print(class1.number)
print(class2.number)
Output:
2
1.0

As suggested in the comments, to do this exactly as you want, you'll have to write your own expression and number classes, such as this:
class Op:
def __init__(self, op):
self.op = op
def __call__(self, a, b):
if self.op == "*":
return a * b
if self.op == "/":
return a / b
if self.op == "-":
return a - b
if self.op == "+":
return a + b
raise TypeError(f"Unknown op {repr(self.op)}")
def __repr__(self):
return self.op
mul = Op("*")
div = Op("/")
add = Op("+")
sub = Op("-")
class Expr:
def __init__(self, a, b, op):
self.op = op
self.a = a
self.b = b
def eval(self):
return self.op(self.a.eval(), self.b.eval())
def __repr__(self):
return f"({self.a} {self.op} {self.b})"
def __mul__(self, other):
if isinstance(other, (int, float)):
b = Number(other)
else:
b = other
a = self
return Expr(a, b, mul)
def __div__(self, other):
if isinstance(other, (int, float)):
b = Number(other)
else:
b = other
a = self
return Expr(a, b, div)
def __add__(self, other):
if isinstance(other, (int, float)):
b = Number(other)
else:
b = other
a = self
return Expr(a, b, add)
def __sub__(self, other):
if isinstance(other, (int, float)):
b = Number(other)
else:
b = other
a = self
return Expr(a, b, sub)
def __rmul__(self, other):
return self.__class__.__mul__(other, self)
def __rdiv__(self, other):
return self.__class__.__div__(other, self)
def __rsub__(self, other):
return self.__class__.__sub__(other, self)
def __radd__(self, other):
return self.__class__.__add__(other, self)
class Number(Expr):
def __init__(self, value):
self._value = value
def get(self):
return self._value
def set(self, new):
self._value = new
def increment(self):
self._value += 1
def eval(self):
return self._value
def __repr__(self):
return str(self._value)
class Dog:
def __init__(self, number):
self.number = Number(number)
def number_update(self):
self.number.increment()
class Cat:
def __init__(self, number):
self._number = number
#property
def number(self):
return self._number.eval()
#number.setter
def number(self, new):
if isinstance(new, (int, float)):
new = Number(new)
self._number = new
cls1 = Dog(1)
cls2 = Cat(cls1.number * 0.5)
cls1.number_update()
print(cls1.number)
print(cls2.number)
Here, we get the expected output of
2
1.0

Lets go through the lines of your main function and trace the values of Dog and Cat
class1 = Dog(1) # Dog=1; Cat=undefined
class2 = Cat(class1.number * 0.5) # Dog=1; Cat=1*0.5=0.5
class1.number_update() # Dog=2; Cat=0.5
print(class1.number) # >>>"2"
print(class2.number) # >>>"0.5"
Your class doesn't have a reference to Dog's number member, it just references the Cat class property.
EDIT: It doesn't copy, it creates a reference directly to the object.

Related

How to add two instances of my custom class

I want to run this code (must) including the attribute value next to total in the print section. What code should I insert inside the class to do it?
class Random:
def __init__(self, x):
self.x = x
def __add__(self, other):
return self.x + other.x
p1 = Random(2)
p2 = Random(3)
total = p1 + p2
print(total.value)
Return an instance of Random in your __add__ method and add a property with the name value for the class.
class Random:
def __init__(self, x):
self.x = x
def __add__(self, other):
return Random(self.x + other.x)
#property
def value(self):
return self.x
p1 = Random(2)
p2 = Random(3)
total = p1 + p2
print(total.value)
Of course the better option would be to replace the instance attribute x with value. Then there's no need for the property.
class Random:
def __init__(self, x):
self.value = x
def __add__(self, other):
return Random(self.value + other.value)
Make total a Random as well.
class Random:
def __init__(self, value):
self.value = value
def __add__(self, other):
return Random(self.value + other.value)
p1: Random = Random(2)
p2: Random = Random(3)
total: Random = p1 + p2
print(total.value)

Assign two functions to class?

class Math:
def __init__(self, number):
self.number = number
def add(self, add_num):
return self.number + add_num
def sub(self, sub_num):
return self.number - sub_num
Math(5).add(5)
I get 10 as expected
But if I do Math(5).add(5).sub(3):
I get this error AttributeError: 'int' object has no attribute 'sub'
for that to work your mehtods need to return self (or a fresh instance of Math):
class Math:
def __init__(self, number):
self.number = number
def add(self, add_num):
self.number += add_num
return self
# or:
# return Math(self.number + add_num)
def sub(self, sub_num):
self.number -= sub_num
return self
# or:
# return Math(self.number - add_num)
def __str__(self):
return str(self.number)
m = Math(5).add(5).sub(3)
print(m)
# 7
the add here now behaves more like an __iadd__.
Of course.
What you do is essentially
a = Math(5) # a is a "Math" object
b = a.add(5) # b is what add() returns, i. e. an int
c = b.sub(3) # an int has no sub() method
I don't know what exactly you want to achieve: do you want add() and sub() to modify the object you are operating on? In this case, you can do
class Math:
def __init__(self, number):
self.number = number
def add(self, add_num):
self.number = self.number + add_num
return self
def sub(self, sub_num):
self.number = self.number - sub_num
return self
If you don't want that, you can do instead
class Math:
def __init__(self, number):
self.number = number
def add(self, add_num):
return Math(self.number + add_num)
def sub(self, sub_num):
return Math(self.number - sub_num)
return self
In both cases, your intended way of chaining the calls works.
The value that you return is not an object of your Math class.
You must create an object of Math whose number attribute is your computed results and return that for your code to work.
When you execute return self.number + add_num, you return an integer, not an instance of your Math class. To solve this, you can change your add method to
return Math(self.number + add_num).

multiple functions in Python

We have some variable, or other instance: a='?'.
We have such input:
f = a(3112).bas(443).ssad(34)
When we type
print(f)
Output should be:
3112a-443bas-34ssad
I've tried some ways to solve this and have found information about chaining, but I still have the problem. I can't return class name to the brginning of the string.
This, what I have:
class A():
def __getattribute__(self, item):
print (str(item))
return super(A, self).__getattribute__(item)
def __init__(self, x):
self.x = x
print (str(x))
def b(self, item):
print (str(item))
return self
def c(self, item):
print (str(item))
return self
def d(self, item):
print (str(item))
return self
A(100).b(200).c(300).d(400)
My output:
100
b
200
c
300
d
400
But I couldn't concatenate it in one string.
Dynamic way
class A(object):
def __init__(self, integer):
self._strings = ['{}a'.format(integer)]
def __getattr__(self, attrname, *args):
def wrapper(*args, **kwargs):
self._strings.append('{}{}'.format(args[0], attrname))
return self
return wrapper
def __str__(self):
return '-'.join(self._strings)
print(A(100).bas(200).ssad(300))
Output
100a-200bas-300ssad
But also
print(A(100).egg(200).bacon(300).SPAM(1000))
Output
100a-200egg-300bacon-1000SPAM
Static way
class A(object):
def __init__(self, integer):
self._strings = ['{}a'.format(integer)]
def bas(self, integer):
self._strings.append('{}bas'.format(integer))
return self
def ssad(self, integer):
self._strings.append('{}ssad'.format(integer))
return self
def __str__(self):
return '-'.join(self._strings)
print(A(100).b(200).c(300))
Output
100a-200bas-300ssad
More about __str__
You can override the __str__ method to define your specific output:
class A():
def __init__(self, a, b="", c="", d=""):
self._a = a
self._b = b
self._c = c
self._d = d
def __str__(self):
return '{}a-{}b-{}c-{}d'.format( self.a, self.b, self.c, self.d )
def b(self, item):
self._b = item
return self
def c(self, item):
self._c = item
return self
def d(self, item):
self._d = item
return self
f = A(100).b(200).c(300).d(400)
print(f) # 100a-200b-300c-400d
Here I tried it in another way , ie, If you want to take the function name instead of manually giving it you can use inspect in python. Try this code :
import inspect
class A():
l = []
def __init__(self, x):
self.x = x
print (str(x))
self.l.append(str(x) + "a")
def b(self, item):
print (str(item))
self.l.append(str(item) + inspect.stack()[0][3])
return self
def c(self, item):
print (str(item))
self.l.append(str(item) + inspect.stack()[0][3])
return self
def d(self, item):
print (str(item))
self.l.append(str(item) + inspect.stack()[0][3])
return self
print("-".join(A(100).b(200).c(300).d(400).l))
The o/p is like :
'100a-200b-300c-400d'

Make __add__ to return arithmetic mean

I want the add method of my object Foo to return averaged summation. For the summation of just two objects it is straightforward:
class Foo():
def __init__(self, n):
self.n = n
def __add__(self, other):
return Foo((self.n + other.n)/2)
How to do this for N>2 objects? E.g. Foo(0) + Foo(1) + Foo(2) + Foo(3) should return Foo((0 + 1 + 2 + 3)/4), i.e. Foo(1.5).
========================================
Edit: Here's my solution
class Foo():
def __init__(self, n):
self.n = n
self._n = n
self._count = 1
def __add__(self, other):
out = Foo(self._n + other._n)
out._count = self._count + other._count
out.n = out.n/out._count
return out
Not the best way to get the arithmetic mean, but I needed to do it in this way. Also, this demonstrates how to do special additions of user defined objects, which return a function of the total sum of the objects. E.g. make __add__ return the square root of the sum of the objects:
class Bar():
def __init__(self, n):
self.n = n
self._n = n
def __add__(self, other):
out = Bar(self._n + other._n)
out.n = (out.n)**0.5
return out
One solution could be storing in the class TWO numbers: the average value and the number of samples:
class Foo:
def __init__(self, avg, count=1):
self.avg = avg
self.count = count
def __add__(self, other):
return Foo((self.avg*self.count + other.avg*other.count)
/
(self.count + other.count),
self.count + other.count)
Even better would be just storing the sum and compute the average only if/when requested.

Allowing User to Input Variables (Python)

I am working on a project using PuLP and I am trying to create a terminal prompt to allow users to input their data and then my Python program will change the input to code readable by PuLP. To do this I must allow users to input:
2*a + 3*b <= c
and my code will eval() this code as well as creating variables a, b and c such
a = LpVariable("a",None,None,LpContinuous)
b = LpVariable("b",None,None,LpContinuous)
c = LpVariable("c",None,None,LpContinuous)
any ideas? I've tried using exec() but it does not seem to like this much.
at the moment I'm getting the input via:
print "Please enter your constraints 1 at a time and enter '#' when done:"
control = True
while (control):
entry = raw_input('-->')
entryS = ""
entryS += entry
so the string 2*a+3*B <= c is stored as entryS
Using eval() might not be such a good idea, but if you insist (Python 3):
call = lambda f: lambda *args: f(*args)
flip = lambda f: lambda *args: f(*reversed(args))
class Expression:
def __repr__(self):
return '{}({})'.format(type(self).__name__, self)
class BinaryExpression(Expression):
def __init__(self, left, right):
self.left = promote(left)
self.right = promote(right)
def __str__(self):
return '({} {} {})'.format(self.op, self.left, self.right)
class Variable(Expression):
def __init__(self, name):
self.name = name
def __str__(self):
return self.name
class Number(Expression):
def __init__(self, value):
self.value = int(value)
def __str__(self):
return str(self.value)
class Multiplication(BinaryExpression):
op = '*'
class Addition(BinaryExpression):
op = '+'
class Smaller(BinaryExpression):
op = '<'
class Greater(BinaryExpression):
op = '>'
class SmallerOrEqual(BinaryExpression):
op = '<='
class GreaterOrEqual(BinaryExpression):
op = '>='
Expression.__mul__ = call(Multiplication)
Expression.__rmul__ = flip(Multiplication)
Expression.__add__ = call(Addition)
Expression.__radd__ = flip(Addition)
Expression.__lt__ = call(Smaller)
Expression.__gt__ = call(Greater)
Expression.__le__ = call(SmallerOrEqual)
Expression.__ge__ = call(GreaterOrEqual)
def promote(item):
if isinstance(item, str):
return Variable(item)
elif isinstance(item, int):
return Number(item)
else:
return item
class LpVariable:
def __init__(self, name, x, y, z):
self.name = name
self.x = x
self.y = y
self.z = z
def __str__(self):
return 'LpVariable({}, {}, {}, {})'.format(
self.name,
self.x,
self.y,
self.z,
)
__repr__ = __str__
LpContinuous = 'LpContinuous'
class ExpressionVisitor:
def visit(self, node):
return getattr(self, 'visit_' + type(node).__name__)(node)
class LpTransformer(ExpressionVisitor):
def visit_Variable(self, node):
return LpVariable(node.name, None, None, LpContinuous)
def visit_Number(self, node):
return node.value
def visit_Multiplication(self, node):
return [node.op, self.visit(node.left), self.visit(node.right)]
def visit_Addition(self, node):
return [node.op, self.visit(node.left), self.visit(node.right)]
def visit_Smaller(self, node):
return [node.op, self.visit(node.left), self.visit(node.right)]
def visit_Greater(self, node):
return [node.op, self.visit(node.left), self.visit(node.right)]
def visit_SmallerOrEqual(self, node):
return [node.op, self.visit(node.left), self.visit(node.right)]
def visit_GreaterOrEqual(self, node):
return [node.op, self.visit(node.left), self.visit(node.right)]
class Evaluator(ExpressionVisitor):
def __init__(self, **env):
self.env = env
def visit_Variable(self, node):
return self.env[node.name]
def visit_Number(self, node):
return node.value
def visit_Multiplication(self, node):
return self.visit(node.left) * self.visit(node.right)
def visit_Addition(self, node):
return self.visit(node.left) + self.visit(node.right)
def visit_Smaller(self, node):
return self.visit(node.left) < self.visit(node.right)
def visit_Greater(self, node):
return self.visit(node.left) > self.visit(node.right)
def visit_SmallerOrEqual(self, node):
return self.visit(node.left) <= self.visit(node.right)
def visit_GreaterOrEqual(self, node):
return self.visit(node.left) >= self.visit(node.right)
class Namespace(dict):
def __missing__(self, key):
value = self[key] = Variable(key)
return value
def main():
constraints = '2*a + 3*b <= c'
namespace = Namespace()
tree = eval(constraints, {}, namespace)
print('AST in prefix notation:', tree)
print()
print('Namespace:', namespace)
print()
print('LP-Transformed tree:')
import pprint
pprint.pprint(LpTransformer().visit(tree))
print()
print('Evaluated with a=3, b=5, c=10:')
pprint.pprint(Evaluator(a=3, b=5, c=10).visit(tree))
print()
print('Evaluated with a=3, b=5, c=100:')
pprint.pprint(Evaluator(a=3, b=5, c=100).visit(tree))
if __name__ == '__main__':
main()
Result:
AST in prefix notation: (<= (+ (* 2 a) (* 3 b)) c)
Namespace: {'a': Variable(a), 'c': Variable(c), 'b': Variable(b)}
LP-Transformed tree:
['<=',
['+',
['*', 2, LpVariable(a, None, None, LpContinuous)],
['*', 3, LpVariable(b, None, None, LpContinuous)]],
LpVariable(c, None, None, LpContinuous)]
Evaluated with a=3, b=5, c=10:
False
Evaluated with a=3, b=5, c=100:
True
The LpVariable class is obviously a mockup. Also, the LpTransformer class should produce something that's usable by pulp. Just change the visit_* methods accordingly.
Numbers are all ints, which you might not want. You should probably add floats and/or convert all numbers to decimal.Decimal.
Instead of using eval() I'd probably write a real parser, maybe with pyparsing, or, my favorite for stuff like that, Parcon.
Put
entryS = ""
before the while loop.

Categories