1 / 34

CSC 310 – Procedural Programming Languages, Spring, 2009

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:

thuong
Download Presentation

CSC 310 – Procedural Programming Languages, Spring, 2009

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. CSC 310 – Procedural Programming Languages, Spring, 2009 Chapters 7 and 8: Python Data Types, Subroutines and Control Abstraction

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

  3. Python’s Dynamic Type System • Python uses dynamictyping. There is no type for parameters, variables and fields. Each value has a typetag. >>> a = 3 >>> type(a) <type 'int'> >>> a = 3.0 >>> type(a) <type 'float'> >>> a = 'this is a string‘ >>> type(a) <type 'str'>

  4. 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 types True >>> t = type(type(a)) >>> t <type 'type'> >>> type(t) <type 'type'>

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

  6. Type equivalence • Structuralequivalence compares the composite construction of two types. • Nameequivalence is based on lexicaloccurrence of type definitions. Python uses name equivalence. >>> type(3) <type 'int'> >>> type(3) == type(4) True >>> from types import * >>> type(3) == IntType True

  7. Aliased types • Some languages have strictnameequivalence for aliased types. Each name is a distinct type. • Python has loosenameequivalence, because what matters is the type’s value. >>> int <type 'int'> >>> mytype = int >>> mytype == int True >>> mytype(3.7) 3 >>> mytype("5") 5

  8. 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'>

  9. Implicit type coercion • Mixed type arithmetic promotes to float. >>> value = 3 + 4 * 2.0 >>> value 11.0 Integer overflow promotes to extended precision long. >>> i = 1 << 30 ; i 1073741824 >>> i = i << 1 ; i 2147483648L

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

  11. 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'

  12. Polymorphism • A single body of code works with objects of multiple types. • Implicitparametricpolymorphismin 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 '

  13. Abstraction-based types • Python type compatibility is determined largely by the operators that combine values. • Subtypepolymorphism 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.

  14. Subtypepolymorphism 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

  15. Additional explicit type check operations for objects >>> isinstance(d1, derived1) True >>> isinstance(d1, derived2) False >>> issubclass(derived1, baseclass) True >>> issubclass(derived1, derived1) True >>> issubclass(derived1, derived2) False >>> 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

  16. 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])

  17. No support for explicit parametric polymorphism • No C++ or Java-like “list of int” generictypes. • >>> 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.

  18. Missing types • No standard array type. • List indexing is similar to arrays. • Modulearray (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.

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

  20. 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 == l True >>> l4 == l True >>> l2 is l True >>> l3 is l False >>> l4 is l False

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

  22. 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, [], []]]

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

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

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

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

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

  28. Closures in Python >>> dir(outer) ['__call__', … 'func_closure', …] >>> dir(f) ['__call__', … 'func_closure', …] >>> print outer.func_closure None >>> print f.func_closure (<cell at 0xa4430: int object at 0x668c0>,)

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

  30. 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'

  31. 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 text 9

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

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

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

More Related