Every problem in the chapter beside the book’s answer, a chapter at a time as you scroll.

Chapter 13: Inheritance

33 problems · 0 figures

Concepts in Practice 13.1.1 §13.1 source ↗

What is the relationship between a Doughnut class and a Pastry class?
  1. a.
    is-a
  2. b.
    has-a

Answer

A. is-a
A doughnut is a type of pastry, so Doughnut inherits from Pastry.

Concepts in Practice 13.1.2 §13.1 source ↗

What is the relationship between a Kitchen class and a Freezer class?
  1. a.
    is-a
  2. b.
    has-a

Answer

B. has-a
A kitchen has a freezer, so a Kitchen class would contain a Freezer instance. A has-a relationship is also called a composition.

Concepts in Practice 13.1.3 §13.1 source ↗

A goalkeeper is a player. Goalkeeper is a ______class. Player is a ______class.
  1. a.
    super; sub
  2. b.
    sub; super

Answer

B. sub; super
The Goalkeeper class inherits from the Player class.

Concepts in Practice 13.1.4 §13.1 source ↗

How is a Daisy class that inherits from the Plant class defined?
  1. a.
    class Plant(Daisy):
  2. b.
    class Daisy(Plant):
  3. c.
    class Daisy:
    class Plant:

Answer

B.
class Daisy(Plant):
The subclass name is followed by the superclass name in parentheses.

Concepts in Practice 13.1.5 §13.1 source ↗

Suppose a CarryOn class is inherited from a Luggage class. How is a CarryOn instance created?
  1. a.
    small_bag = CarryOn()
  2. b.
    small_bag = Luggage(CarryOn)
  3. c.
    small_bag = CarryOn(Luggage)

Answer

A. small_bag = CarryOn()
Deriving CarryOn from Luggage is specified in CarryOn's class definition. Ex: class CarryOn(Luggage): . Instances of a subclass, like CarryOn, are created like other classes and do not require the base class name.

Concepts in Practice 13.1.6 §13.1 source ↗

Given the following SuperClass and SubClass, which of the following can an instance of SubClass access?
class SuperClass():
  def func_1(self):
    print('Superclass function')

class SubClass(SuperClass):
  def func_2(self):
    print('Subclass function')
  1. a.
    func_1() only
  2. b.
    func_2() only
  3. c.
    func_1() and func_2()

Answer

C. func_1() and func_2()
A SubClass instance has access to func_1(), inherited from SuperClass, as well as to func_2(), a SubClass method.

Concepts in Practice 13.1.7 §13.1 source ↗

Given the following SuperClass and SubClass, which of the following can an instance of SuperClass access?
class SuperClass():
  def func_1(self):
    print('Superclass function')

class SubClass(SuperClass):
  def func_2(self):
    print('Subclass function')
  1. a.
    func_1() only
  2. b.
    func_2() only
  3. c.
    func_1() and func_2()

Answer

A. func_1() only
A SuperClass instance has access to SuperClass's func_1() but doesn't have access to anything in SubClass, including func_2().

Concepts in Practice 13.2.1 §13.2 source ↗

Consider the Employee and Developer example above. What is the value of dev_1.e_id?
  1. a.
    1
  2. b.
    2
  3. c.
    Error
Video · Defining a simple subclass in the book ↗

Answer

B. 2
dev_1 is the second Employee created. So dev_1 is the second object to call Employee.__init__(), and dev_1.e_id is assigned with 2 .

Concepts in Practice 13.2.2 §13.2 source ↗

Consider the following example. Line 13 executes and SubClass() is called. Which line does control flow move to?
 1  class SuperClass:
 2    def __init__(self):
 3      self.feat_1 = 1
 4      self.feat_2 = ""
 5  
 6    def bc_display(self):
 7      print(f"Superclass: {self.feat_2}")
 8  
 9  class SubClass(SuperClass):
10    def dc_display(self):
11      print(f"Subclass: {self.feat_2}")
12  
13  dc_1 = SubClass()
  1. a.
    2
  2. b.
    10
  3. c.
    Error

Answer

A. 2
SubClass's __init__() is not explicitly defined, so SuperClass's __init__() is executed.

