10 Replies - 557 Views - Last Post: 30 October 2017 - 10:34 PM Rate Topic: -----

#1 Frenchi33  Icon User is offline

  • D.I.C Head

Reputation: 1
  • View blog
  • Posts: 50
  • Joined: 20-November 16

How can I improve this program?

Posted 24 October 2017 - 04:10 PM

This is the description:

Write a class for linear equations. A generic linear equation is of the form
y = mx + b where m and b are constants.

Include the following methods:
a. __init__, __str__, __repr__.
B. value(x), which returns the value of the equation given x.
c. compose(linear_eq) that composes two linear equations. That is,
if y = x + 1 and z = 2a + 5, then y(z) = 2x + 6 and will be called as
y.compose(z). Note that the compose operation is not communitive.
d. __add__ returns the sum of two linear equations. That is,
if y = ax + b and z = cx + d, then y + z = (a + c)x + (b + d).

Include sample code that uses your class and demonstrates the use of all
methods as well as error handling.

Here's what I've put together:

class LinearEquation(object):
    def __init__(self, m, B)/>/>/>:
        self.m = float(m)
        self.b = float(B)/>/>/>

    def __str__(self):
        return "%.2fx + %.2f" % (self.m, self.B)/>/>/>

    def __repr__(self):
        return self.__str__()

    def value(self, x):
        return self.m * x + self.b

    def compose(self, linear_eq):
        return LinearEquation(self.m * linear_eq.m, \
                      self.m * linear_eq.b + self.B)/>/>/>

    def __add__(self, z):
        return LinearEquation(self.m + z.m, self.b + z.B)/>/>/>
# ---------------------------------main---------------------------------------
eq1 = LinearEquation(2, 3)
eq2 = LinearEquation(5, 6)

print("\nEquation 1: y =", eq1)
print("Equation 2: y =", eq2)

print("\nThe sum of the two equations is y =", eq1.__add__(eq2))


... and this is the output:

Equation 1: y = 2.00x + 3.00
Equation 2: y = 5.00x + 6.00

The sum of the two equations is y = 7.00x + 9.00

... so I guess it works, but what can I do to improve it? The only thing I haven't done from the description is Error handling. How would I implement that into the program? I assume in the __add__() method? Should I use try-except... or if-else? Any tips?

LOL I just noticed the face in the description! But I have one more question, should I change from "float" to "int" so I'm not getting decimal whole numbers?

This post has been edited by Frenchi33: 24 October 2017 - 04:24 PM


Is This A Good Question/Topic? 0
  • +

Replies To: How can I improve this program?

#2 Martyr2  Icon User is offline

  • Programming Theoretician
  • member icon

Reputation: 5074
  • View blog
  • Posts: 13,697
  • Joined: 18-April 07

Re: How can I improve this program?

Posted 24 October 2017 - 05:02 PM

If you are wanting to do error handling, that would be through the use of try-except, if-else is not exception handling and should never be used for handling errors. It is for flow control as they are known as flow control structures.

Now for the float vs int question, if you want to show integers (not decimals) then yes you can change the display to int. However, do keep in mind that int isn't going to round but instead just chop off the decimals. 1.6 converted to an int is 1, not 2. That may or may not be a problem if you want accurate answers.

But I found that your code isn't terribly long or complex there so not much simplification can be done other than using more descriptive variable names where possible. :)
Was This Post Helpful? 0
  • +
  • -

#3 Frenchi33  Icon User is offline

  • D.I.C Head

Reputation: 1
  • View blog
  • Posts: 50
  • Joined: 20-November 16

Re: How can I improve this program?

Posted 24 October 2017 - 08:44 PM

View PostMartyr2, on 24 October 2017 - 05:02 PM, said:

If you are wanting to do error handling, that would be through the use of try-except, if-else is not exception handling and should never be used for handling errors.


Is this the right way to implement it?

