Welcome to Programming Languages...

Preview:

Citation preview

Welcome to Programming Languages (ITP20005)

• lab08 - OOP• Due is 09:59, Nov. 25, 2014 (One week from today)• lab08.pdf (No template file provided)• 3.5 points (2~6: 0.5 point each, 7: 1.0 point)

In the beginning God created the heavens and the earth.

ITP 20005 Programming LanguagesChapter 2 Building Abstractions with Data

Major references: 1. Structure and Interpretation of Computer Programs(SICP) by Abelson and Sussman, MIT

Composing Programs by John DeNero, Google2. MITx OPENCOURSEWARE(OCW) 6.00 SC Lecture 3. UC Berkley CS61A Lecture 4. Python, Wikipedia and many on-line resources.Prof. Youngsup Kim, idebtor@handong.edu, 2014 Programming Languages, CSEE Dept., Handong Global University

5. Object-Oriented Programming 1. Classes2. Object3. Attributes4. Methods5. Inheritance

4

Object

Object-Oriented Programming

Classes

instance 1instance 2instance 3……

method Amethod Bmethod C

……

attribute aattribute battribute c

……

Review

5

Terminology: Attributes, Functions, and Methods

• All objects have attributes, which are name-value pairs.

• Classes are objects too, so they have attributes.

• Instance attributes: attributes of instance objects.

• Class attributes: attributes of class objects.

Terminology:

ClassAttributes

FunctionsMethods

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>

6

Inheritance

everywhere…everything…except…

God created man in his own image, in the image of God he created him;

Genesis 1:27 f

7

Inheritance

• Inheritance is a method 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.

• Conceptually, the new subclass "shares" attributes of its base class.

class <Name>(<Base Class>):

<suite>

• The subclass may override certain inherited attributes.

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

8

Inheritance Example

A CheckingAccount is a specialized type of Account.

Let's review the class Account since ...

Challenge: Implement a CheckingAccount.

Characteristics?

9

Methods are functions defined in the suite of a class statement.

class Account:

def __init__(self, account_holder):

self.balance = 0

self.holder = account_holder

def deposit(self, amount):

self.balance = self.balance + amount

return self.balance

def withdraw(self, amount):

if amount > self.balance:

return 'Insufficient funds'

self.balance = self.balance - amount

return self.balance

self should always be bound to an instance of the Account class

These def statements create function objects as always,but their names are bound as attributes of the class

Review

10

Inheritance Example

Challenge: Implement a CheckingAccount.

• account holder – same as a regular account • balance – same• interest rate – a little lower than a regular account• deposit – same • withdraw – may have a fee

Characteristics?

11

Inheritance Example

A CheckingAccount is a specialized type of Account.

Most behaviors are shared with the base class Account.

>>> ch = CheckingAccount('Tom')

>>> 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

class CheckingAccount(Account):

"""A bank account that charges for withdrawals."""

withdraw_fee = 1

interest = 0.01

def withdraw(self, amount):

return Account.withdraw(self, amount + self.withdraw_fee)

return super().withdraw(self, amount + self.withdraw_fee)

or

12

Base class attributes aren't copied into subclasses!

Looking Up Attribute Names on Classes

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

[Demo]

13

Object-Oriented Design

14

class CheckingAccount(Account):

"""A bank account that charges for withdrawals."""

withdraw_fee = 1

interest = 0.01

def withdraw(self, amount):

return Account.withdraw(self, amount + self.withdraw_fee)

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.

Attribute look-up on base class

15

Inheritance vs

16

Inheritance

having another objects as attributes

Compositionvs

17

Inheritance and Composition

Object-oriented programming shines when we adopt the metaphor.

Inheritance is best for representing is-a relationships.

• E.g., a checking account is a specific type of account.

• So, CheckingAccount inherits from Account.

Composition is best for representing has-a relationships.

• E.g., a bank has a collection of bank accounts it manages.

• So, A bank has a list of accounts as an attribute.

[Demo]

18

Inheritance and Composition

class Bank:

""" A bank *has* accounts.

class Account:

def __init__(self, account_holder):

self.balance = 0

self.holder = account_holder

// more attributes follows ...

Is this relation is-a or has-a?

19

Inheritance and Composition

class Bank:

""" A bank *has* accounts.