Concepts in Practice 13.2.3 §13.2 source ↗

Consider the following example. Which instance attribute(s) does dc_1 have?
class SuperClass:
  def __init__(self):
    self.feat_1 = 1
    self.feat_2 = ""

  def bc_display(self):
    print(f"Superclass: {self.feat_2}")

class SubClass(SuperClass):
  def dc_display(self):
    print(f"Subclass: {self.feat_2}")

dc_1 = SubClass()
  1. a.
    feat_2
  2. b.
    feat_1 and feat_2
  3. c.
    None

Answer

B. feat_1 and feat_2
dc_1 inherits feat_1 and feat_2 from SuperClass.

Concepts in Practice 13.2.4 §13.2 source ↗

Consider the Employee and Developer example code:

class Employee:
  count = 0
  def __init__(self):
    Employee.count += 1
    self.e_id = Employee.count
    self.hire_year = 2023

  def emp_display(self):
    print(f"Employee {self.e_id} hired in {self.hire_year}")

class Developer(Employee):
  def __init__(self):
    Employee.count += 1
    self.e_id = Employee.count
    self.hire_year = 2023
    self.lang_xp = ["Python", "C++", "Java"]

  def dev_display(self):
    print(f"Proficient in {self.lang_xp}")

emp_1 = Employee()
dev_1 = Developer()
What would be the output of dev_1.dev_display()?
  1. a.
    Employee 2 hired in 2023
  2. b.
    Proficient in ['Python', 'C++', 'Java']
  3. c.
    Error

Answer

B. Proficient in ['Python', 'C++', 'Java']
dev_display() is a Developer method that accesses dev_1's instance attribute lang_xp.

Concepts in Practice 13.2.5 §13.2 source ↗

Consider the Employee and Developer example code:

class Employee:
  count = 0
  def __init__(self):
    Employee.count += 1
    self.e_id = Employee.count
    self.hire_year = 2023

  def emp_display(self):
    print(f"Employee {self.e_id} hired in {self.hire_year}")

class Developer(Employee):
  def __init__(self):
    Employee.count += 1
    self.e_id = Employee.count
    self.hire_year = 2023
    self.lang_xp = ["Python", "C++", "Java"]

  def dev_display(self):
    print(f"Proficient in {self.lang_xp}")

emp_1 = Employee()
dev_1 = Developer()
What would be the output of emp_1.dev_display()?
  1. a.
    Employee 1 hired in 2023
  2. b.
    Proficient in ['Python', 'C++', 'Java']
  3. c.
    Error

Answer

C. Error
dev_display() is a Developer method. emp_1 is not a Developer instance, so emp_1 cannot access dev_display().

Concepts in Practice 13.2.6 §13.2 source ↗

Consider the Employee and Developer example code:

class Employee:
  count = 0
  def __init__(self):
    Employee.count += 1
    self.e_id = Employee.count
    self.hire_year = 2023

  def emp_display(self):
    print(f"Employee {self.e_id} hired in {self.hire_year}")

class Developer(Employee):
  def __init__(self):
    Employee.count += 1
    self.e_id = Employee.count
    self.hire_year = 2023
    self.lang_xp = ["Python", "C++", "Java"]

  def dev_display(self):
    print(f"Proficient in {self.lang_xp}")

emp_1 = Employee()
dev_1 = Developer()
Suppose dev_display() should be modified to display the developer's ID along with their proficiencies. Ex: dev_1.dev_display() would output Employee 2 proficient in ['Python', 'C++', 'Java']. Which is the appropriate new print() call in dev_display()?
  1. a.
    print(f"Employee {self.e_id} proficient in {self.lang_xp}")
  2. b.
    print(f"Employee {self.Employee.e_id} proficient in {self.lang_xp}")
  3. c.
    print(f"Employee 2 proficient in {self.lang_xp}")

Answer

A. print(f"Employee {self.e_id} proficient in {self.lang_xp}")
Instance attributes inherited from Employee, the superclass, are accessed the same way as the subclass Developer's instance attributes.

Concepts in Practice 13.3.1 §13.3 source ↗

