61A Lecture 16Wednesday, October 5Policy Changes Based on the SurveyHomework can now be completed in pairs, if you wish. •Every individual should still submit his/her own homework•Please write your partner's name at the top of your file•I strongly recommend that you try problems on your own firstSome questions will be deferred to office hours & after class•Deferred: Questions about related topics, extensions, etc.•Answered: Clarifications, examples, confusions, etc.•Your job: Keep asking all your questions; I'll answer fewerCode examples distributed in lecture•Code examples are always on the course website•Homework solutions are also online •I'll print out the code on code-intensive days2Implementing an Object SystemToday's topics:•What is a class?•What is an instance?•How do we create inheritance relationships?•How do we write code for attribute look-up procedures?3Tools we'll use:•Dispatch dictionaries•Higher-order functionsThe OOP Abstraction Barrier (a.k.a. the Line)Above the Line:•Objects with local state & interact via message passing•Objects are instantiated by classes, which are also objects•Classes may inherit from other classes to share behavior•Mechanics of objects are governed by "evaluation procedures"4Below the Line:•Objects have mutable dictionaries of attributes•Attribute look-up for instances is a function•Attribute look-up for classes is another function•Object instantiation is another functionTHE LINEImplementing the Object AbstractionFundamental OOP concepts:•Object instantiation and initialization•Attribute look-up and assignment•Method invocation•Inheritance5Not-so-fundamental issues (that we'll skip):•Dot expression syntax•Multiple inheritance•Introspection (e.g., what class does this object have?)Dot expressions are equivalent to getattr and setattr (Demo)InstancesDispatch dictionary with messages 'get' and 'set'Attributes stored in a local dictionary "attributes"6 def make_instance(cls): """Return a new object instance.""" def get_value(name): if name in attributes: return attributes[name] else: value = cls['get'](name) return bind_method(value, instance) def set_value(name, value): attributes[name] = value attributes = {} instance = {'get': get_value, 'set': set_value} return instanceThe class of the instanceLook up the name in the classMatch name against instance attributesAssignment always creates/modifies instance attributesBound MethodsIf looking up a name returns a class attribute value that is a function, getattr returns a bound method7 def bind_method(value, instance): if callable(value): def method(*args): return value(instance, *args) return method else: return value def make_instance(cls): def get_value(name): if name in attributes: return attributes[name] else: value = cls['get'](name) return bind_method(value, instance) ...ClassesDispatch dictionaries with messages 'get', 'set', and 'new'8 def make_class(attributes={}, base_class=None): """Return a new class.""" def get_value(name): if name in attributes: return attributes[name] elif base_class is not None: return base_class['get'](name) def set_value(name, value): attributes[name] = value def new(*args): return init_instance(cls, *args) cls = {'get': get_value, 'set': set_value, 'new': new} return clsThe class attribute look-up procedureCommon dispatch dictionary patternInstantiation and InitializationFirst makes a new instance, then invokes the __init__ method9 def make_class(attributes={}, base_class=None): ... def new(*args): return init_instance(cls, *args) ... def init_instance(cls, *args): """Return a new instance of cls, initialized with args.""" instance = make_instance(cls) init = cls['get']('__init__') if init: init(instance, *args) return instanceThe constructor name is fixed hereDispatch dictionaryExample: Defining an Account Class10 def make_account_class(): """Return the Account class.""" def __init__(self, account_holder): self['set']('holder', account_holder) self['set']('balance', 0) def deposit(self, amount): """Increase the account balance by amount.""" new_balance = self['get']('balance') + amount self['set']('balance', new_balance) return self['get']('balance') def withdraw(self, amount): """Decrease the account balance by amount.""" ... return make_class({'__init__': __init__, 'deposit': deposit, 'withdraw': withdraw, 'interest': 0.02})Example: Using the Account ClassThe Account class is instantiated and stored, then messaged11>>> Account = make_account_class()>>> jim_acct = Account['new']('Jim')>>> jim_acct['get']('holder')'Jim'>>> jim_acct['get']('interest')0.02>>> jim_acct['get']('deposit')(20)20>>> jim_acct['get']('withdraw')(5)15How can we also use getattr and setattr style syntax?Class and Instance AttributesInstance attributes and class attributes can still share names12>>> Account = make_account_class()>>> jim_acct = Account['new']('Jim')>>> jim_acct['set']('interest', 0.04)>>> Account['get']('interest')0.02DemoExample: Using InheritanceCheckingAccount is a special case of Account13 def make_checking_account_class(): """Return the CheckingAccount class.""" def withdraw(self, amount): return Account['get']('withdraw')(self, amount + 1) return make_class({'withdraw': withdraw, 'interest': 0.01}, Account)DemoClass attributes for CheckingAccountRelationship to the Python Object SystemObject attributes are stored as dictionariesSome "magic" names, __<name>__, require special handlingAn object has an "attribute" called __dict__ that is a dictionary of its instance attributes14BonusMaterialDemoIn Python, classes have classes tooThe equivalent of init_instance can be customized
View Full Document