230 likes | 364 Views
CSC 310 – Theory of Programming Languages, Spring, 2009. Chapter 9: Data Abstraction and Object Orientation. Review of Object-Oriented Programming – Encapsulation.
E N D
CSC 310 – Theory of Programming Languages, Spring, 2009 Chapter 9: Data Abstraction and Object Orientation
Review of Object-Oriented Programming – Encapsulation • Amodule encapsulates implementation code and data, exposing abstract interfaces to client code while hiding implementation details. • Also called informationhiding, this approach does not necessarily entail using objects. • C++ namespaces, Java packages, Python packages and modules. • It reduces conceptual load, provides fault containment, and provides component independence.
Interface Inheritance • An interface defines operations and symbolic constants that specify operation signatures and semantics. • C++ abstract class consisting of pure virtual functions and constant definitions, Java interface, Python class with method declarations that throw exceptions. • Derived concrete classes implement the operations of a base class interface while hiding implementation details.
sequence_interface (ADT) – sequence of string objects cp ~parson/JavaLang/sequence_adt ~/JavaLang/sequence_adt <<interface>> sequence_interface.java sequence_interface insert(value : string, offset : integer) : boolean remove(offset : integer) : boolean get(offset : integer) : string size() : integer
Concrete class sequence_arrayimpl implements sequence_interface <<interface>> sequence_interface sequence_arrayimpl insert(), remove() get(), size() private String [] array ; private int count ; // number of array elements actually used
Class sequence_linkedlistimpl implements sequence_interface <<interface>> sequence_interface sequence_linkedlistimpl insert(), remove() get(), size() private static class listelement { // private local helper class String content ; // string stored at this element listelement next ; // next element, higher in number than this one } private listelement first ; private int count ; // number of linked list nodes actually used
Implementation Inheritance • An abstract or concrete base class provides fields, public methods and protected methods used in common by alternative implementations in derived classes. • Protected fields and methods are accessible only to derived classes. They are part of shared implementation. They eliminate duplicate code. • Public fields and methods are accessible to client code, and methods can be redefined or extended by derived classes.
Package sequence_aclass class sequence_abstract_baseclass <<interface>> sequence_interface <<abstract>> sequence_abstract_baseclass size() : int protected int getRealOffset(int offset, boolean isinsert) : int (helper method to convert an offset parameter to a real offset) protected int count sequence_arrayimpl sequence_linkedlistimpl sequence_arraylistimpl
Subtype Polymorphism • Derived classes that implement a common interface can take various forms. • Each class can provide an implementation that is extended, customized or optimized for some class of client applications. • Once object construction is complete, client access occurs via a pointer or reference to a base class or interface object. • The concrete run-time objects accessed via such a pointer or reference have many forms.
Module encapsulation in Python • A package takes the form of a directory containing one or more Python modules. • The package name is a “.”-separated path name below a directory on PYTHONPATH. • A module is a Python source file within a package directory with related data and code definitions. • Clients must import components of a module.
Python Packages • Assuming $HOME/ProcLang is on my PYTHONPATH, package mysort corresponds to directory $HOME/ProcLang/mysort. • File __init__.py contains a list of every module name in the package in its __all__ variable. • ~parson/ProcLang/mysort/__init__.py contains the assignment __all__ = ["mysort"] for module mysort.py. Most packages contain multiple modules. • This list provides support for “from mysort import *” from other modules. It tells Python what modules to import.
Importing Python Modules • Importing a module without importing explicit symbols requires using the module name as a prefix. • >>> import sys ; sys.exit(1) • Importing distinct names restricts the import and makes those name first class objects. • from sys import exit ; exit(1) • from sys import exit as byebye ; byebye(1) • Importing “*” imports all modules in a package or all symbols in a module. • Python does not report symbol collisions from multiple modules. It uses the most recent import.
Python Classes • Classes are dynamic constructs in Python, like everything else. • There is no compiler check to ensure definition of “abstract methods” in concrete derived classes (there are no abstract methods) or method signature compatibility between base and derived classes. • Inherited symbol access is a series of dictionary lookups from derived to base classes. • All fields and methods are public. Naming conventions document intended access limitations.
Classy Examples >>> class baseclass(object): ... """ baseclass is an example """ ... @staticmethod ... def statmethod(): … print "statmethod in baseclass" ... def __init__(self, val): ... self.value = val ... def f(self, newval): ... oldval = self.value ... self.value = newval ... return oldval >>> class d1(baseclass): ... @staticmethod ... def statmethod(): print "statmethod in d1" ... def __init__(self, val): ... return super(d1, self).__init__(val) >>> D1 = d1(3) >>> D1.f(5) 3 >>> D1.f(7) 5
More Classy Examples >>> class d2(baseclass): ... def f(self, newval): ... oldval = self.value ... self.value = newval + 10.0 ... return oldval >>> D2 = d2(5) >>> D2.f(1) 5 >>> D2.f(3) 11.0 >>> isinstance(D2, d2) True >>> isinstance(D2, baseclass) True >>> isinstance(D2, d1) False >>> issubclass(d1, baseclass) True >>> issubclass(d1, d1) True >>> issubclass(d1, d2) False
No method name overloading • Both the constructor method, called __init__, and other methods within the class, must have unique names. There is no name overloading in Python. • Calls to superclass __init__ are explicit in explicit order. The class determines construction order. • You can supply default parameter values. • Methods can test for argument types. • Methods can use variable number of *positional and **keyword arguments. • There are no destructors in Python. The garbage collector invokes __del__(self) on an object being recovered, but most classes do not redefine __del__.
Operator overloading and extension of built-in types • You can overload Python operators such as + by defining special methods such as __add_ and __radd__ -- see PY Chapter 3. • You can extend built-in types. >>> class coercive_int(int): ... def __init__(self, value): ... super(coercive_int,self).__init__(self, value) ... def __add__(self, value): ... print "Inside method __add__" ... return int(self) + int(value) ... def __radd__(self, value): ... print "Inside method __radd__" ... return int(self) + int(value)
User-extended types in expressions >>> ci = coercive_int(3) >>> ci 3 >>> ci + 4.0 Inside method __add__ 7 >>> int(ci) + 4.0 7.0 >>> coercive_int(ci) + 4.0 Inside method __add__ 7 >>> 4.0 + ci 7.0 >>> "12345" + ci Inside method __radd__ 12348 >>> "12345" + 3 Traceback (most recent call last): File "<stdin>", line 1, in ? TypeError: cannot concatenate 'str' and 'int' objects
Multiple Inheritance uses Mixins • Each base class can be a fragment of a class that refers to symbols defined in other fragmentary or complete classes. • Combining fragmentary classes via multiple inheritance supplies their missing parts. • Python’s SocketServer module has both UDPServer and TCPServer classes, and threading and forking mixin classes. You can define derived classes like this: ThreadingTCPServer(ThreadingMixIn, TCPServer) ForkingUDPServer(ForkingMixIn, UDPServer)
Mixin Inheritance • Mixin inheritance requires application-specific names for methods and possibly fields contributed by mixin component classes. • Multiple implementation inheritance of complete base classes is also possible. • Python walks a class’ inheritance graph in left-to-right order, from most-to-least derived, backing up before shared base classes, to search for symbols and to resolve conflicts. • Print CLASSNAME.__mro__ shows the class ordering.
Deciphering multiple inheritance >>> class d11(d1): pass >>> class d12(d1) : pass >>> class d21(d2) : pass >>> class d22(d2) : pass >>> class multi(d11, d12, d21, d22): pass >>> multi.__mro__ (<class '__main__.multi'>, <class '__main__.d11'>, <class '__main__.d12'>, <clas s '__main__.d1'>, <class '__main__.d21'>, <class '__main__.d22'>, <class '__main __.d2'>, <class '__main__.baseclass'>, <type 'object'>) multi(d11, d12, d21, d22):
All method bindings are either object-dynamic or class-static. • The Python bytecode interpreter looks for field and method symbols within class objects using the __mro__ class ordering graph. All lookup is dynamic. • There is nothing like a C++ non-virtual member function that is bound statically by the compiler. • @staticmethod-tagged methods require no object. They can be invoked using a class name or an object of that class as a prefix. Resolution of static methods also uses __mro__ for an object prefix.
Python metaclasses (end of PY Ch. 7) • Derive a class from type or class and define or redefine the appropriate methods. • This new type can create alternatives to “class” for creating user-defined types. • http://www.ibm.com/developerworks/linux/library/l-pymeta.html • http://www.onlamp.com/pub/a/python/2003/04/17/metaclasses.html?page=1 • http://www.python.org/download/releases/2.2/descrintro/