class LikeTerms(object):
    """ Combine like terms by adding two linear equations together. """
    def __init__(self, m, B)/>:
        self.m = float(m)
        self.b = float(B)/>

    def __str__(self):
        return "%.2fx + %.2f" % (self.m, self.B)/>/>

    def __repr__(self):
        return self.__str__()

    def value(self, x):
        return self.m * x + self.b

    def compose(self, linear_equation):
        return LikeTerms(self.m * linear_equation.m, \
                      self.m * linear_equation.b + self.B)/>

    def __add__(self, z):
        try:
            return LikeTerms(self.m + z.m, self.b + z.B)/>
        except TypeError as e:
            print("Error!", e)
            return None
# ---------------------------------main---------------------------------------
eq1 = LikeTerms(2, 3)
eq2 = LikeTerms(5, 6)

print("\nEquation 1: y =", eq1)
print("Equation 2: y =", eq2)

print("\nThe sum of the two equations is y =", eq1.__add__(eq2))


I also change the class name if that's a better name choice.

This post has been edited by Frenchi33: 24 October 2017 - 08:45 PM

Was This Post Helpful? 0
  • +
  • -

#4 Frenchi33  Icon User is offline

  • D.I.C Head

Reputation: 1
  • View blog
  • Posts: 50
  • Joined: 20-November 16

Re: How can I improve this program?

Posted 25 October 2017 - 03:58 PM

I just realized something, I'm not exactly sure what it's asking for in the description at part c.

It says:

"compose(linear_equation) that composes two linear equations. That is, if y = x + 1 and z = 2a + 5, then y(z) = 2x + 6 and will be called as y.compose(z). Note that the compose operation is not communitive."

What does it mean by compose? Also, I assume it has to do with composing the equations, but how does y = x + 1 and z = 2a + 5 make
y(z) = 2x + 6? I see the constants added together, but where did the "a" go?
Was This Post Helpful? 0
  • +
  • -

#5 Frenchi33  Icon User is offline

  • D.I.C Head

Reputation: 1
  • View blog
  • Posts: 50
  • Joined: 20-November 16

Re: How can I improve this program?

Posted 25 October 2017 - 04:06 PM

I'm not exactly sure what it wants me to do.

This post has been edited by Frenchi33: 25 October 2017 - 04:12 PM

Was This Post Helpful? 0
  • +
  • -

#6 ndc85430  Icon User is online

  • D.I.C Lover
  • member icon

Reputation: 590
  • View blog
  • Posts: 2,483
  • Joined: 13-June 14

Re: How can I improve this program?

Posted 27 October 2017 - 12:41 PM

I assume there's a typo in there and that it is just function composition, i.e.

z(a) = 2a + 5

y(x) = x + 1

=> y(z(a)) = (2a + 5) + 1 = 2a + 6,

where I've substituted the value of z(a) for x in the expression for y.

This post has been edited by ndc85430: 27 October 2017 - 12:48 PM

Was This Post Helpful? 1
  • +
  • -

#7 jon.kiparsky  Icon User is online

  • Chinga la migra
  • member icon


Reputation: 10686
  • View blog
  • Posts: 18,302
  • Joined: 19-March 11

Re: How can I improve this program?

Posted 27 October 2017 - 01:49 PM

    def compose(self, linear_equation):
        return LikeTerms(self.m * linear_equation.m, \
                      self.m * linear_equation.b + self.B)/>>


Two minor quibbles. First, the backslash continuation is not needed, since python expects a continuation if there's an unclosed paren.
Second, in a function like this I would like to call the other equation "other", to emphasize that we're dealing with two things that are of the same type. Then you'd have:

        return LikeTerms(self.m * other.m, 
                      self.m * other.b + self.B)/>>


which reads a bit nicer to me. But that's a matter of personal preference.

(In Java, where the current object is referred to as this I usually refer to the target object as that)

    def __add__(self, z):
        try:
            return LikeTerms(self.m + z.m, self.b + z.B)/>/>
        except TypeError as e:
            print("Error!", e)
            return None