>>> bank = Bank()

>>> john = bank.open_account('John', 10)

>>> jack = bank.open_account('Jack', 5, CheckingAccount)

>>> john.interest

0.02

>>> jack.interest

0.01

>>> bank.pay_interest()

>>> john.balance

10.2

"""

def __init__(self):

self.accounts = []

def open_account(self, holder, account_type=Account):account = account_type (holder)account.deposit(amount)

self.accounts.append(account)

return account

def pay_interest(self):

for a in self.accounts:

a.deposit(a.balance * a.interest)

20

Inheritance and Composition

class Bank:

""" A bank *has* accounts.

>>> bank = Bank()

>>> john = bank.open_account('John', 10)

>>> jack = bank.open_account('Jack', 5, CheckingAccount)

>>> john.interest

0.02

>>> jack.interest

0.01

>>> bank.pay_interest()

>>> john.balance

10.2

>>> bank.too_big_to_fail()

True

"""

def __init__(self):

self.accounts = []

def open_account(self, holder, account_type=Account):account = account_type (holder)account.deposit(amount)

self.accounts.append(account)

return account

def pay_interest(self):

for a in self.accounts:

a.deposit(a.balance * a.interest)

def too_big_to_fail(self):

return len(self.accounts) > 1

21

Multiple Inheritance

22

Multiple Inheritance

class SavingsAccount(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:Example:

• Low interest rate of 1%• A $1 fee for withdrawals• A $2 fee for deposits• A free dollar when you open your account

class AsSeenOnTVAccount(CheckingAccount, SavingsAccount):

def __init__(self, account_holder):

self.holder = account_holder

self.balance = 1 # A free dollar!

23

A class may inherit from multiple base classes in Python.

class AsSeenOnTVAccount(CheckingAccount, SavingsAccount):

def __init__(self, account_holder):

self.holder = account_holder

self.balance = 1 # A free dollar!

Multiple Inheritance

>>> such_a_deal = AsSeenOnTVAccount("John")

>>> such_a_deal.balance

1

>>> such_a_deal.deposit(20)

19

>>> such_a_deal.withdraw(5)

13

Instance attribute

SavingsAccount method

CheckingAccount method

24

>>> such_a_deal = AsSeenOnTVAccount("John")

>>> such_a_deal.balance

1

>>> such_a_deal.deposit(20)

19

>>> such_a_deal.withdraw(5)

13

Resolving Ambiguous Class Attribute Names

Instance attribute

SavingsAccount method

CheckingAccount method

CheckingAccount SavingAccount

Account

AsSeenOnTVAcount

25

class CheckingAccount(Account):

withdraw_fee = 1

def withdraw(self, amount):

return Account.withdraw(self, amount + withdraw_fee)

Challenge: What’s wrong in the following?

Looking up names

Name expressions look up names in the environment:

<name>

Dot expressions look up names in an object:

<expression> . <name>

Error: withdraw_fee not bound in environment

Not all languages work this way.

26

CheckingAccount SavingAccount

Account

AsSeenOnTVAcount

Resolving Ambiguous Class Attribute Names

class AsSeenOnTVAccount(CheckingAccount, SavingsAccount):

• Methods looked up from bottom to top, left to right.

• The mro method on a class lists the order in which classes are checked for attributes. (mro stands for method resolution order.)

>>> [c.__name__ for c in AsSeenOnTVAccount.mro()]

['AsSeenOnTVAccount', 'CheckingAccount', 'SavingsAccount',

'Account', 'object']

27

Odds and Ends

The object class is at the root of the inheritance hierarchy.

• object should be given as the base class when no other meaningful base class exists

• Class names should be in CamelCase , not enforced.

Error messages can be confusing when calling methods with the wrong number of arguments:

>>> tom_account = Account('Tom') >>> tom_account.deposit(100, 200) TypeError: deposit() takes exactly 2 positional arguments (3 given)

Compare to partially curried function:

>>> add3 = curry(add)(3) >>> add3(4, 5)

TypeError: op_add expected 2 arguments, got 3

28

Resolving Ambiguous Class Attribute Names

Multiple Inheritance is complicated.

avoid it whenever possible!

Recommended