Attribute access

13.2 Attribute access

Learning objectives

By the end of this section you should be able to

  • Implement a subclass that accesses inherited attributes from the superclass.
  • Write a subclass's __init__() that inherits superclass instance attributes and creates new instance attributes.

Creating a simple subclass

Subclasses have access to the attributes inherited from the superclass. When the subclass's __init__() isn't explicitly defined, the superclass's __init__() method is called. Accessing both types of attributes uses the same syntax.

Checkpoint

Defining a simple subclass

Concepts in Practice

Using simple subclasses

1.
Consider the Employee and Developer example above. What is the value of dev_1.e_id?
  1. 1
  2. 2
  3. Error
2.
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. 2
  2. 10
  3. Error
3.
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. feat_2
  2. feat_1 and feat_2
  3. None

Using __init__() to create and inherit instance attributes

A programmer often wants a subclass to have new instance attributes as well as those inherited from the superclass. Explicitly defining a subclass's __init__() involves defining instance attributes and assigning instance attributes inherited from the superclass.

Checkpoint

Defining __init__() in a subclass

Concepts in Practice

Accessing a subclass's attributes

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()
4.
What would be the output of dev_1.dev_display()?
  1. Employee 2 hired in 2023
  2. Proficient in ['Python', 'C++', 'Java']
  3. Error
5.
What would be the output of emp_1.dev_display()?
  1. Employee 1 hired in 2023
  2. Proficient in ['Python', 'C++', 'Java']
  3. Error
6.
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. print(f"Employee {self.e_id} proficient in {self.lang_xp}")
  2. print(f"Employee {self.Employee.e_id} proficient in {self.lang_xp}")
  3. print(f"Employee 2 proficient in {self.lang_xp}")

Try It

Creating a subclass with an instance attribute

Given a class Dessert, create a class, Cupcake, inherited from Dessert. Cupcake class methods:

  • __init__(self): initializes inherited instance attribute ingredients with ["butter", "sugar", "eggs", "flour"], and initializes instance attribute frosting with "buttercream"
  • display(self): prints a cupcake's ingredients and frosting

Then call the display() method on a new Cupcake object. The output should match:

    Made with ["butter", "sugar", "eggs", "flour"] and topped with buttercream frosting