Suppose a programmer inherits the ContractTax class from class Tax and wants to override Tax's calc_tax(). What should the programmer do?
  1. a.
    Define another calc_tax() method in Tax.
  2. b.
    Define a calc_tax() method in ContractTax.
  3. c.
    Define a function that takes a ContractTax instance.

Answer

B. Define a calc_tax() method in ContractTax.
Overriding involves defining a subclass method that has the same name as the superclass method.

Concepts in Practice 13.3.2 §13.3 source ↗

Which is the error in the program that attempts to override calc_tax() for ContractTaxDE?
class Tax:
  def calc_tax(self):
    print('Calculating tax')

class ContractTax(Tax):
  def calc_tax(self):
    print('Calculating contract tax')

class ContractTaxDE(ContractTax):
  def calc_tax():
    print('Calculating German contract tax')

my_tax = ContractTaxDE()
my_tax.calc_tax()
  1. a.
    ContractTaxDE must inherit from Tax, not ContractTax.
  2. b.
    ContractTaxDE's definition of calc_tax() is missing a parameter.
  3. c.
    ContractTaxDE can't override calc_tax() since ContractTax already has.

Answer

B. ContractTaxDE's definition of calc_tax() is missing a parameter.
The self parameter is missing from the overridden method's definition.

Concepts in Practice 13.3.3 §13.3 source ↗

The following program doesn't override calc_tax(). Why?
class Tax:
  def calc_tax(self):
    print('Calculating tax')
    total = 0 # To replace with calculation
    return total

class ContractTax:
  def calc_tax(self):
    print('Calculating contract tax')
    total = 0 # To replace with calculation
    return total

my_tax = ContractTax()
my_tax.calc_tax()
  1. a.
    An overridden method cannot return a value.
  2. b.
    Tax doesn't specify calc_tax() can be overridden.
  3. c.
    ContractTax isn't inherited from Tax.

Answer

C. ContractTax isn't inherited from Tax.
The class definition doesn't indicate inheritance. The definition should be class ContractTax(Tax):.

Concepts in Practice 13.3.4 §13.3 source ↗

Consider the following program.

 1  class Polygon:
 2    def __init__(self, num_sides=3):
 3      self.num_sides = num_sides
 4  
 5  class Rectangle(Polygon):
 6    def __init__(self, ln=1, wd=1):
 7      super().__init__(4)
 8      self.length = ln
 9      self.width = wd
10  
11  class Square(Rectangle):
12    def __init__(self, side=1):
13      super().__init__(side, side)
14      self.side = side
15  
16  sq_1 = Square(5)
17  print(sq_1.num_sides)
Line 16 executes and Square's __init__() is called on line 12. Line 13 executes and the superclass's __init__() is called. Which line does control flow move to next?
  1. a.
    2
  2. b.
    6
  3. c.
    14

Answer

B. 6
Square's superclass is Rectangle. Rectangle's __init__() is called on line 6.

Concepts in Practice 13.3.5 §13.3 source ↗

Consider the following program.

 1  class Polygon:
 2    def __init__(self, num_sides=3):
 3      self.num_sides = num_sides
 4  
 5  class Rectangle(Polygon):
 6    def __init__(self, ln=1, wd=1):
 7      super().__init__(4)
 8      self.length = ln
 9      self.width = wd
10  
11  class Square(Rectangle):
12    def __init__(self, side=1):
13      super().__init__(side, side)
14      self.side = side
15  
16  sq_1 = Square(5)
17  print(sq_1.num_sides)
The next line executes. Which line does control flow move to next?
  1. a.
    2
  2. b.
    6
  3. c.
    14

Answer

A. 2
super().__init__(4) calls the __init__() of Rectangle's superclass, Polygon. Control moves to line 3, and num_sides is initialized with 4.

Concepts in Practice 13.3.6 §13.3 source ↗

Consider the following program.

 1  class Polygon:
 2    def __init__(self, num_sides=3):
 3      self.num_sides = num_sides
 4  
 5  class Rectangle(Polygon):
 6    def __init__(self, ln=1, wd=1):
 7      super().__init__(4)
 8      self.length = ln
 9      self.width = wd