It'd be better to throw this exception up to whoever is trying to add these equations so they can handle it as they see fit.

print("\nThe sum of the two equations is y =", eq1.__add__(eq2))


Since __add__ is a dunder method which allows you to write eq1 + eq2, you should write it that way.
Also, use string formatting here. Concatenation works but in general writing a format string is the write way to do this.

I would include examples that demonstrate more completely the code that you've written.

Quote

I also change the class name if that's a better name choice.


In my view, classes should be named for the thing the represent. LinearEquation would therefore be a better name than LikeTerms
Was This Post Helpful? 1
  • +
  • -

#8 forumer444  Icon User is offline

  • New D.I.C Head

Reputation: 1
  • View blog
  • Posts: 28
  • Joined: 19-September 17

Re: How can I improve this program?

Posted 28 October 2017 - 07:33 PM

Thanks, Jon.

Here's the updated code:

class LinearEquation(object):
    def __init__(self, m, B)/>:
        # print("in constructor")
        self.m = float(m)
        self.b = float(B)/>:

    def __str__(self):
        # print("in str")
        # return "%2fx + %.2f" % (self.m, self.B)/> # optional return
        return "{}x + {}".format(self.m, self.B)/>

    def __repr__(self):
        # print("in repr")
        return self.__str__()

    def value(self, x):
        return self.m * x + self.b

    def compose(self, other):
        return LinearEquation(self.m * other.m, 
                              self.m * other.b + self.B)/>

    def __add__(self, z):
        return LinearEquation(self.m + z.m, self.b + z.B)/>
# -----------------------main-----------------------------
try:
    # create instances of class LinearEq()
    equation_y = LinearEquation(1, 1) # name error
    equation_z = LinearEquation(2, 5) # possibility

    # display instances
    print("\nLinear Equation 1: y =", equation_y)
    print("Linear Equation 2: z =", equation_z)

    # get user input for x values
    y_x = float(input("Enter an x value for Equation 1: ")) # value error
    z_x = float(input("Enter an x value for Equation 2: ")) # possibility

    # display results
    # print equation values given x
    print("\ny =", equation_y.value(y_x), "if x =", y_x) # y = m(x) + b
    print("z =", equation_z.value(z_x), "if x =", z_x) # z = m(x) + b
    
    # compose equations
    print("\ny(z) =", equation_y.compose(equation_z))
    print("z(y) =", equation_z.compose(equation_y))
    
    # add like terms
    print("\ny + z =", equation_y + equation_z)

except ValueError:
    print("\nSorry, there was a value error.")
except NameError:
    print("\nSorry, there was a name error.")



Why am I getting a capital B followed by a "/>"?

This post has been edited by forumer444: 28 October 2017 - 07:31 PM

Was This Post Helpful? 0
  • +
  • -

#9 ndc85430  Icon User is online

  • D.I.C Lover
  • member icon

Reputation: 590
  • View blog
  • Posts: 2,483
  • Joined: 13-June 14

Re: How can I improve this program?

Posted 28 October 2017 - 09:17 PM

The forum is slightly broken, so don't worry about that.
Was This Post Helpful? 0
  • +
  • -

#10 jon.kiparsky  Icon User is online

  • Chinga la migra
  • member icon


Reputation: 10686
  • View blog
  • Posts: 18,302
  • Joined: 19-March 11

Re: How can I improve this program?

Posted 28 October 2017 - 10:09 PM

Looks good. There's one or two things I'd look at in terms of exceptions. First of all, it's best practice to limit the scope of a try block to just the line or lines that might trigger the exceptional condition. This allows you to handle the exception more precisely. Also, it'd be more usual to use a try block in a function, to ensure that exceptional conditions are handled correctly. In your case, you're just wrapping a bunch of lines in a try which shows that you're able to handle them, and that's fine, but more typically you might have a function which uses your LinearEquation class to do some work, for example to create LinearEquations based on data provided by the user in a data file of some sort and do some sort of composition and addition of them. In that case, you'd like to be sure that a typo on line 47 of the data file doesn't blow up the process.

