overload __add__

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • TMS
    New Member
    • Sep 2006
    • 119

    overload __add__

    OK, I'm building this reactor software (an assignment) that takes particles and shows a chain reaction.

    Here is the code I have so far:

    Code:
    class Particle:
    	def __init__(self, symbol, charge, number):
    		self.symbol = symbol
    		self.charge = charge
    		self.number = number
    	def __repr__(self):
    		return self.symbol
    class Nucleus(Particle):
    	def __repr__(self):
    		return "(%d)%s" % (self.number, self.symbol)
    class UnbalancedCharge:
    	pass #worry about this later
    class UnbalancedNumber:
    	pass #worry about this later
     
    class Reaction: # this is the class I'm having trouble with
    	def __init__(symbol, charge, number):
    		lhs = number, symbol
    		rhs = number, symbol
    		print lhs # just a test
    	#def __repr__(lhs, rhs): //this is what I'll return later, when I get lhs and rhs to access correct information
    		#return lhs, rhs
     
    if __name__ == '__main__':
    	em = Particle("e-", -1, 0)
    	ep = Particle("e+", 1, 0)
    	p = Particle("p", 1, 1)
    	n = Particle("n", 0, 1)
    	neutrino = Particle("nu_e", 0, 0)
    	gamma = Particle("gamma", 0, 0)			 
    	print em, ep, p, n, neutrino, gamma
    	d = Nucleus("H", 1, 2)
    	li6 = Nucleus("li", 3, 6)
    	he4 = Nucleus("He", 2, 4)
    	print d
    	print li6
    	print he4
    	print Reaction((li6, d), (he4, he4))
    The problem is in the Reaction class. It should print out like this:

    (6)Li + (2)H -> (4)He + (4)He

    Right now its only giving me the following:

    e- e+ p n nu_e gamma
    (2)H
    (6)li
    (4)He
    (((4)He, (4)He), <__main__.React ion instance at 0x00C42670>) (((4)He, (4)He), <__main__.React ion instance at 0x00C42670>)
    <__main__.React ion instance at 0x00C42670>
    >>>

    The final one starting with (((4)He, (4)He), is the part I don't want and should look like the example I gave.

    So, I think I'm going the right direction but its printing the second particles twice, and not using the first particles at all. Plus its giving me the address in memory, and I most definitely don't want that. At first I thought it was inheritance, but I can see now that it isn't. The Nucleus prints the correct format for one particle, so I need to reuse that to make this class print out what I need. Can someone give me a nudge in the right direction, please?

    Thanks
  • bvdet
    Recognized Expert Specialist
    • Oct 2006
    • 2851

    #2
    You are mismatching your arguments:
    Code:
    class Reaction:
    	def __init__(self, lhs, rhs):
    		self.lhs = lhs
    		self.rhs = rhs
    Now self.lhs and self.rhs are tuples. To print the elements:
    Code:
    self.lhs[0], self.lhs[1], self.rhs[0], self.rhs[1]

    Comment

    • TMS
      New Member
      • Sep 2006
      • 119

      #3
      I'm getting an error message with that. Here is what I did (I had already figured out the self.lhs = lhs and I got it to print... but not right).

      Code:
      class Reaction:
      	def __init__(self, lhs, rhs):
      		self.lhs = lhs
      		self.rhs = rhs
      	def __repr__ (self): 
      		return self.lhs[0], "+", self.lhs[1], "->", self.rhs[0], "+", self.rhs[1]
      Here is the error:
      Traceback (most recent call last):
      File "C:\Python25\pa rt.py", line 44, in <module>
      print Reaction((li6, d), (he4, he4))
      TypeError: __str__ returned non-string (type tuple)

      But when I print from __init__ I get this:

      ((6)li, (2)h) ((4)he, (4)he)

      So, I am accessing it, its returning a tuple and I don't know how to fix it.

      :(

      Comment

      • ghostdog74
        Recognized Expert Contributor
        • Apr 2006
        • 511

        #4
        Originally posted by TMS
        I'm getting an error message with that. Here is what I did (I had already figured out the self.lhs = lhs and I got it to print... but not right).

        Code:
        class Reaction:
        	def __init__(self, lhs, rhs):
        		self.lhs = lhs
        		self.rhs = rhs
        	def __repr__ (self): 
        		return self.lhs[0], "+", self.lhs[1], "->", self.rhs[0], "+", self.rhs[1]
        Here is the error:
        Traceback (most recent call last):
        File "C:\Python25\pa rt.py", line 44, in <module>
        print Reaction((li6, d), (he4, he4))
        TypeError: __str__ returned non-string (type tuple)

        But when I print from __init__ I get this:

        ((6)li, (2)h) ((4)he, (4)he)

        So, I am accessing it, its returning a tuple and I don't know how to fix it.

        :(

        how about this
        Code:
        ....
        def __repr__ (self): 	
        	s = "%s+%s->%s+%s" %(self.lhs[0],self.lhs[1],self.rhs[0],self.rhs[1])
        	return s

        Comment

        • TMS
          New Member
          • Sep 2006
          • 119

          #5
          ah... thank you

          Comment

          • TMS
            New Member
            • Sep 2006
            • 119

            #6
            ok, new problem on this assignment.

            For me, this is rather complicated, so I will try to make it as simple as possible. I've gotten the reactor to take in an element, then add 2 elements 2 different ways. Now I need to get it to add 3 different elements. (not really add, just look as if it is adding). Here is my code:

            Code:
            """
            Assignment: Homework #6
            Create a class called Reaction, will have a left hand side and right hand side, specified by tuples
            containing one or more particles (including Nucleuses). The reaction taking place transofrms
            the particles on the left-hand side to the particles on the right hand side.
            """
            class Particle:
            	def __init__(self, symbol, charge, number):
            		self.symbol = symbol
            		self.charge = charge
            		self.number = number
             
            	def __add__(left, right):
            		"""
            		#2. Extend the Particle class to have the "+" operator acting on two particles
            		result in a tuple containing them, so that print Reaction(li6+d, he4 + he4) is
            		equivalent to print Reaction((li6, d), (he4, he4)), this uses class Reaction to print out
            		the correct format.
            		"""
            		return left, right
            	def __repr__(self):
            		return self.symbol
             
            class Nucleus(Particle):
            	def __repr__(self):
            		return "(%d)%s" % (self.number, self.symbol)
            class UnbalancedCharge:
            	pass #worry about this later
            class UnbalancedNumber:
            	pass #worry about this later
            class Reaction:
            	def __init__(self, lhs, rhs):
            		"""
            		Initialize the left hand side and right hand side so that print Reaction(li6, d)(he4, he4)
            		will produce (6)LI + (2)H -> (4)He + (4)He
            		"""
            		self.lhs = lhs
            		self.rhs = rhs
            	def __repr__ (self):
            		s = "%s+%s->%s+%s" % (self.lhs[0], self.lhs[1], self.rhs[0], self.rhs[1])
            		return s
            class chainReaction(Reaction):
            	def __init__(self, name):
            		self.name = name
            	def chain(self, lhsNet, rhsNet):
            		pass #combine
            	def __repr__ (self):
            		return "%s %s" % (self.name, "chain:" )
             
            if __name__ == '__main__':
            	em = Particle("e-", -1, 0)
            	ep = Particle("e+", 1, 0)
            	p = Particle("p", 1, 1)
            	n = Particle("n", 0, 1)
            	neutrino = Particle("nu_e", 0, 0)
            	gamma = Particle("gamma", 0, 0)			 
            	print em, ep, p, n, neutrino, gamma
            	d = Nucleus("h", 1, 2)
            	li6 = Nucleus("li", 3, 6)
            	he4 = Nucleus("he", 2, 4)
            	print d
            	print li6
            	print he4
            	print Reaction((li6, d), (he4, he4))
            	print Reaction(li6 + d, he4 + he4)
            	he3 = Nucleus("he", 2, 3)
            	chnPP = chainReaction("proton-proton (branch I)")
            	print chnPP
            	print Reaction(li6 + d + he4) #this one gives me trouble
            The last print request is the one I can't seem to figure out. I've tried re-writing the function that is called when I add 2 by adding middle, but it doesn't work. I mean, like this:

            Code:
             
            def __addMore__(left, right, middle):
            	return left, right, middle
            because it works so well for the one that 'adds' two, but it doesn't work. I need this because eventually I have to write a net reaction that combines reactions on the left side, then 'points' to the reactions on the right hand side. One of the reactions for the sun looks like this:

            Reaction(p + p, d + ep + neutrino, chnPP)

            which has a part with 2 elements, then 3, then the name of the reaction which I defined in a different class. I will do that later, for now I simply need to get the program to add three as the test shows on my code.

            Any ideas?

            Comment

            • bartonc
              Recognized Expert Expert
              • Sep 2006
              • 6478

              #7
              Originally posted by TMS
              ok, new problem on this assignment.

              For me, this is rather complicated, so I will try to make it as simple as possible. I've gotten the reactor to take in an element, then add 2 elements 2 different ways. Now I need to get it to add 3 different elements. (not really add, just look as if it is adding). Here is my code:

              Code:
              """
              Assignment: Homework #6
              Create a class called Reaction, will have a left hand side and right hand side, specified by tuples
              containing one or more particles (including Nucleuses). The reaction taking place transofrms
              the particles on the left-hand side to the particles on the right hand side.
              """
              class Particle:
              	def __init__(self, symbol, charge, number):
              		self.symbol = symbol
              		self.charge = charge
              		self.number = number
               
              	def __add__(left, right):
              		"""
              		#2. Extend the Particle class to have the "+" operator acting on two particles
              		result in a tuple containing them, so that print Reaction(li6+d, he4 + he4) is
              		equivalent to print Reaction((li6, d), (he4, he4)), this uses class Reaction to print out
              		the correct format.
              		"""
              		return left, right
              	def __repr__(self):
              		return self.symbol
               
              class Nucleus(Particle):
              	def __repr__(self):
              		return "(%d)%s" % (self.number, self.symbol)
              class UnbalancedCharge:
              	pass #worry about this later
              class UnbalancedNumber:
              	pass #worry about this later
              class Reaction:
              	def __init__(self, lhs, rhs):
              		"""
              		Initialize the left hand side and right hand side so that print Reaction(li6, d)(he4, he4)
              		will produce (6)LI + (2)H -> (4)He + (4)He
              		"""
              		self.lhs = lhs
              		self.rhs = rhs
              	def __repr__ (self):
              		s = "%s+%s->%s+%s" % (self.lhs[0], self.lhs[1], self.rhs[0], self.rhs[1])
              		return s
              class chainReaction(Reaction):
              	def __init__(self, name):
              		self.name = name
              	def chain(self, lhsNet, rhsNet):
              		pass #combine
              	def __repr__ (self):
              		return "%s %s" % (self.name, "chain:" )
               
              if __name__ == '__main__':
              	em = Particle("e-", -1, 0)
              	ep = Particle("e+", 1, 0)
              	p = Particle("p", 1, 1)
              	n = Particle("n", 0, 1)
              	neutrino = Particle("nu_e", 0, 0)
              	gamma = Particle("gamma", 0, 0)			 
              	print em, ep, p, n, neutrino, gamma
              	d = Nucleus("h", 1, 2)
              	li6 = Nucleus("li", 3, 6)
              	he4 = Nucleus("he", 2, 4)
              	print d
              	print li6
              	print he4
              	print Reaction((li6, d), (he4, he4))
              	print Reaction(li6 + d, he4 + he4)
              	he3 = Nucleus("he", 2, 3)
              	chnPP = chainReaction("proton-proton (branch I)")
              	print chnPP
              	print Reaction(li6 + d + he4) #this one gives me trouble
              The last print request is the one I can't seem to figure out. I've tried re-writing the function that is called when I add 2 by adding middle, but it doesn't work. I mean, like this:

              Code:
               
              def __addMore__(left, right, middle):
              	return left, right, middle
              because it works so well for the one that 'adds' two, but it doesn't work. I need this because eventually I have to write a net reaction that combines reactions on the left side, then 'points' to the reactions on the right hand side. One of the reactions for the sun looks like this:

              Reaction(p + p, d + ep + neutrino, chnPP)

              which has a part with 2 elements, then 3, then the name of the reaction which I defined in a different class. I will do that later, for now I simply need to get the program to add three as the test shows on my code.

              Any ideas?
              __add__() and all others with those names are internal to python and are called operator overloads (they let your code resond to operators ("+" in this case)). You don't get to addMore of them to the language. If your __add__() is working correctly, python will do the work: first evaluate d+ep, then add neutrino to the result.

              Comment

              • TMS
                New Member
                • Sep 2006
                • 119

                #8
                so maybe adding an if statement to the __add__ function? Because sometimes it takes two elements and sometimes 3. If so, I'll have to think for a bit how to logically make that work.

                tms

                Comment

                • bvdet
                  Recognized Expert Specialist
                  • Oct 2006
                  • 2851

                  #9
                  Originally posted by TMS
                  so maybe adding an if statement to the __add__ function? Because sometimes it takes two elements and sometimes 3. If so, I'll have to think for a bit how to logically make that work.

                  tms
                  Yep!
                  Code:
                  	def __add__(self, p2):
                  		"""
                  		#2. Extend the Particle class to have the "+" operator acting on two particles
                  		result in a tuple containing them, so that print Reaction(li6+d, he4 + he4) is
                  		equivalent to print Reaction((li6, d), (he4, he4)), this uses class Reaction to print out
                  		the correct format.
                  		"""
                  		if isinstance(p2, tuple):
                  			return (self,) + p2
                  		else:
                  			return self, p2
                  You will need to use parentheses such that you are adding two instances or one instance and one tuple.
                  Code:
                  	print li6+d
                  	print li6+(d+he4)
                  	print he4+(he4+(he4+(he4+(he4+he4))))
                  # Yields:
                  >>> ((6)Li, (2)H)
                  ((6)Li, (2)H, (4)He)
                  ((4)He, (4)He, (4)He, (4)He, (4)He, (4)He)
                  >>>
                  Not ideal but seems to work.

                  Comment

                  • bvdet
                    Recognized Expert Specialist
                    • Oct 2006
                    • 2851

                    #10
                    Originally posted by TMS
                    so maybe adding an if statement to the __add__ function? Because sometimes it takes two elements and sometimes 3. If so, I'll have to think for a bit how to logically make that work.

                    tms
                    Now you need to get a Reaction() instance to display properly. It only expects two elements on each side, so you need to build the return string allowing for the variable length of tuples on each side. Insead of me posting code, I think you can do it.

                    Comment

                    • TMS
                      New Member
                      • Sep 2006
                      • 119

                      #11
                      :)

                      I was also toying with __radd__ but couldn't really get that to work. I think I can figure it out from here. Thank you!

                      Comment

                      • bartonc
                        Recognized Expert Expert
                        • Sep 2006
                        • 6478

                        #12
                        Ok guys, it's time for me to rename this thread. Either of you have a preference?

                        Comment

                        • TMS
                          New Member
                          • Sep 2006
                          • 119

                          #13
                          yes, I was thinking it would be appropriate to rename it also. How about

                          overload __add__

                          or something similar?

                          Comment

                          • bartonc
                            Recognized Expert Expert
                            • Sep 2006
                            • 6478

                            #14
                            Originally posted by TMS
                            yes, I was thinking it would be appropriate to rename it also. How about

                            overload __add__

                            or something similar?
                            You got it! Thanks.

                            Comment

                            Working...