SICP-Notes-Lecture 13 Inheritance

Lecture 13 Inheritance

These are my notes for SICP(Structure and Interpretation of Computer Programs). Hope they’ll be of some help to you.

Methods and Functions

Python distinguishes between:

  • Functions, which we have been creating since the beginning of the course, and
  • Bound Methods, which couple together a function and the object on which that method will be invoked

Object + Function = Bound Method

>>> type(Account.deposit)
<class 'function'>
>>> type(tom_account.deposit)
<class 'method'>

>>> Account.deposit(tom_account, 1001) #Function: all arguments within parentheses
1001
>>> tom_account.deposit(1004) #Method: One object before the dot and other arguments whthin parentheses
2005

Python Object System

  • Functions are objects.
  • Bound methods are also objects: a function that has its first parameter “self” already bound to an instance
  • Dot expressions evaluate to bound methods for class attributes that are functions <instance>.<method_name>

Looking Up Attributes by Name

<expression>.<name>

To evaluate a dot expression:

  1. Evaluate the expression to the left of the dot, which yields the object of the dot expression
  2. name is matched against the instance attributes of that object; if an attribute with that name exists, its value is returned
  3. If not, name is looked up in the class, which yields a class attribute value
  4. That value is returned unless it is a function, in which case a bound method is returned instead

Class attributes are “shared” across all instances of a class because they are attributes of the class, not the instance.

Assignment to Attributes

Assignment statements with a dot expression on their left-hand side affect attributes for the object of that dot expression

  • If the object is an instance, then assignment sets an instance attribute
  • If the object is a class, then assignment sets a class attribute

tom_account.interest = 0.08

tom_account evaluates to an object, but the name ‘interest’ is not looked up.

Attribute assignment statement adds or modifies the attribute named ‘interest’ of tom_account

Inheritance

  • Inheritance is a technique for relating classes together

  • A common use: Two similar classes differ in their degree of specialization

  • The specialized class may have the same attributes as the general class, along with some special-case behavior

class <name>(<Base Class>):

<suite>

  • Conceptually, the new subclass inherits attributes of its base class

  • The subclass may override certain inherited attributes

  • Using inheritance, we implement a subclass by specifying its differences from the base class.

Inheritance Example

A CheckingAccount is a specialized type of Account

>>> ch = CheckingAccount
>>> ch.interest #Lower interest rate for checking accounts
0.01
>>> ch.deposit(20) #Deposits are the same
20
>>> ch.withdraw(5) #Withdrawals incur a $1 fee
14

Most behavior is shared with the base class Account

class CheckingAccount(Account):
    """A bank account that charges for withdrawls."""
    withdraw_fee = 1
    interest = 0.01
    def withdraw(self, amount):
        return super().withdraw(amount + self.withdraw_fee)
    #or
    	return Account.withdraw(self, amount + self.withdraw_fee)
Looking Up Attribute Names on Classes

Base class attributes aren’t copied into subclasses!

To look up a name in a class:

  1. If it names an attribute in the class, return the attribute value.
  2. Otherwise, look up the name in the base class, if there is one.
>>> ch = CheckingAccount('Tom') # Calls Account.__init__
>>> ch.interest #Found in CheckingAccount
0.01
>>> ch.deposit(20) #Found in Account
20
>>> ch.withdraw(5) #Found in CheckingAccount
14

Object-Oriented Design

Designing for Inheritance
  • Don’t repeat yourself; use existing implementations
  • Attributes that have been overridden are still accessible via class objects
  • Look up attributes on instances whenever possible
class CheckingAccount(Account):
    """A bank account that charges for """
    withdraw_fee = 1
    interest = 0.01
    def withdraw(self, amount):
        return Account.withdraw(self, amount + self.withdraw_fee)
               #Attribute look-up on base class 
               #Preferred to CheckingAccount.withdraw_fee to allow for specialized accounts.

Assume in the future, a subclass GreenCheckingAccount whose interest is 0.01 but withdraw_fee is only 0.23

Inheritance: Use it Carefully

Inheritance helps code reuse but NOT for code reuse!

  • Disadvantages of inheritance
    • Breaks encapsulation
      • Inheritance forces the developer of the subclass to know about the internals of the superclass
    • Unnecessary cost for inheritance maintenance
Composition

Colloquially, composition means

If you want to reuse some behavior, put that behavior in a class, create an object of that class, include it as an attribute, and call its methods when the behavior is needed.

  • Composition does not break encapsulation, and does not affect the types(all public interfaces remain unchanged)
  • No need to involve in possibly complex hierarchy, and easy to understand and implement
Inheritance vs Composition

Guidance to choose inheritance or composition

  • By conceptual difference
    • Inheritance represents “is-a” relationship
      • e.g. A checking account is a specific type of account.
    • Composition represents “has-a” relationhip
      • e.g. a bank has a collection of bank accounts it manages
  • By practical need
    • If type B wants to expose all public public methods of type A (B can be used wherever A is expected), favors inheritance
    • If type B needs only parts of behaviors exposed by type A, favors composition

Implementing composition means we need to wrap the delegation logic (delegated to the composed object) into certain methods, in which case inheritance’s “direct reuse” seems more convenient.

Do we have some approach to somewhat take the advantage of both inheritance and composition?

Mixin

Mixin is a class that contains methods for use by other classes without having to be the parent class of those other classes, and without having to use delegation to a composed object.

  • Mixin is usually considered as “included” rather than “inherited”
  • But unlike composition (as also an “included” approach), the mixin-ed methods appear to be inherited(no object delegation)
  • Unlike Python, some languages such as Ruby and Scala, has language support to enforce to enforce the syntax/semantics of Mixin
    • Mixin is called module in Ruby, and trait in Scala
  • Mixin is usually considered as a mean for multiple inheritance

Multiple Inheritance

class SavingAccount(Account):
    deposit_fee = 2
    def deposit(self, amount):
        return Account.deposit(self, amount - self.deposit_fee)
  • A class may inherit from multiple base classes in Python

  • CleverBank marketing executive has an idea:

    • Low interest rate of 1%
    • A $1 fee for withdrawals
    • A $2 fee for deposits
    • A free dollar when you open your account
class CleverAccount(CheckingAccount, SavingAccount):
    def __init__(self, account_holder):
        self.holder = account_holder
        self.balance = 1 #A free dollar!
>>> tom = CleverAccount('Tom')
>>> tom.balance #Instance attribute
1
>>> tom.deposit(20) #SavingAccount
19
>>> tem.withdraw(5)
13
Diamond Problem
  • Method Resolution Order(MRO)?
  • C3 Linearization Algorithm for method resolution while doing multiple inheritance
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值