Upload
thuong
View
23
Download
0
Embed Size (px)
DESCRIPTION
CSC 310 – Procedural Programming Languages, Spring, 2009. Chapters 7 and 8: Python Data Types, Subroutines and Control Abstraction. Definition of Types. Denotational type system A type is a set of possible values. Constructive – type system is a union of: - PowerPoint PPT Presentation
Citation preview
CSC 310 – Procedural Programming Languages, Spring, 2009
Chapters 7 and 8: Python Data Types, Subroutines and Control Abstraction
Definition of Types
• Denotational type system– A type is a set of possible values.
• Constructive – type system is a union of:– Built-in (primitive or predefined) types;– Composite, constructed types.
• Abstraction-based– Interface consisting of a set of constants and
operations
Python’s Dynamic Type System
• Python uses dynamic typing. There is no type for parameters, variables and fields. Each value has a type tag.>>> a = 3>>> type(a)<type 'int'>>>> a = 3.0>>> type(a)<type 'float'>>>> a = 'this is a string‘>>> type(a)<type 'str'>
Types are run-time values
• Compare types for equality.>>> type(a) == str # Some built-in types have built-in names.True>>> import types # See 'types' module in PY Ch. 13>>> type(a) == types.StringType # all built-in object typesTrue>>> t = type(type(a))>>> t<type 'type'>>>> type(t)<type 'type'>
Dynamic versus static type checking Weak versus strong type checking
• Python is dynamically and strongly typed.– A value (a.k.a. object) carries a type tag.– Values must be type compatible within
operations.
• The source-to-bytecode compiler checks syntax, but it does not check type.
• Lack of static type checking puts a heavier burden on testing to verify type compatibility.
Type equivalence
• Structural equivalence compares the composite construction of two types.
• Name equivalence is based on lexical occurrence of type definitions. Python uses name equivalence.>>> type(3)<type 'int'>>>> type(3) == type(4)True>>> from types import *>>> type(3) == IntTypeTrue
Aliased types
• Some languages have strict name equivalence for aliased types. Each name is a distinct type.
• Python has loose name equivalence, because what matters is the type’s value.
>>> int<type 'int'>>>> mytype = int>>> mytype == intTrue>>> mytype(3.7)3>>> mytype("5")5
Explicit type conversion
• Conversion uses a type name to cast a value from one type to another.>>> i = 3>>> type(i)<type 'int'>>>> i = float(i)>>> type(i)<type 'float'>
Implicit type coercion
• Mixed type arithmetic promotes to float.>>> value = 3 + 4 * 2.0>>> value11.0Integer overflow promotes to extended precision
long.>>> i = 1 << 30 ; i1073741824>>> i = i << 1 ; i2147483648L
Most conversions are explicit
• Most conversions must be explicit type casts>>> value = 3.0 + ' units'Traceback (most recent call last): File "<stdin>", line 1, in <module>TypeError: unsupported operand type(s) for +: 'float' and 'str'>>> value = str(3.0) + ' units' ; value'3.0 units'>>> value = 3.0 + float("-4.5") ; value-1.5
No C-like non-converting types casts
• C/C++ supports non-converting casts float fval = 1.3125 ; int ival = *((int *) &fval); printf("float value %f gives bit pattern 0x%x\n", fval, ival);float value 1.312500 gives bit pattern 0x3fa80000
• Python’s struct module can convert to a bit pattern format, then back to Python.from struct import pack, unpack>>> '%x' % (unpack('i', pack('f', 1.3125))[0])'3fa80000'
Polymorphism
• A single body of code works with objects of multiple types.• Implicit parametric polymorphism in Python.
>>> def summer(termlist):... mysum = termlist[0]... for term in termlist[1:]:... mysum = mysum + term... return mysum...>>> summer([3, 5, 7])15>>> summer(('cat ', 'dog ', 'beaver '))'cat dog beaver '
Abstraction-based types
• Python type compatibility is determined largely by the operators that combine values.
• Subtype polymorphism takes the form of related derived classes with alternative method definitions. The methods determine type compatibility.
• Operator overloading and make methods look syntactically like operators.
Subtype polymorphism in Python>>> class baseclass(object):... def f(self, param):... raise Exception, "not implemented">>> class derived1(baseclass):... def f(self, param):... return int(param)>>> class derived2(baseclass):... def f(self, param):... return float(param)>>> d1 = derived1() ; d2 = derived2()>>> d1.f(3) RETURNS 3>>> d2.f(3) RETURNS 3.0>>> d1.f(-3.2) RETURNS -3>>> d2.f(-3.2) RETURNS -3.2000000000000002
Additional explicit type check operations for objects
>>> baseclass<class '__main__.baseclass'>>>> derived1<class '__main__.derived1'>>>> type(derived1)<type 'type'>>>> type(int)<type 'type'>>>> isinstance<built-in function isinstance>>>> isinstance(d1, baseclass)True
>>> isinstance(d1, derived1)True>>> isinstance(d1, derived2)False>>> issubclass(derived1,
baseclass)True>>> issubclass(derived1,
derived1)True>>> issubclass(derived1,
derived2)False
Python composite types• Strings are a built-in type with extensive support.• List type supports heterogeneous sequences.
• >>> l = [1, 'a', None] ; print l• [1, 'a', None]
• Tuple acts like an immutable list.• >>> t = (1, 'a', None, l) ; print t• (1, 'a', None, [1, 'a', None])
• Dictionary is a mapping. Key is immutable.• >>> d = {'a' : 1, 'b' : 2} ; print d['b']• 2
• Set or frozenset is an unordered collection.• >>> s = set([1, 'a', None]) ; print s• set(['a', 1, None])
No support for explicit parametric polymorphism
• No C++ or Java-like “list of int” generic types.• >>> print type(l) ; print type(t) ; print type(d) ; print
type(s)• <type 'list'>• <type 'tuple'>• <type 'dict'>• <type 'set'>
• A Python container can hold a mix of types.
Missing types
• No standard array type.• List indexing is similar to arrays.• Module array (PY 15) stores primitive type objects.
• No subranges or enumeration types.• No fixed or variant contiguous records.
• No struct or union as in C/C++.
• Class objects can be used as records.• No private, etc. access protection on fields.• __field__ naming convention denotes private.
• Programmers can create their own types via the C/C++ or Java (for Jython) extension APIs.
Class objects as records
• >>> r = record() • print r.a ; r.b = "a value" ; print r.b
• None• a value
• Methods use self.a or self.b to access fields.• Parameter self is an explicit, first parameter to
object methods.• Equivalent to this in C++ or Java.
Values and References
• Python uses values for primitives, references for composite types.
• Every datum is an object.• >>> from copy import copy, deepcopy ;
print l• [1, 'a', None]• >>> l2 = l• >>> l3 = copy(l) # shallow copy• >>> l4 = deepcopy(l)• >>> l2 == l• True
>>> l3 == lTrue>>> l4 == lTrue>>> l2 is lTrue>>> l3 is lFalse>>> l4 is lFalse
Pointers and Recursive Types
• Object references are notational.• There are no explicit pointers. A reference is a pointer.• >>> l• [1, 'a', None]• >>> l.append(l)• >>> l• [1, 'a', None, [...]]• >>> l[3] == l• True• >>> l[3] is l• True• >>> l[3][3][3][3] is l• True
Binary tree in a list>>> t = []>>> def insert_into_binary_tree(tree, value):... if (not tree): # 'null pointer' beyond a leaf... tree.extend([value, [], []])... return tree... elif (tree[0] == value):... return tree... elif (value < tree[0]):... return(insert_into_binary_tree(tree[1],
value))... else:... return(insert_into_binary_tree(tree[2],
value))>>> insert_into_binary_tree(t, 5)>>> insert_into_binary_tree(t, 4)>>> insert_into_binary_tree(t, 1)>>> insert_into_binary_tree(t, 2)>>> insert_into_binary_tree(t, 17)>>> insert_into_binary_tree(t, -5)>>> t[5, [4, [1, [-5, [], []], [2, [], []]], []], [17, [], []]]
>>> t[5, [4, [1, [-5, [], []], [2, [], []]], []], [17, [], []]]
No dangling references or uncollected objects (no garbage)
• Python uses a garbage collector.• Reference counting tracks most objects.
• Every variable binding adds a reference.
• Additional garbage collection for circular structures.
• May be mark and sweep.• May be stop and copy.• May be generational collection.• Details not specified by the language.
Subroutines and Control Abstraction
• Python supports functions / procedures, object methods, generators (iterators) and closures (function + static environment).
• Primitive parameters are values.• Object parameters are references.• Immutable objects (e.g. tuples) cannot be changed.
• Functions and methods are first class objects.• Reflection supports interactive inspection of
functions.
Python’s call stack
• The call stack occupies contiguous memory.• >>> from sys import getrecursionlimit,
setrecursionlimit• getrecursionlimit()• 1000
• Each stack frame points to dynamic data structures.
• Both static (lexical) and dynamic bindings resides in dynamic data structures.
Parameters are values for primitives, references for objects
>>> def modl(l):... l = [1, 2, 3]... print "modl sees
" + str(l)>>> gl = [4, 5, 6]>>> modl(gl)modl sees [1, 2, 3]>>> print gl[4, 5, 6]
>>> def modelem(l):... l[1] = 111... l.append('appended string')... print "modelem sees " +
str(l)>>> gl = [4, 5, 6]>>> modelem(gl)modelem sees [4, 111, 6,
'appended string']>>> print gl[4, 111, 6, 'appended string']>>> modelem(tuple(gl))Traceback (most recent call last):TypeError: 'tuple' object does not support item
assignment
A closure both sees its lexical environment and saves it as well!
>>> def outer(vala):... def inner(valb):... return vala + valb... return inner...>>> f = outer(5)>>> f<function inner at 0x9ad70>>>> f(6)11
Closures in Python
>>> dir(outer)['__call__', … 'func_closure', …]>>> dir(f)['__call__', … 'func_closure', …] >>> print outer.func_closureNone>>> print f.func_closure(<cell at 0xa4430: int object at 0x668c0>,)
Uncovering the static link in a closure
• >>> print f.func_closure[0]• <cell at 0xa4430: int object at 0x668c0>• >>> print type(f.func_closure[0])• <type 'cell'>• >>> dir(f.func_closure[0])• ['__class__', '__cmp__', '__delattr__', '__doc__',
'__getattribute__', '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', 'cell_contents']
• >>> f.func_closure[0].cell_contents• 5
Both positional and keyword parameters supported
• Positional, if any, come first in a call.• Default values come last in a definition.• >>> def sum(a, b=3):• ... return a + b• >>> sum(2)• 5• >>> sum(2,7)• 9• >>> sum(b=8, a=9)• 17• >>> sum(4, a=9)• Traceback (most recent call last):• File "<stdin>", line 1, in <module>• TypeError: sum() got multiple values for keyword argument 'a'
Apply allows processes to construct function calls at run time.
>>> f = sum>>> keywordargs = {'a': 3, 'b': 4}>>> apply(f,(),keywordargs)7>>> apply(f,(7, 6), {})13>>> eval("sum(4,5)") # eval() evaluates text9
Variable number of *positional and **keyword arguments
• A trailing *param is a tuple of variable-length positional parameters. A trailing **param is a dictionary of keyword parameters.
• >>> def sum(*terms):• ... mysum = terms[0]• ... for t in terms[1:]:• ... mysum += t• ... return mysum• ...• >>> sum(1, 2, 3, 4, 5)• 15
Exception handling• Exceptions are class objects, similar to C++ and Java.• Finally and except clauses cannot appear in the same try
statement. Use nested try.>>> try:... i = int('dog')... except ValueError, estring:... print "exception says: " + str(estring)...exception says: invalid literal for int() with base 10: 'dog‘• Use raise to throw an exception.
Generators are Pythons iterators>>> def g(start, end):... for v in range(start,end):... yield v...>>> gen = g(1,4)>>> gen.next()1>>> gen.next()2>>> gen.next()3>>> gen.next()Traceback (most recent call last): File "<stdin>", line 1, in <module>StopIteration