In order to facilitate this, your LinearEquation class might do some validation of the input to the __init__ function, and throw an informative exception if either of the parameters cannot be case to a float. Traditionally this would be an exception that you define for this purpose, extending the built-in Exception class. Might be called an InvalidParameterException or something like that - the name is only useful in so far as it's informative to the developer using the class. Then the developer using your class can practice a bit of defensive programming by wrapping the line that creates each instance of your class in a try block and dealing with invalid data in whatever way they prefer (perhaps ignoring that line and continuing, perhaps reporting on the failure, perhaps aborting the whole process and informing the user where the failure was found, whatever they like - it's up to them how they use your code!)

So they might write something like

def read_linear_equations(filename):
  csv_reader = _create_csv_reader(filename) # ignoring details of csv handling!
  equations = []
  errors = []
  for row_number, row in enumerate(csv_reader):
    try:
      equations.append(LinearEquation(row[0], row[1])
    except InvalidParameterException e:
      errors.append((row_number, row)) # hang on to the error rows for later
  return (equations, errors) # calling function can report out the errors - returning tuple in this way is not great style!



There are a few constructs here that I'm using like the enumerate function which might not be familiar to you, but you should be able to work out what I'm doing here. If I've read your class correctly, this should give the user a list of LinearEquation instances which are safe to work with.
Was This Post Helpful? 0
  • +
  • -

#11 Frenchi33  Icon User is offline

  • D.I.C Head

Reputation: 1
  • View blog
  • Posts: 50
  • Joined: 20-November 16

Re: How can I improve this program?

Posted 30 October 2017 - 10:34 PM

Well I already turned in my assignment the way it was with a bunch of lines inside a try block, but I'm confused on how I would use try/except in the methods, and on which ones? I tried afterwards and wasn't sure exactly what I was doing. So I tried this for example:

class LinearEquation(object):
    def __init__(self, m, B)/>:
        try:
            # print("in constructor")
            self.m = float(m)
            self.b = float(B)/>
        except ValueError as e:
            print(e)

    def __str__(self):
        # print("in str")
        # return "%2fx + %.2f" % (self.m, self.B)/> # optional return
        return "{}x + {}".format(self.m, self.B)/>

    def __repr__(self):
        # print("in repr")
        return self.__str__()

    def value(self, x):
        return self.m * x + self.b

    def compose(self, other):
        return LinearEquation(self.m * other.m, 
                              self.m * other.b + self.B)/>

    def __add__(self, z):
        return LinearEquation(self.m + z.m, self.b + z.B)/>
# ----------------------------------------------------------
# *** description example executed ***
# create instances
equation_y = LinearEquation(1, f)
equation_z = LinearEquation(2, 5)

# display instances
print("Equation 1: y =", equation_y)
print("Equation 2: z =", equation_z)

# user input for x values
x1 = float(input("Enter an x value for equation 1: "))
x2 = float(input("Enter an x value for equation 2: "))
print()

# *** display calculated results ***
# title
print("'equation values'")
# display equation values
print("y = to", equation_y.value(x1), "if x =", x1)
print("z = to", equation_z.value(x2), "if x =", x2)
print()

# title
print("'composed equations'")
# display composed equations
print("y(z) =", equation_y.compose(equation_z))
print("z(y) =", equation_z.compose(equation_y))
print()

# title
print("'equation sums'")
# display sum
print("y + z =", equation_y + equation_z)


So for example, if I had a 'f' in the parameter when creating the equation instances, I'd get: "ValueError: could not convert string to float: 'f'", before it even gets to my __init__() method. So it's not like the try/except inside the constructor method is being used, so why would I put try/except inside the method if I could catch the Value Error outside? If I catch it outside, then that would ensure that no value errors could possibly be inside the __init__() method, right?

Sorry if that's confusing. I just wanna figure this out.
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1