10  
11  class Square(Rectangle):
12    def __init__(self, side=1):
13      super().__init__(side, side)
14      self.side = side
15  
16  sq_1 = Square(5)
17  print(sq_1.num_sides)
The method call returns. Lines 8 and 9 execute to initialize length and width, and Rectangle's __init__() returns. Which line does control flow move to next?
  1. a.
    12
  2. b.
    14
  3. c.
    17

Answer

B. 14
The instance attribute side is initialized with 5.

Concepts in Practice 13.3.7 §13.3 source ↗

Consider the following program.

 1  class Polygon:
 2    def __init__(self, num_sides=3):
 3      self.num_sides = num_sides
 4  
 5  class Rectangle(Polygon):
 6    def __init__(self, ln=1, wd=1):
 7      super().__init__(4)
 8      self.length = ln
 9      self.width = wd
10  
11  class Square(Rectangle):
12    def __init__(self, side=1):
13      super().__init__(side, side)
14      self.side = side
15  
16  sq_1 = Square(5)
17  print(sq_1.num_sides)
Square's __init__() returns and control flow moves to line 17. What is the output?
  1. a.
    3
  2. b.
    4
  3. c.
    5

Answer

B. 4
Rectangle's __init__() always calls Polygon's __init__() with num_sides=4.

Concepts in Practice 13.3.8 §13.3 source ↗

Consider the example. What is the output?
class Polygon:
  def print_type(self):
    print("Polygon type")

class Rectangle(Polygon):
  def print_type(self):
    print("Rectangle type")

class Square(Rectangle):
  def print_type(self):
    print("Square type")

sq_1 = Square()
sq_1.print_type()
  1. a.
    Polygon type
  2. b.
    Rectangle type
  3. c.
    Square type

Answer

C. Square type
Polymorphism allows print_type() to be overridden in subclasses of Polygon.

Concepts in Practice 13.3.9 §13.3 source ↗

Which is an example of polymorphism for the multiplication operator?
  1. a.
    x = 3 * 4
    y = 3 * "la"
  2. b.
    x = 3 * 4
    y = str(x)
  3. c.
    x = 3 * 4
    y = x * x

Answer

A.
x = 3 * 4
y = 3 * "la"
The * operator can be used with integer operands as well as strings and other types.

Concepts in Practice 13.4.1 §13.4 source ↗

Which is an example of hierarchical inheritance?
  1. a.
    Class B inherits from Class A
    Class C inherits from Class A
  2. b.
    Class B inherits from Class A
    Class C inherits from Class B
  3. c.
    Class B inherits from Class A
    Class C inherits from Class D

Answer

A. Class B inherits from Class A
Class C inherits from Class A
Class A is the superclass for Class B and Class C.

Concepts in Practice 13.4.2 §13.4 source ↗

Which group of classes is hierarchical inheritance appropriate for?
  1. a.
    Cat, Dog, Bird
  2. b.
    Employee, Developer, SalesRep
  3. c.
    Dessert, BakedGood, ApplePie

Answer

B. Employee, Developer, SalesRep
Employee would be an appropriate superclass for Developer and SalesRep. Developer and SalesRep are not directly related.

Concepts in Practice 13.4.3 §13.4 source ↗

Consider the program:

class A:
  def __init__(self, a_attr=0):
    self.a_attr = a_attr

class B(A):
  def __init__(self, a_attr=0, b_attr=0):
    super().__init__(a_attr)
    self.b_attr = b_attr

class C(A):
  def __init__(self, a_attr=0, c_attr=0):
    super().__init__(a_attr)
    self.c_attr = c_attr

class D(B):
  def __init__(self, a_attr=0, b_attr=0, d_attr=0):
    super().__init__(a_attr, b_attr)
    self.d_attr = d_attr

b_inst = B(2)
c_inst = C(c_attr=4)
d_inst = D(6, 7)
What is the value of b_inst.b_attr?
  1. a.
    0
  2. b.
    2
  3. c.
    Error

Answer

A. 0
B(2) resolves to B(2, 0), as b_attr has a default value of 0 . a_attr is assigned with 2 .

Concepts in Practice 13.4.4 §13.4 source ↗

Consider the program:

class A:
  def __init__(self, a_attr=0):
    self.a_attr = a_attr

