Announcements HW7 due on Wednesday Ants project out CS61A Lecture 20 Amir Kamil and Julia Oh UC Berkeley March 8, 2013 Dot Expressions Accessing Attributes Using getattr , we can look up an attribute using a string, just Objects receive messages via dot notation as we did with a dispatch function/dictionary Dot notation accesses attributes of the instance or its class >>> getattr(tom_account, 'balance') <expression> . <name> 10 The <expression> can be any valid Python expression >>> hasattr(tom_account, 'deposit') True The <name> must be a simple name getattr and dot expressions look up a name in the same way Evaluates to the value of the attribute looked up by <name> in the object that is the value of the <expression> Looking up an attribute name in an object may return: • One of its instance attributes, or tom_account.deposit(10) Call expression Dot expression • One of the attributes of its class Methods and Functions Methods and Currying Earlier, we saw currying , which converts a function that takes in Python distinguishes between: multiple arguments into multiple chained functions. • Functions , which we have been creating since the beginning of the course, and The same procedure can be used to create a bound method • Bound methods , which couple together a function and the from a function object on which that method will be invoked. def curry(f): def outer(x): Object + Function = Bound Method def inner(*args): return f(x, *args) >>> type(Account.deposit) return inner <class 'function'> >>> add2 = curry(add)(2) return outer >>> type(tom_account.deposit) >>> add2(3) <class 'method'> 5 >>> Account.deposit(tom_account, 1001) >>> tom_deposit = curry(Account.deposit)(tom_account) 1011 >>> tom_deposit(1000) >>> tom_account.deposit(1000) 3011 2011 1
Attributes, Functions, and Methods Looking Up Attributes by Name All objects have attributes, which are name ‐ value pairs <expression> . <name> Classes are objects too, so they have attributes To evaluate a dot expression: Instance attributes: attributes of instance objects Class attributes: attributes of class objects 1. Evaluate the <expression>. Terminology: Python object system: 2. <name> is matched against the instance attributes. Functions are objects. 3. If not found, <name> is looked up in the class. Bound methods are also objects: a Class function that has its first parameter 4. That class attribute value is returned unless it is a Functions Attributes Methods "self" already bound to an instance. function , in which case a bound method is returned. Dot expressions on instances evaluate to bound methods for class attributes that are functions. Class Attributes Assignment to Attributes Assignment statements with a dot expression on their left ‐ hand Class attributes are "shared" across all instances of a class side affect attributes for the object of that dot expression because they are attributes of the class, not the instance. • If the object is an instance, then assignment sets an instance class Account(object): attribute interest = 0.02 # Class attribute • If the object is a class, then assignment sets a class attribute def __init__(self, account_holder): self.balance = 0 # Instance attribute Instance tom_account.interest = 0.08 Attribute self.holder = account_holder Attribute : assignment Assignment # Additional methods would be defined here This expression evaluates to statement adds an object or modifies the >>> tom_account = Account('Tom') “interest” >>> jim_account = Account('Jim') attribute of But the name (“interest”) is not >>> tom_account.interest interest is not part of the tom_account looked up 0.02 instance that was somehow >>> jim_account.interest Class Attribute Assignment : copied from the class! Account.interest = 0.04 0.02 Attribute Assignment Statements Inheritance A technique for relating classes together Account class interest: 0.02 0.04 0.05 (withdraw, deposit, __init__) attributes Common use: Similar classes differ in amount of specialization Two classes have overlapping attribute sets, but one represents balance: 0 balance: 0 a special case of the other. holder: 'Jim' holder: 'Tom' interest: 0.08 class <name>(<base class>): >>> jim_account = Account('Jim') >>> jim_account.interest = 0.08 <suite> >>> tom_account = Account('Tom') >>> jim_account.interest >>> tom_account.interest 0.08 Conceptually, the new subclass "shares" attributes with its 0.02 >>> tom_account.interest base class. >>> jim_account.interest 0.04 0.02 >>> Account.interest = 0.05 The subclass may override certain inherited attributes. >>> tom_account.interest >>> tom_account.interest 0.02 0.05 Using inheritance, we implement a subclass by specifying its >>> Account.interest = 0.04 >>> jim_account.interest difference from the base class. >>> tom_account.interest 0.08 0.04 2
Inheritance Example Looking Up Attribute Names on Classes A CheckingAccount is a specialized type of Account . Base class attributes aren't copied into subclasses! >>> ch = CheckingAccount('Tom') To look up a name in a class. >>> ch.interest # Lower interest rate for checking accounts 0.01 1. If it names an attribute in the class, return the attribute value. >>> ch.deposit(20) # Deposits are the same 2. Otherwise, look up the name in the base class, if there is one. 20 >>> ch.withdraw(5) # Withdrawals incur a $1 fee 14 >>> ch = CheckingAccount('Tom') # Calls Account.__init__ Most behavior is shared with the base class Account >>> ch.interest # Found in CheckingAccount 0.01 class CheckingAccount(Account): """A bank account that charges for withdrawals.""" >>> ch.deposit(20) # Found in Account withdraw_fee = 1 20 interest = 0.01 >>> ch.withdraw(5) # Found in CheckingAccount def withdraw(self, amount): return Account.withdraw(self, 14 amount + self.withdraw_fee) Designing for Inheritance General Base Classes Base classes may contain logic that is meant for subclasses. Don't repeat yourself; use existing implementations. Example: Same CheckingAccount behavior; different Attributes that have been overridden are still accessible via approach class objects. class Account(object): Look up attributes on instances whenever possible. interest = 0.02 May be overridden by subclasses withdraw_fee = 0 class CheckingAccount(Account): def withdraw(self, amount): """A bank account that charges for withdrawals.""" amount += self.withdraw_fee withdraw_fee = 1 if amount > self.balance: interest = 0.01 return 'Insufficient funds' def withdraw(self, amount): self.balance = self.balance – amount return Account.withdraw(self, return self.balance amount + self.withdraw_fee) Attribute look ‐ up class CheckingAccount(Account): Preferable alternative to on base class interest = 0.01 Nothing else needed in this class CheckingAccount.withdraw_fee withdraw_fee = 1 Inheritance and Composition Multiple Inheritance class SavingsAccount(Account): Object ‐ oriented programming shines when we adopt the deposit_fee = 2 metaphor. def deposit(self, amount): return Account.deposit(self, Inheritance is best for representing is ‐ a relationships. amount - self.deposit_fee) A class may inherit from multiple base classes in Python. E.g., a checking account is a specific type of account. CleverBank marketing executive wants: So, CheckingAccount inherits from Account . • Low interest rate of 1% Composition is best for representing has ‐ a relationships. • A $1 fee for withdrawals • A $2 fee for deposits E.g., a bank has a collection of bank accounts it manages. • A free dollar when you open your account So, A bank has a list of Account instances as an attribute. class AsSeenOnTVAccount(CheckingAccount, SavingsAccount): def __init__(self, account_holder): No local state at all? Just write a pure function! self.holder = account_holder self.balance = 1 # A free dollar! 3
Multiple Inheritance Resolving Ambiguous Class Attribute Names A class may inherit from multiple base classes in Python. Account class AsSeenOnTVAccount(CheckingAccount, SavingsAccount): CheckingAccount SavingsAccount def __init__(self, account_holder): self.holder = account_holder self.balance = 1 # A free dollar! AsSeenOnTVAccount >>> such_a_deal = AsSeenOnTVAccount("John") >>> such_a_deal = AsSeenOnTVAccount("John") Instance attribute Instance attribute >>> such_a_deal.balance >>> such_a_deal.balance 1 1 SavingsAccount SavingsAccount >>> such_a_deal.deposit(20) >>> such_a_deal.deposit(20) method method 19 19 >>> such_a_deal.withdraw(5) >>> such_a_deal.withdraw(5) CheckingAccount CheckingAccount 13 13 method method Human Relationships Some_Guy Grandma Grandpa Grandaddy Gramammy Double Half Aunt Mom Dad Double Half Uncle Some_Dude You Quadruple Double Half Cousin 4
Recommend
More recommend