abstraction case study fractions
play

Abstraction Case Study: Fractions class Fraction(object): Want to - PowerPoint PPT Presentation

Module 23 Abstraction Case Study: Fractions class Fraction(object): Want to add a new type """Instance is a fraction n/d""" Values are fractions: , # INSTANCE ATTRIBUTES: Operations are standard #


  1. Module 23 Abstraction

  2. Case Study: Fractions class Fraction(object): • Want to add a new type """Instance is a fraction n/d""" § Values are fractions: ½ , ¾ # INSTANCE ATTRIBUTES: § Operations are standard # _numerator: an int multiply, divide, etc. # _denominator: an int > 0 § Example : ½ * ¾ = ⅜ • Can do this with a class def __init__(self,n=0,d=1): § Values are fraction objects """Init: makes a Fraction""" § Operations are methods self._numerator = n self._denominator = d • Example : frac1.py

  3. Case Study: Fractions class Fraction(object): • Want to add a new type """Instance is a fraction n/d""" § Values are fractions: ½ , ¾ # INSTANCE ATTRIBUTES: § Operations are standard Reminder : Hide # _numerator: an int multiply, divide, etc. attributes, use # _denominator: an int > 0 § Example : ½ * ¾ = ⅜ getters/setters • Can do this with a class def __init__(self,n=0,d=1): § Values are fraction objects """Init: makes a Fraction""" § Operations are methods self._numerator = n self._denominator = d • Example : frac1.py

  4. Problem: Doing Math is Unwieldy What We Want What We Get 1 2 + 1 3 + 1 4 ∗ 5 >>> p = Fraction(1,2) >>> q = Fraction(1,3) 4 >>> r = Fraction(1,4) >>> s = Fraction(5,4) >>> (p.add(q.add(r))).mult(s) This is confusing!

  5. Problem: Doing Math is Unwieldy What We Want What We Get 1 2 + 1 3 + 1 4 ∗ 5 >>> p = Fraction(1,2) >>> q = Fraction(1,3) 4 >>> r = Fraction(1,4) >>> s = Fraction(5,4) Why not use the >>> (p.add(q.add(r))).mult(s) standard Python math operations? This is confusing!

  6. Abstraction • Goal: Hide unimportant details from user § Replace unfamiliar with the familiar § Focus on the core functionality of the type • Data encapsulation is one part of it § Hide direct access to the attributes § Only allow getters and setters • But also involves operator overloading § Replace method calls with operators § Make class feel like a built-in type

  7. Operator Overloading • Many operators in Python a special symbols § + , - , / , * , ** for mathematics § == , != , < , > for comparisons • The meaning of these symbols depends on type § 1 + 2 vs 'Hello' + 'World' § 1 < 2 vs 'Hello' < 'World' • Our new type might want to use these symbols § We overload them to support our new type

  8. Special Methods in Python class Point3(object): • Have seen three so far """Instances are points in 3D space""" § __init__ for initializer … § __str__ for str() def __init__(self,x=0,y=0,z=0): § __repr__ for repr() """Initializer: makes new Point3""" • Start/end with 2 underscores … § This is standard in Python def __str__(self,q): § Used in all special methods """Returns: string with contents""” § Also for special attributes … • We can overload operators def __repr__(self,q): § Give new meaning to +, *, - """Returns: unambiguous string""” …

  9. Returning to Fractions What We Want Operator Overloading 1 2 + 1 3 + 1 4 ∗ 5 • Python has methods that correspond to built-in ops 4 § __ add__ corresponds to + § __mul__ corresponds to * § __eq__ corresponds to == Why not use the § Not implemented by default standard Python • To overload operators you math operations? implement these methods

  10. Operator Overloading: Multiplication class Fraction(object): >>> p = Fraction(1,2) """Instance is a fraction n/d""" >>> q = Fraction(3,4) # _numerator: an int >>> r = p*q # _denominator: an int > 0 def __mul__(self,q): Python """Returns: Product of self, q converts to Makes a new Fraction; does not modify contents of self or q >>> r = p.__mul__(q) Precondition: q a Fraction""" assert type(q) == Fraction Operator overloading uses top= self._numerator*q._numerator bot= self._denominator*q._denominator method in object on left. return Fraction(top,bot)

  11. Operator Overloading: Addition class Fraction(object): >>> p = Fraction(1,2) """Instance is a fraction n/d""” >>> q = Fraction(3,4) # _numerator: an int >>> r = p+q # _denominator: an int > 0 def __add__(self,q): Python """Returns: Sum of self, q converts to Makes a new Fraction Precondition: q a Fraction""" >>> r = p.__add__(q) assert type(q) == Fraction bot= self._denominator*q._denominator Operator overloading uses top= (self._numerator*q._denominator+ self._denominator*q._numerator) method in object on left. return Fraction(top,bot)

  12. Comparing Objects for Equality class Fraction(object): • Earlier in course, we saw == """Instance is a fraction n/d""" compare object contents # _numerator: an int § This is not the default # _denominator: an int > 0 § Default : folder names • Must implement __eq__ def __eq__(self,q): """Returns: True if self, q equal, § Operator overloading! False if not, or q not a Fraction""" § Not limited to simple if type(q) != Fraction: attribute comparison return False § Ex : cross multiplying left = self._numerator*q._denominator rght = self._denominator*q._numerator 4 1 2 4 return left == rght 2 4

  13. is Versus == • p is q evaluates to False • p == q evaluates to True § Compares folder names § But only because method __eq__ compares contents § Cannot change this id2 id2 id3 id3 p q Point Point x 2.2 x 2.2 y 5.4 y 5.4 z 6.7 z 6.7 Always use (x is None) not (x == None)

  14. Recall: Overloading Multiplication class Fraction(object): >>> p = Fraction(1,2) """Instance is a fraction n/d""" >>> q = 2 # an int # _numerator: an int >>> r = p*q # _denominator: an int > 0 def __mul__(self,q): Python """Returns: Product of self, q converts to Makes a new Fraction; does not modify contents of self or q >>> r = p.__mul__(q) # ERROR Precondition: q a Fraction""" assert type(q) == Fraction Can only multiply fractions. top = self._numerator*q._numerator bot= self._denominator*q._denominator But ints “make sense” too. return Fraction(top,bot)

  15. Solution: Look at Argument Type class Fraction(object): • Overloading use left type … § p*q => p.__mul__(q) def __mul__(self,q): § Done for us automatically """Returns: Product of self, q Precondition: q a Fraction or int""" § Looks in class definition if type(q) == Fraction: • What about type on right ? return self._mulFrac(q) § Have to handle ourselves elif type(q) == int: return self._mulInt(q) • Can implement with ifs … § Write helper for each type def _mulInt(self,q): # Hidden method return Fraction(self._numerator*q, § Check type in method self._denominator) § Send to appropriate helper

  16. A Better Multiplication class Fraction(object): >>> p = Fraction(1,2) … >>> q = 2 # an int def __mul__(self,q): >>> r = p*q """Returns: Product of self, q Precondition: q a Fraction or int""" Python if type(q) == Fraction: converts to return self._mulFrac(q) elif type(q) == int: return self._mulInt(q) >>> r = p.__mul__(q) # OK! … def _mulInt(self,q): # Hidden method See frac3.py for a full return Fraction(self._numerator*q, example of this method self._denominator)

  17. What Do We Get This Time? class Fraction(object): >>> p = Fraction(1,2) … >>> q = 2 # an int def __mul__(self,q): >>> r = q*p """Returns: Product of self, q Precondition: q a Fraction or int""" if type(q) == Fraction: A: Fraction(2,2) return self._mulFrac(q) elif type(q) == int: B: Fraction(1,1) return self._mulInt(q) C: Fraction(2,4) … D: Error def _mulInt(self,q): # Hidden method return Fraction(self._numerator*q, E: I don’t know self._denominator)

  18. What Do We Get This Time? class Fraction(object): >>> p = Fraction(1,2) … >>> q = 2 # an int def __mul__(self,q): >>> r = q*p """Returns: Product of self, q Precondition: q a Fraction or int""" if type(q) == Fraction: Meaning determined by left. A: Fraction(2,2) return self._mulFrac(q) Variable q stores an int . elif type(q) == int: B: Fraction(1,1) return self._mulInt(q) C: Fraction(2,4) … D: Error CORRECT def _mulInt(self,q): # Hidden method return Fraction(self._numerator*q, E: I don’t know self._denominator)

  19. The Python Data Model http://docs.python.org/3/reference/datamodel.html

  20. We Have Come Full Circle • On the first day, saw that a type is both § a set of values , and § the operations on them • In Python, all values are objects § Everything has a folder in the heap § Just ignore it for immutable, basic types • In Python, all operations are methods § Each operator has a double-underscore helper § Looks at type of object on left to process

Download Presentation
Download Policy: The content available on the website is offered to you 'AS IS' for your personal information and use only. It cannot be commercialized, licensed, or distributed on other websites without prior consent from the author. To download a presentation, simply click this link. If you encounter any difficulties during the download process, it's possible that the publisher has removed the file from their server.

Recommend


More recommend