class B(A):
  def __init__(self, a_attr=0, b_attr=0):
    super().__init__(a_attr)
    self.b_attr = b_attr

class C(A):
  def __init__(self, a_attr=0, c_attr=0):
    super().__init__(a_attr)
    self.c_attr = c_attr

class D(B):
  def __init__(self, a_attr=0, b_attr=0, d_attr=0):
    super().__init__(a_attr, b_attr)
    self.d_attr = d_attr

b_inst = B(2)
c_inst = C(c_attr=4)
d_inst = D(6, 7)
Which attributes does c_inst have access to?
  1. a.
    a_attr
  2. b.
    a_attr, c_attr
  3. c.
    c_attr

Answer

B. a_attr, c_attr
c_inst has access to C's instance attribute, c_attr, as well the inherited attribute from A, a_attr.

Concepts in Practice 13.4.5 §13.4 source ↗

Consider the program:

class A:
  def __init__(self, a_attr=0):
    self.a_attr = a_attr

class B(A):
  def __init__(self, a_attr=0, b_attr=0):
    super().__init__(a_attr)
    self.b_attr = b_attr

class C(A):
  def __init__(self, a_attr=0, c_attr=0):
    super().__init__(a_attr)
    self.c_attr = c_attr

class D(B):
  def __init__(self, a_attr=0, b_attr=0, d_attr=0):
    super().__init__(a_attr, b_attr)
    self.d_attr = d_attr

b_inst = B(2)
c_inst = C(c_attr=4)
d_inst = D(6, 7)
Which attributes does d_inst have access to?
  1. a.
    b_attr, d_attr
  2. b.
    a_attr, b_attr, d_attr
  3. c.
    d_attr

Answer

B. a_attr, b_attr, d_attr
D, which inherits from B, so d_inst inherits b_attr. B also inherits from A, so d_inst inherits d_attr.

Concepts in Practice 13.5.1 §13.5 source ↗

Consider the program:

class A:
  def __init__(self, a_attr=2):
    self.a_attr = a_attr

class B:
  def __init__(self, b_attr=4):
    self.b_attr = b_attr

class C(A, B):
  def __init__(self, a_attr=5, b_attr=10, c_attr=20):
    A.__init__(self, a_attr)
    B.__init__(self, b_attr)
    self.c_attr = c_attr

b_inst = B(2)
c_inst = C(1, 2)
What is the value of c_inst.a_attr?
  1. a.
    1
  2. b.
    5
  3. c.
    Error

Answer

A. 1
1 is the argument passed to C's __init__() for a_attr.

Concepts in Practice 13.5.2 §13.5 source ↗

Consider the program:

class A:
  def __init__(self, a_attr=2):
    self.a_attr = a_attr

class B:
  def __init__(self, b_attr=4):
    self.b_attr = b_attr

class C(A, B):
  def __init__(self, a_attr=5, b_attr=10, c_attr=20):
    A.__init__(self, a_attr)
    B.__init__(self, b_attr)
    self.c_attr = c_attr

b_inst = B(2)
c_inst = C(1, 2)
What is the value of c_inst.c_attr?
  1. a.
    2
  2. b.
    20
  3. c.
    Error

Answer

B. 20
An argument is not passed to C's __init__() for c_attr, so c_attr is assigned with the default value, 20 .

Concepts in Practice 13.5.3 §13.5 source ↗

Consider the program:

class A:
  def __init__(self, a_attr=2):
    self.a_attr = a_attr

class B:
  def __init__(self, b_attr=4):
    self.b_attr = b_attr

class C(A, B):
  def __init__(self, a_attr=5, b_attr=10, c_attr=20):
    A.__init__(self, a_attr)
    B.__init__(self, b_attr)
    self.c_attr = c_attr

b_inst = B(2)
c_inst = C(1, 2)
What is the value of b_inst.a_attr?
  1. a.
    2
  2. b.
    4
  3. c.
    Error

Answer

A. 2
2 maps to b_attr in B' s __init__().

Concepts in Practice 13.5.4 §13.5 source ↗

