Exercises

  1. 10.1 (What’s Wrong with This Code?) What is wrong with the code in the following IPython session?

    In [1]: try:
       ...:     raise RuntimeError()
       ...: except Exception:
       ...:     print('An Exception occurred')
       ...: except RuntimeError:
       ...:     print('A RuntimeError occurred')
       ...:
    An Exception occurred
  2. 10.2 (Account Class with Read-Only Properties) Modify Section 10.2.2’s Account class to provide read-only properties for the name and balance. Rename the class attributes with single leading underscores. Re-execute Section 10.2.2’s IPython session to test your updated class. To show that name and balance are read-only, try to assign new values to them.

  3. 10.3 (Time Class Enhancement) Modify Section 10.4.2’s Time class to provide a read-only property universal_str that returns a string representation of a Time in 24-hour clock format with two digits each for the hour, minute and second, as in '22:30:00' (for 10:30 PM) or '06:30:00' (for 6:30 AM). Test your new read-only property.

  4. 10.4 (Modifying the Internal Data Representation of a Class) Section 10.4.2’s Time class represents the time as three integer values. Modify the class to store the time as the total number of seconds since midnight. Replace the _hour, _minute and _second attributes with one _total_seconds attribute. Modify the bodies of the hour, minute and second properties’ methods to get and set _total_seconds. Re-execute Section 10.4’s IPython session using the modified Time class to show that the updated class Time is interchangeable with the original one.

  5. 10.5 (Duck Typing) Recall that with duck typing, objects of unrelated classes can respond to the same method calls if they implement those methods. In Section 10.8, you created a list containing a CommissionEmployee and a SalariedCommissionEmployee. Then, you iterated through it, displaying each employee’s string representation and earnings. Create a class SalariedEmployee for an employee that gets paid a fixed weekly salary. Do not inherit from CommissionEmployee or SalariedCommissionEmployee. In class SalariedEmployee, override method __repr__ and provide an earnings method. Demonstrate duck typing by creating an object of your class, adding it to the list at the end of Section 10.8, then executing the loop to show that it properly processes objects of all three classes.

  6. 10.6 (Composition: A Circle “Has a” Point at Its Center) A circle has a point at its center. Create a class Point that represents an (x-y) coordinate pair and provides x and y read-write properties for the attributes _x and _y. Include __init__ and __repr__ methods, and a move method that receives x- and y-coordinate values and sets the Point’s new location. Create a class Circle that has as its attributes _radius and _point (a Point that represents the Circle’s center location). Include __init__ and __repr__ methods, and a move method that receives x- and y-coordinate values and sets a new location for the Circle by calling the composed Point object’s move method. Test your Circle class by creating a Circle object, displaying its string representation, moving the Circle and displaying its string representation again.

  7. 10.7 (Manipulating Dates and Times with Module datetime) The Python Standard Library’s datetime module contains a datetime class for manipulating dates and times. The class provides various overloaded operators. Research class datetime’s capabilities, then perform the following tasks:

    1. Get the current date and time and store it in variable x.

    2. Repeat Part (a) and store the result in variable y.

    3. Display each datetime object.

    4. Display each datetime object’s data attributes individually.

    5. Use the comparison operators to compare the two datetime objects.

    6. Calculate the difference between y and x.

  8. 10.8 (Converting Data Class Objects to Tuples and Dictionaries) In some cases, you might want to treat data class objects as tuples or dictionaries. The dataclasses module provides functions astuple and asdict for this purpose. Research these functions, then create an object of this chapter’s Card data class and use these functions to convert the Card to a tuple and a dictionary. Display the results.

  9. 10.9 (Square Class) Write a class that implements a Square shape. The class should contain a side property. Provide an __init__ method that takes the side length as an argument. Also, provide the following read-only properties:

    1. perimeter returns 4 × side.

    2. area returns side × side.

    3. diagonal returns the square root of the expression (2 × side2).

    The perimeter, area and diagonal should not have corresponding data attributes; rather, they should use side in calculations that return the desired values. Create a Square object and display its side, perimeter, area and diagonal properties’ values.

  10. 10.10 (Invoice Class) Create a class called Invoice that a hardware store might use to represent an invoice for an item sold at the store. An Invoice should include four pieces of information as data attributes—a part number (a string), a part description (a string), a quantity of the item being purchased (an int) and a price per item (a Decimal). Your class should have an __init__ method that initializes the four data attributes. Provide a property for each data attribute. The quantity and price per item should each be non-negative—use validation in the properties for these data attributes to ensure that they remain valid. Provide a calculate_invoice method that returns the invoice amount (that is, multiplies the quantity by the price per item). Demonstrate class Invoice’s capabilities.

  11. 10.11 (Class Fraction) The Python Standard Library module fractions provides a Fraction class that stores the numerator and denominator of a fraction, such as:

    2 divided by 4

    Research Fraction’s capabilities, then demonstrate:

    1. Adding two Fractions.

    2. Subtracting two Fractions.

    3. Multiplying two Fractions.

    4. Dividing two Fractions.

    5. Printing Fractions in the form a/b, where a is the numerator and b is the denominator.

    6. Converting Fractions to floating-point numbers with built-in function float.

  12. 10.12 (Built-in Type complex) Python supports complex numbers with the built-in type complex. Research complex’s capabilities, then demonstrate:

    1. Adding two complex numbers.

    2. Subtracting two complex numbers.

    3. Printing complex numbers.

    4. Getting the real and imaginary parts of complex numbers.

  13. 10.13 (doctest) Create a script containing the following maximum function:

    def maximum(value1, value2, value3):
        """Return the maximum of three values."""
        max_value = value1
    
        if value2 > max_value:
            max_value = value2
    
        if value3 > max_value:
            max_value = value3
    
        return max_value

    Modify the function’s docstring to define tests for calling function maximum with three ints, three floats and three strings. For each type, provide three tests—one with the largest value as the first argument, one with the largest value as the second argument, one with the largest value as the third argument. Use doctest to run your tests and confirm that all execute correctly. Next, modify the maximum function to use < operators rather than > operators. Run your tests again to see which tests fail.

  14. 10.14 (Creating an Account Data Class Dynamically) The dataclasses module’s make_dataclass function creates a data class dynamically from a list of strings that represent the data class’s attributes. Research function make_dataclass, then use it to generate an Account class from the following list of strings:

    ['account', 'name', 'balance']

    Create objects of the new Account class, then display their string representations and compare the objects with the == and != operators.

  15. 10.15 (Immutable Data Class Objects) Built-in types int, float, str and tuple are immutable. Data classes can simulate immutability by designating that objects of the class should be “frozen” after they’re created. Client code cannot assign values to the attributes of a frozen object. Research “frozen” data classes, then reimplement this chapter’s Complex class as a “frozen” data class. Show that you cannot modify a Complex object after you create it.

  16. 10.16 (Account Inheritance Hierarchy) Create an inheritance hierarchy that a bank might use to represent customer bank accounts. All customers at this bank can deposit money into their accounts and withdraw money from their accounts. More specific types of accounts also exist. Savings accounts, for instance, earn interest on the money they hold. Checking accounts, on the other hand, don’t earn interest and charge a fee per transaction.

    Start with class Account from this chapter and create two subclasses SavingsAccount and CheckingAccount. A SavingsAccount should also include a data attribute indicating the interest rate. A SavingsAccount’s calculate_interest method should return the Decimal result of multiplying the interest rate by the account balance. SavingsAccount should inherit methods deposit and withdraw without redefining them.

    A CheckingAccount should include a Decimal data attribute that represents the fee charged per transaction. Class CheckingAccount should override methods deposit and withdraw so that they subtract the fee from the account balance whenever either transaction is performed successfully. CheckingAccount’s versions of these methods should invoke the base-class Account versions to update the account balance. CheckingAccount’s withdraw method should charge a fee only if money is withdrawn (that is, the withdrawal amount does not exceed the account balance).

    Create objects of each class and tests their methods. Add interest to the SavingsAccount object by invoking its calculate_interest method, then passing the returned interest amount to the object’s deposit method.

  17. 10.17 (Nested Functions and Namespaces) Section 10.15 discussed namespaces and how Python uses them to determine which identifiers are in scope. We also mentioned the LEGB (local, enclosing, global, built-in) rule for the order in which Python searches for identifiers in namespaces. For each of the print function calls in the following IPython session, list the namespaces that Python searches for print’s argument:

    In [1]: z = 'global z'
    
    In [2]: def print_variables():
       ...:     y = 'local y in print_variables'
       ...:     print(y)
       ...:     print(z)
       ...:     def nested_function():
       ...:         x = 'x in nested function'
       ...:         print(x)
       ...:         print(y)
       ...:         print(z)
       ...:     nested_function()
       ...:
    
    In [3]: print_variables()
    local y in print_variables
    global z
    x in nested function
    local y in print_variables
    global z
  18. 10.18 (Intro to Data Science: Time Series) Reimplement the Intro to Data Science section’s study using the Los Angeles Average January High Temperatures for 1985 through 2018, which can be found in the file ave_hi_la_jan_1895-2018.csv located in the ch10 examples folder. How does the Los Angeles temperature trend compare to that of New York City?

  19. 10.19 (Project: Static Code Analysis with Prospector and MyPy) In Exercise 3.24, you used the prospector static code analysis tool to check your code for common errors and suggested improvements. The prospector tool includes support for checking variable annotations with the MyPy static code analysis tool. Research MyPy online. Write a script that creates objects of this chapter’s Card data class. In the script, assign integers to a Card’s face and suit string attributes. Then, use MyPy to analyze the script and see the warning messages that MyPy produces. For instructions on using MyPy with prospector, see

    https://github.com/PyCQA/prospector/blob/master/docs/supported_tools.rst
  20. 10.20 (Project: Solitaire) Using classes Card and DeckOfCards from this chapter’s examples, implement your favorite solitaire card game.

  21. 10.21 (Project: Blackjack) Using the DeckOfCards class from this chapter, create a simple Blackjack game. The rules of the game are as follows:

    • Two cards each are dealt to the dealer and the player. The player’s cards are dealt face up. Only one of the dealer’s cards is dealt face up.

    • Each card has a value. A card numbered 2 through 10 is worth its face value. Jacks, queens and kings each count as 10. Aces can count as 1 or 11—whichever value is more beneficial to the player (as we’ll soon see).

    • If the sum of the player’s first two cards is 21 (that is, the player was dealt a card valued at 10 and an ace, which counts as 11 in this situation), the player has “blackjack” and immediately wins the game—if the dealer does not also have blackjack, which would result in a “push” (or tie).

    • Otherwise, the player can begin taking additional cards one at a time. These cards are dealt face up, and the player decides when to stop taking cards. If the player “busts” (that is, the sum of the player’s cards exceeds 21), the game is over and the player loses. When the player is satisfied with the current set of cards, the player “stands” (that is, stops taking cards), and the dealer’s hidden card is revealed.

    • If the dealer’s total is 16 or less, the dealer must take another card; otherwise, the dealer must stand. The dealer must continue taking cards until the sum of the cards is greater than or equal to 17. If the dealer exceeds 21, the player wins. Otherwise, the hand with the higher point total wins. If the dealer and the player have the same point total, the game is a “push,” and no one wins.

    An ace’s value for a dealer depends on the dealer’s other card(s) and the casino’s house rules. A dealer typically must hit for totals of 16 or less and must stand for 17 or more. For a “soft 17”—a total of 17 with one ace counted as 11—some casinos require the dealer to hit and some require the dealer to stand (we require the dealer to stand). Such a hand is known as a “soft 17” because taking another card cannot bust the hand.

    Enable a player to interact with the game using the keyboard—'H' means hit (take another card and 'S' means stand (do not take another card). Display the dealer’s and player’s hands as card images using Matplotlib, as we did in this chapter.

  22. 10.22 (Project: Card Class with Overloaded Comparison Operators) Modify class Card to support the comparison operators, so you can determine whether one Card is less than, equal to or greater than another. Investigate the functools module’s total_ordering decorator. If your class is preceded by @total_ordering and defines methods __eq__ and __lt__ (for the < operator), the remaining comparison methods for <=, > and >= are autogenerated.

  23. 10.23 (Project: Poker) Exercises 5.25–5.26 asked you to create functions for comparing poker hands. Develop equivalent features for use with this chapter’s DeckOfCards class. Develop a new class called Hand that represents a five-card poker hand. Use operator overloading to enable two Hands to be compared with the comparison operators. Use your new capabilities in a simple poker game script.

  24. 10.24 (Project: PyDealer Library) We demonstrated basic card shuffling and dealing in this chapter, but many card games require significant additional capabilities. As is often the case in Python, libraries already exist that can help you build more substantial card games. One such library is PyDealer. Research this library’s extensive capabilities, then use it to implement your favorite card game.

  25. 10.25 (Project: Enumerations) Many programming languages provide a language element called an enumeration for creating sets of named constants. Often, these are used to make code more readable. The Python Standard Library’s enum module enables you to emulate this concept by creating subclasses of the Enum base class. Investigate the enum module’s capabilities, then create subclasses of Enum that represent card faces and card suits. Modify class Card to use these to represent the face and suit as enum constants rather than as strings.

  26. 10.26 (Software Engineering with Abstract Classes and Abstract Methods) When we think of a class, we assume that programs use it to create objects. Sometimes, it’s useful to declare classes for which you never instantiate objects, because in some way they are incomplete. As you’ll see, such classes can help you engineer effective inheritance hierarchies.

    Concrete Classes—Consider Section 10.7’s Shape hierarchy. If Circle, Square and Triangle objects all have draw methods, its reasonable to expect that calling draw on a Circle will display a Circle, calling draw on a Square will display a Square and calling draw on a Triangle will display a Triangle. Objects of each class know all the details of the specific shapes to draw. Classes that provide (or inherit) implementations of every method they define and that can be used to create objects are called concrete classes.

    Abstract Classes—Now, let’s consider class TwoDimensionalShape in the Shape hierarchy’s second level. If we were to create a TwoDimensionalShape object and call its draw method, class TwoDimensionalShape knows that all two-dimensional shapes are drawable, but it does not know what specific two-dimensional shape to draw—there are many! So it does not make sense for TwoDimensionalShape to fully implement a draw method. A method that is defined in a given class, but for which you cannot provide an implementation is called an abstract method. Any class with an abstract method has a “hole”—the incomplete method implementation—and is called an abstract class. TypeErrors occur when you try to create objects of abstract classes. In the Shape hierarchy, classes Shape, TwoDimensionalShape and ThreeDimensionalShape all are abstract classes. They all know that shapes should be drawable, but do not know what specific shape to draw. Abstract base classes are too general to create real objects.

    Inheriting a Common Design—An abstract class’s purpose is to provide a base class from which subclasses can inherit a common design, such as a specific set of attributes and methods. So, such classes often are called abstract base classes. In the Shape hierarchy, subclasses inherit from the abstract base class Shape the notion of what it means to be a Shape—that is, common properties, such as location and color, and common behaviors, such as draw, move and resize.

    Polymorphic Employee Payroll System—Now, let’s develop an Employee class hierarchy that begins with an abstract class, then use polymorphism to perform payroll calculations for objects of two concrete subclasses. Consider the following problem statement:

    • A company pays its employees weekly. The employees are of two types. Salaried employees are paid a fixed weekly salary regardless of the number of hours worked. Hourly employees are paid by the hour and receive overtime pay (1.5 times their hourly salary rate) for all hours worked in excess of 40 hours. The company wants to implement an app that performs its payroll calculations polymorphically.

    Employee Hierarchy Class Diagram—The following diagram shows the Employee hierarchy. Abstract class Employee represents the general concept of an employee. Subclasses SalariedEmployee and HourlyEmployee inherit from Employee. Employee is italicized by convention to indicate that it’s an abstract class. Concrete class names are not italicized:

    A hierarchy shows that salaried and hourly employees are both employees.

    Abstract Base Class EmployeeThe Python Standard Library’s abc (abstract base class) module helps you define abstract classes by inheriting from the module’s ABC class. Your abstract base class Employee class should declare the methods and properties that all employees should have. Each employee, regardless of the way his or her earnings are calculated, has a first name, a last name and a Social Security number. Also, every employee should have an earnings method, but the specific calculation depends on the employee’s type, so you’ll make earnings an abstract method that the subclasses must override. Your Employee class should contain:

    • An __init__ method that initializes the first name, last name and Social Security number data attributes.

    • Read-only properties for the first name, last name and Social Security number data attributes.

    • An abstract method earnings preceded by the abc module’s @abstractmethod decorator. Concrete subclasses must implement this method. The Python documentation says you should raise a NotImplementedError in abstract methods.26

    • A __repr__ method that returns a string containing the first name, last name and Social Security number of the employee.

    Concrete Subclass SalariedEmployeeThis Employee subclass should override earnings to return a SalariedEmployee’s weekly salary. The class also should include:

    • An __init__ method that initializes the first name, last name, Social Security number and weekly salary data attributes. The first three of these should be initialized by calling base class Employee’s __init__ method.

    • A read-write weekly_salary property in which the setter ensures that the property is always non-negative.

    • A __repr__ method that returns a string starting with 'SalariedEmployee:' and followed by all the information about a SalariedEmployee. This overridden method should call Employee’s version.

    Concrete Subclass HourlyEmployeeThis Employee subclass should override earnings to return an HourlyEmployee’s earnings, based on the hours worked and wage per hour. The class also should include:

    • An __init__ method to initialize the first name, last name, Social Security number, hours and wages data attributes. The first name, last name and Social Security number should be initialized by calling base class Employee’s __init__ method.

    • Read-write hours and wages properties in which the setters ensure that the hours are in range (0–168) and wage per hour is always non-negative.

    • A __repr__ method that returns a string starting with 'HourlyEmployee:' and followed by all the information about a HourlyEmployee. This overridden method should call Employee’s version.

    Testing Your Classes—In an IPython session, test your hierarchy:

    • Import the classes Employee, SalariedEmployee and HourlyEmployee.

    • Attempt to create an Employee object to see the TypeError that occurs and prove that you cannot create an object of an abstract class.

    • Assign objects of the concrete classes SalariedEmployee and HourlyEmployee to variables, then display each employee’s string representation and earnings.

    • Place the objects into a list, then iterate through the list and polymorphically process each object, displaying its string representation and earnings.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.225.35.81