The following code isn't correct, as not all plants are carnivorous. Follow the programmer through the programmer's edits to improve the program. Note: Rose, Pitcher, and VenusFlyTrap represent plants that all photosynthesize. Pitcher and VenusFlyTrap represent plants that are also carnivorous and can eat.

A pass statement is used in Python to indicate that code is to be written later and prevents certain errors that would result if no code was written or a comment was used instead.

class Plant:
  def photosynth(self):
    print("Photosynthesizing")

  def eat(self):
    print("Eating")

class Rose(Plant):
  pass

class Pitcher(Plant):
  pass

class VenusFlyTrap(Plant):
  pass
Which edit is appropriate?
  1. a.
    Move eat() to a different class.
  2. b.
    Remove Plant as a superclass.

Answer

A. Move eat() to a different class.
eat() only applies to carnivorous plants, which Pitcher and VenusFlyTrap represent.

Concepts in Practice 13.5.5 §13.5 source ↗

The following code isn't correct, as not all plants are carnivorous. Follow the programmer through the programmer's edits to improve the program. Note: Rose, Pitcher, and VenusFlyTrap represent plants that all photosynthesize. Pitcher and VenusFlyTrap represent plants that are also carnivorous and can eat.

A pass statement is used in Python to indicate that code is to be written later and prevents certain errors that would result if no code was written or a comment was used instead.

class Plant:
  def photosynth(self):
    print("Photosynthesizing")

  def eat(self):
    print("Eating")

class Rose(Plant):
  pass

class Pitcher(Plant):
  pass

class VenusFlyTrap(Plant):
  pass
The programmer edits the code as follows. How can the program be improved?
class Plant:
  def photosynth(self):
    print("Photosynthesizing")

class Rose(Plant):
  pass

class Pitcher(Plant):
  def eat(self):
    print("Eating")

class VenusFlyTrap(Plant)
  def eat(self):
    print("Eating")
  1. a.
    Move photosynth() into Rose.
  2. b.
    Remove redundancy of eat().

Answer

B. Remove redundancy of eat().
eat() can be moved into a mixin class included in Pitcher's and VenusFlyTrap's inheritance list.

Concepts in Practice 13.5.6 §13.5 source ↗

The following code isn't correct, as not all plants are carnivorous. Follow the programmer through the programmer's edits to improve the program. Note: Rose, Pitcher, and VenusFlyTrap represent plants that all photosynthesize. Pitcher and VenusFlyTrap represent plants that are also carnivorous and can eat.

A pass statement is used in Python to indicate that code is to be written later and prevents certain errors that would result if no code was written or a comment was used instead.

class Plant:
  def photosynth(self):
    print("Photosynthesizing")

  def eat(self):
    print("Eating")

class Rose(Plant):
  pass

class Pitcher(Plant):
  pass

class VenusFlyTrap(Plant):
  pass
The programmer edits the code to create a mixin class containing eat(). Which class name, replacing X, is most appropriate for the mixin?
class Plant:
  def photosynth(self):
    print("Photosynthesizing")

class X:
  def eat(self):
    print("Eating")

class Rose(Plant):
  pass

class Pitcher(Plant, X):
  pass

class VenusFlyTrap(Plant, X)
  pass
  1. a.
    CarnivClass
  2. b.
    CarnivMixin

Answer

B. CarnivMixin
Good practice is to have a mixin class name end in "Mixin" to identify the class's purpose. The final implementation is:
class Plant:
  def photosynth(self):
    print("Photosynthesizing")

class CarnivMixin:
  def eat(self):
    print("Eating")

class Rose(Plant):
  pass

class Pitcher(Plant, CarnivMixin):
  pass

class VenusFlyTrap(Plant, CarnivMixin)
  pass

Loading chapter 14…

Problems and answers are adapted from Introduction to Python Programming by Udayan Das, Aubrey Lawson, Chris Mayfield and Narges Norouzi, OpenStax, and are used under the CC BY-NC-SA 4.0 licence. Access for free at https://openstax.org/books/introduction-python-programming/pages/1-introduction. Illustrations: Copyright Rice University, OpenStax, under CC BY-NC-SA 4.0 license. This adaptation is released under the same licence, is non-commercial, and is neither affiliated with nor endorsed by OpenStax or Rice University.