Preview: built-in objects
Object type |
Example constants/usage |
Numbers |
3.14, 1234, 999L, 3+4j,
decimal |
Strings |
'spam',
"spam's" |
Lists |
[1, [2, 'three'], 4] |
Dictionaries |
{'food':'spam',
'taste':'yum'} |
Tuples |
(1,'spam', 4, 'U') |
Files |
text = open('eggs',
'r').read() |
Others |
sets, types, None, bool |
Demo: Built-in Types, a first pass
■
Most examples
listed ahead
■
See also Extras\Other\PriorClasses logs for
similar code
■
Key terms:
“sequence”, “immutable”, “mapping”
■
Key ideas: no
fixed types, no fixed sizes, arbitrary nesting
■
Full story:
dir(object), help(object.method), manuals
Python program structure
♦ Programs are composed of modules
♦ Modules contain statements
♦ Statements contain expressions
♦ Expressions create and process objects
Why use built-in types?
♦ Python provides objects and supports extensions
♦ Built-in objects make simple programs easy to write
♦ Built-in objects are components of extensions
♦ Often more efficient than custom data structures
Standard types and operators
♦ Integer, floating-point, hex/octal constants
♦ ‘long’ integer type with unlimited precision
♦ Built-in mathematical functions: ‘pow’, ‘abs’
♦ Utility modules: ‘random’, ‘math’
♦ Complex numbers, ‘**’ power operator
Numeric Python (NumPy)
♦ An optional extension, beyond core language
♦ For advanced numeric programming in Python
♦ Matrix object, interfaces to numeric libraries, etc.
♦ Plus SciPy, matplotlib, pypar, IPython shell, others
♦ Python + NumPy = open source MATLAB alternative
►For interested audiences: Numerical overview page
Numeric literals
Constant |
Interpretation |
1234,
-24 |
integers
(C longs, 3.X: unlimited size) |
99999999L |
2.X
long integers (unlimited size) |
1.23,
3.14e-10 |
floating-point
(C doubles) |
0o177,0x9f,0b101 |
octal,
hex, binary integer literals |
3+4j,
3.0+4.0j |
complex
number literals |
Decimal('0.11') |
fixed-precision
decimal (2.4+) |
Fraction(2,
3) |
rational
type (2.6+, 3.0+) |
Python expressions
♦ Usual algebraic operators: ‘+’ , ‘-’, ‘*’, ‘/’, . . .
♦ C’s bitwise operators: “<<”, “&”, . . .
♦ Mixed types: converted up just as in C
♦ Parenthesis group sub-expressions
Numbers in action
♦ Variables created when assigned
♦ Variables replaced with their value when used
♦ Variables must be assigned before used
♦ Expression results echoed back
♦ Mixed integer/float: casts up to float
♦ Integer division truncates (until 3.X: use // to force)
% python
>>> a = 3 # name created
>>> b = 4
>>> b / 2 + a # same as ((4 / 2) + 3)
5
>>> b / (2.0 + a) # same as (4 / (2.0 + 3))
0.8
>>> 1 / 2, 1 // 2 # 3.X: / keeps remainder, // does not
(0.5, 0)
Hint: use print if you don’t want all the precision (in some versions):
>>> 4 / 5.0
0.80000000000000004
>>> print 4 / 5.0 # 3.X: print(4 / 5.0)
0.8
>>> a = 3 # Where are the missing declarations?
● Names
versus objects
● Names are always “references” (pointers) to objects
● Names are created when first assigned (or so)
● Objects have types, names do not
● Each value is a distinct object (normally)
● Objects are pieces of memory with value + operations
● Shared references to mutables are open to side
effects (on purpose)
Back to numbers: bitwise operations
>>> x = 1
>>> x << 2 # shift left 2 bits
4
>>> x | 2 # bitwise OR
3
>>> x & 1 # bitwise AND
1
Long integers
♦ 2.X only—subsumed by arbitrary precision int in 3.X
♦ Via ‘L’ suffix
♦ Some performance penalty
♦ As of 2.2, integers auto-converted to long if too big (“L” optional)
>>> 9999999999999999999999999999L + 1
10000000000000000000000000000L
>>> 9999999999999999999999999999 + 1
10000000000000000000000000000L
before 2.2:
>>> 9999999999999999999999999999 + 1
OverflowError: integer literal too large
Decimal and Fraction extension types
>>> 0.1 + 0.1 + 0.1 - 0.3
5.5511151231257827e-017
>>> print 0.1 + 0.1 + 0.1 - 0.3
5.55111512313e-017
>>> 0.1 + 0.1 + 0.1 - 0.3
# as of 3.4
5.551115123125783e-17
>>> from decimal import Decimal
>>> Decimal('0.1') + Decimal('0.1') + Decimal('0.1') -
Decimal('0.3')
Decimal("0.0")
>>> Decimal('0.1') + Decimal('0.10') + Decimal('0.10') -
Decimal('0.30')
Decimal("0.00")
>>> from
fractions import Fraction
>>>
Fraction(1, 3) + Fraction(2, 8)
Fraction(7, 12)
>>>
Fraction(1, 10) + Fraction(1, 10) + Fraction(1, 10) - Fraction(3, 10)
Fraction(0, 1)
Python operators and precedence
■ Operators lower in table bind tighter (parens force order)
■ Preview: all Python operators may be overloaded by Python classes and C extension types
■ Added
in Python 2.0: +=. *=, &=, …
augmented assignment statements, not operators
■
Python 3.X: `X` →
repr(X), X / Y → true div, X <> Y → X != Y
■ Recent
operator/expression additions:
x if y else z |
Ternary
if, same as 4-line if/else statement |
yield [from] x |
Generator
function’s iteration result (return can send one too) |
await x |
For
3.5+ async def coroutines |
x @ y |
Matrix
multiply in 3.5+ (but not used by core Python itself!) |
[x, *iter] |
Unpacks
(flattens) objects in literals in 3.5+ |
Operators |
Description |
x or
y, lambda
args: expr |
Logical
‘or’ (y is only evaluated if x is false), anonymous function |
x and
y |
Logical
‘and’ (y is only evaluated if x is true) |
not
x |
Logical
negation |
<,
<=, >, >=, ==, <>, !=, is,
is not, in, not in |
Comparison
operators, sequence
membership |
x |
y |
Bitwise
‘or’ |
x ^
y |
Bitwise
‘exclusive or’ |
x
& y |
Bitwise
‘and’ |
x
<< y, x >> y |
Shift
x left or right by y bits |
x +
y, x – y |
Addition/concatenation,
subtraction |
x *
y, x / y, x % y, x // y |
Multiply/repetition,
divide, remainder/format, floor divide |
x **
y, -x, +x, ~x |
Power,
unary negation, identity, bitwise compliment |
x[i],
x[i:j], x.y, x(...) |
Indexing,
slicing, qualification, function calls |
(...),
[...], {...}, `...` |
Tuple,
list, dictionary, conversion to string |
♦ Ordered collections of characters
♦ No ‘char’ in Python, just 1-character strings
♦ Constants, operators, utility modules (‘string’, ‘re’)
♦ Strings are ‘immutable sequences’
♦ See ‘re’ module for pattern-based text processing
About
Unicode support: this section covers basic, ASCII text
strings. See the Advanced
Topics section for coverage of Unicode and byte strings and files. This varies per Python line. In 3.X, strings are always Unicode and
support encoding to bytes, and bytes strings represent truly binary 8-bit data
and support decoding to strings. In 2.X,
strings are essentially the same as 3.X bytes strings (containing just 8-bit
characters), and Unicode is a special type similar to 3.X strings.
Common string operations
Operation |
Interpretation |
s1 =
'' |
single
quotes (empty) |
s2 =
"spam's" |
double
quotes (same) |
block
= """...""" |
triple-quoted
blocks, can
span multiple lines |
r'C:\new\text\file.txt' |
raw
strings (\ kept) |
s1 +
s2, s2 * 3 |
concatenate,
repeat |
s2[i],
s2[i:j], s[i:j:k], len(s2) |
index,
slice, length |
'a
%s parrot' % 'dead' 'a
{} parrot'.format('dead') |
string
formatting: original,
2.6+ option |
u'A\xC4B',
'A\xC4B' |
Unicode:
2.X, 3.X |
b'\x00spam\x01' |
bytes:
3.X (and 2.X) |
f'we
get {spam} a lot' |
formats:
3.6? |
for
x in s2, 'm' in s2 |
iteration/membership |
Newer extensions
● String methods:
X.split('+')
same as older string.split(X, '+')
string
module requires import, methods do not
methods
now faster, preferred to string module
● Unicode strings:
Multi-byte characters, for
internationalization (I18N)
U'xxxx'
constants, Unicode modules, auto conversions
Can mix
with normal strings, or convert: str(U), unicode(S)
Varies
in 3.X: see note box above for more details
● Template formatting: string module, see ahead
● String .format() method: largely redundant with “%”
Strings in action
% python
>>> 'abc' + 'def' # concatenation: a new string
'abcdef'
>>> 'Ni!' * 4 # like "Ni!" + "Ni!" + ...
'Ni!Ni!Ni!Ni!'
Indexing and slicing
>>> S = 'spam'
>>> S[0], S[-2] # indexing from from or end
('s', 'a')
>>> S[1:3], S[1:], S[:-1] # slicing: extract section
('pa', 'pam', 'spa')
Changing and formatting
>>> S = S + 'Spam!' # to change a string, make a new one
>>> S
'spamSpam!'
>>> 'That is %d %s bird!' % (1, 'dead') # like C sprintf
That is 1 dead bird!
Advanced formatting examples
>>> res = "integers: ...%d...%-6d...%06d" % (x, x, x)
>>> res
'integers: ...1234...1234 ...001234'
>>> x = 1.23456789
>>> x
1.2345678899999999
>>> '%e | %f | %g' % (x, x, x)
'1.234568e+000 | 1.234568 | 1.23457'
>>> '%-6.2f | %05.2f | %+06.1f' % (x, x, x)
'1.23 | 01.23 | +001.2'
>>> int(x)
1
>>> round(x, 2)
1.23
>>> x = 1.236
>>> round(x, 2)
1.24
>>> "%o %x %X" % (64, 64, 255)
'100 40 FF'
>>> hex(255), int('0xff', 16), eval('0xFF')
('0xff', 255, 255)
>>> ord('s'), chr(115)
(115, 's')
Formatting with dictionaries
>>> D = {'xx': 1, 'yy': 2}
>>> "%(xx)d => %(yy)s" % D
'1 => 2'
>>> aa = 3
>>> bb = 4
>>> "%(aa)d => %(bb)s" % vars()
'3 => 4'
>>> reply = """
Greetings...
Hello %(name)s!
Your age squared is %(age)s
"""
>>> values = {'name': 'Bob', 'age': 40}
>>> print reply % values
Greetings...
Hello Bob!
Your age squared is 40
Formatting method
alternative (2.6+, 3.0+)
>>> '{} {}'.format(42, 'spam')
'42 spam'
>>> '{0:.2f}'.format(1.234)
'1.23'
>>> '{0:,.2f}'.format(1234567.234)
'1,234,567.23'
Template formatting (2.4+)
>>> ('%(page)i: %(title)s' %
{'page':2, 'title': 'The Best of Times'})
'2: The Best of Times'
>>> import string
>>> t = string.Template('$page: $title')
>>> t.substitute({'page':2, 'title': 'The
Best of Times'})
'2: The Best of Times'
>>> s = string.Template('$who likes
$what')
>>> s.substitute(who='bob', what=3.14)
'bob likes 3.14'
>>> s.substitute(dict(who='bob',
what=’pie’))
'bob likes pie'
Common string tools
>>> S = "spammify"
>>> S.upper() # convert to uppercase
'SPAMMIFY'
>>> S.find("mm") # return index of substring
3
>>> int("42"), str(42) # convert from/to string
(42, '42')
>>> S.split('mm') # splitting and joining
['spa', 'ify']
>>> 'XX'.join(S.split("mm"), "XX")
'spaXXify'
Example: replacing text
# replace method
>>> S = 'spammy'
>>> S = S.replace('mm', 'xx')
>>> S
'spaxxy'
>>> S = 'xxxxSPAMxxxxSPAMxxxx'
>>> S.replace('SPAM', 'EGG') # replace all
'xxxxEGGxxxxEGGxxxx'
# finding and slicing
>>> S = 'xxxxSPAMxxxxSPAMxxxx'
>>> where = S.find('SPAM') # search for position
>>> where # occurs at offset 4
4
>>> S = S[:where] + 'EGGS' + S[(where+4):]
>>> S
'xxxxEGGSxxxxSPAMxxxx'
# exploding to/from list
>>> S = 'spammy'
>>> L = list(S) # explode to list
>>> L
['s', 'p', 'a', 'm', 'm', 'y']
>>> L[3] = 'x' # multiple in-place changes
>>> L[4] = 'x' # cant do this for strings
>>> L
['s', 'p', 'a', 'x', 'x', 'y']
>>> S = ''.join(L) # implode back to string
>>> S
'spaxxy'
Example: parsing with slices
>>> line = 'aaa bbb ccc'
>>> col1 = line[0:3] # columns at fixed offsets
>>> col3 = line[8:]
>>> col1
'aaa'
>>> col3
'ccc'
Example: parsing with splits
>>> line = 'aaa bbb ccc' # split around whitespace
>>> cols = line.split()
>>> cols
['aaa', 'bbb', 'ccc']
>>> line = 'bob,hacker,40' # split around commas
>>> line.split(',')
['bob', 'hacker', '40']
Generic type concepts
■ Types share operation sets by categories
■ Numbers support addition, multiplication, . . .
■ Sequences support indexing, slicing, concatenation, . . .
■ Mappings support indexing by key, . . .
■ Mutable types can be changed in place
■ Strings are ‘immutable sequences’
Concatenation and repetition
■ ‘X + Y’ makes a new sequence object with the contents of both operands
■ ‘X * N’ makes a new sequence object with N copies of the sequence operand
Indexing and slicing
■ Indexing
● Fetches components via offsets: zero-based
● Negative indexes: adds length to offset
● S[0] is the first item
● S[-2] is the second from the end (4 - 2)
● Also works on mappings, but index is a key
■ Slicing
● Extracts contiguous sections of a sequence
● Slices default to 0 and the sequence length if omitted
● S[1:3] fetches from offsets 1 upto but not including 3
● S[1:] fetches from offsets 1 through the end (length)
● S[:-1] fetches from offsets 0 upto but not including last
● S[I:J:K] newer, I to J by K, K is a stride/step (S[::2])
♦ Arrays of object references
♦ Access by offset
♦ Variable length, heterogeneous, arbitrarily nestable
♦ Category: ‘mutable sequence’
♦ Ordered collections of arbitrary objects
Common list operations
Operation |
Interpretation |
L1 =
[] |
an
empty list |
L2 =
[0, 1, 2, 3] |
4-items:
indexes 0..3 |
['abc',
['def', 'ghi']] |
nested
sublists |
L2[i],
L2[i:j], len(L2) |
index,
slice, length |
L1 +
L2, L2 * 3 |
concatenate,
repeat |
L1.sort(),
L2.append(4) |
methods:
sort, grow |
del
L2[k], L2[i:j] = [] |
shrinking |
L2[i:j]
= [1,2,3] |
slice
assignment |
range(4),
xrange(0, 4) |
make
integer lists |
for
x in L2, 3 in L2 |
iteration/membership |
Lists in action
% python
>>> [1, 2, 3] + [4, 5, 6] # concatenation
[1, 2, 3, 4, 5, 6]
>>> ['Ni!'] * 4 # repetition
['Ni!', 'Ni!', 'Ni!', 'Ni!']
Indexing and slicing
>>> L = ['spam', 'Spam', 'SPAM!']
>>> L[2]
'SPAM!'
>>> L[1:]
['Spam', 'SPAM!']
Changing lists in-place
>>> L[1] = 'eggs' # index assignment
>>> L
['spam', 'eggs', 'SPAM!']
>>> L[0:2] = ['eat', 'more'] # slice assignment
>>> L # replace items 0,1
['eat', 'more', 'SPAM!']
>>> L.append('please') # append method call
>>> L
['eat', 'more', 'SPAM!', 'please']
● Only works for ‘mutable’ objects: not strings
● Index assignment replaces an object reference
● Slice assignment deletes a slice and inserts new items
● Append method inserts a new item on the end (‘realloc’)
Preview: iteration/membership
>>> for x in L: print x,
...
eat more SPAM! please
Example: 2-dimensional array
>>> matrix = [[1, 2, 3],
... [4, 5, 6],
... [7, 8, 9]]
...
>>> matrix[1]
[4, 5, 6]
>>> matrix[1][1]
5
>>> matrix[2][0]
7
♦ Tables of object references
♦ Access by key, not offset (hash-tables)
♦ Variable length, heterogeneous, arbitrarily nestable
♦ Category: ‘mutable mappings’ (not a sequence)
♦ Unordered collections of arbitrary objects
Common dictionary operations
Operation |
Interpretation |
d1 =
{} |
empty
dictionary |
d2 =
{'spam': 2, 'eggs': 3} |
2
items |
d3 =
{'food': {'ham': 1, 'egg': 2}} |
nesting |
d2['eggs'],
d3['food']['ham'] |
indexing
by key |
d2.has_key('eggs'),
d2.keys() |
methods |
d2.get('eggs',
default) |
default
values |
len(d1) |
length
(entries) |
d2[key]
= new, del d2[key] |
adding/changing
|
Dictionaries in action
% python
>>> d2 = {'spam': 2, 'ham': 1, 'eggs': 3}
>>> d2['spam']
2
>>> len(d2) # number entries
3
>>> d2.keys() # list of keys
['eggs', 'spam', 'ham']
Changing dictionaries
>>> d2['ham'] = ['grill', 'bake', 'fry']
>>> d2
{'eggs': 3, 'spam': 2, 'ham': ['grill', 'bake', 'fry']}
>>> del d2['eggs']
>>> d2
{'spam': 2, 'ham': ['grill', 'bake', 'fry']}
Making dictionaries
# literals
>>> D = {'name': 'Bob', 'age': 42, 'job': 'dev'}
>>> D
{'job': 'dev', 'age': 42, 'name': 'Bob'}
# keywords
>>> D = dict(name='Bob', age=42, job='dev')
>>> D
{'job': 'dev', 'age': 42, 'name': 'Bob'}
# field by field
>>> D = {}
>>> D['name'] = 'Bob'
>>> D['age'] = 42
>>> D['job'] = 'dev'
>>> D
{'job': 'dev', 'age': 42, 'name': 'Bob'}
# zipped keys/values
>>> pairs = zip(['name', 'age', 'job'], ('Bob', 42, 'dev'))
>>> pairs
[('name', 'Bob'), ('age', 42), ('job', 'dev')]
>>> D = dict(pairs)
>>> D
{'job': 'dev', 'age': 42, 'name': 'Bob'}
# key lists
>>> D = dict.fromkeys(['name', 'age', 'job'], '?')
>>> D
{'job': '?', 'age': '?', 'name': '?'}
A language table
>>> table = {'Perl': 'Larry Wall',
... 'Tcl': 'John Ousterhout',
... 'Python': 'Guido van Rossum' }
...
>>> language = 'Python'
>>> creator = table[language]
>>> creator
'Guido van Rossum'
>>> for lang in table.keys(): print lang,
...
Tcl Python Perl
Dictionary usage notes
● Sequence operations don’t work!
● Assigning to new indexes adds entries
● Keys need not always be strings
Example: simulating auto-grown lists
>>> L = [] # L=[0]*100 would help
>>> L[99] = 'spam'
IndexError: list assignment index out of range
>>> D = {}
>>> D[99] = 'spam'
>>> D[99]
'spam'
>>> D
{99: 'spam'}
Example: dictionary-based “records”
>>> rec = {}
>>> rec['name'] = 'mel'
>>> rec['age'] = 40
>>> rec['job'] = 'trainer/writer'
>>>
>>> print rec['name']
mel
>>> mel = {'name': 'Mark',
... 'jobs': ['trainer', 'writer'],
... 'web': 'www.rmi.net/~lutz',
... 'home': {'state': 'CO', 'zip':80503}}
>>> mel['jobs']
['trainer', 'writer']
>>> mel['jobs'][1]
'writer'
>>> mel['home']['zip']
80503
Example: more object nesting
>>> rec = {'name': {'first': 'Bob', 'last': 'Smith'},
'job': ['dev', 'mgr'],
'age': 40.5}
>>>
>>> rec['name']
{'last': 'Smith', 'first': 'Bob'}
>>> rec['name']['last']
'Smith'
>>> rec['job'][-1]
'mgr'
>>> rec['job'].append('janitor')
>>> rec
{'age': 40.5, 'job': ['dev', 'mgr', 'janitor'], 'name': {'last': 'Smith', 'first': 'Bob'}}
>>> db = {}
>>> db['bob'] = rec # collecting records into a db
>>> db['sue'] = …
Preview: Bob could be a record
in a real database, using shelve or pickle persistence modules: watch
for more details on the class and database units. This nested dictionary/list structure is also
the genesis of JSON: see Python’s json standard library module
for a trivial translation utility, and the Database unit
for a simple example.
Example: dictionary-based sparse matrix
>>> Matrix = {}
>>> Matrix[(2,3,4)] = 88 # tuple key is coordinates
>>> Matrix[(7,8,9)] = 99
>>> X = 2; Y = 3; Z = 4 # ; separates statements
>>> Matrix[(X,Y,Z)]
88
>>> Matrix
{(2, 3, 4): 88, (7, 8, 9): 99}
>>> Matrix.get((0, 1, 2), 'Missing')
'Missing'
♦ Arrays of object references
♦ Access by offset
♦ Fixed length, heterogeneous, arbitrarily nestable
♦ Category: ‘immutable sequences’ (can’t be changed)
♦ Ordered collections of arbitrary objects
Common tuple operations
Operation |
Interpretation |
() |
an
empty tuple |
T1 =
(0,) |
a
one-item tuple |
T2 =
(0, 1, 2, 3) |
a
4-item tuple |
T2 =
0, 1, 2, 3 |
another
4-item tuple |
T3 =
('abc', ('def', 'ghi')) |
nested
tuples |
T1[i],
t1[i:j], len(t1) |
index,
slice, length |
T1 +
t2, t2 * 3 |
concatenate,
repeat |
for
x in t2, 3 in t2 |
iteration/membership |
Tuples in action
>>> T1 = (1, 'spam')
>>> T2 = (2, 'ni')
>>> T1 + T2
(1, 'spam', 2, 'ni')
>>> T1 * 4
(1, 'spam', 1, 'spam', 1, 'spam', 1, 'spam')
>>> T2[1]
'ni'
>>> T2[1:]
('ni',)
Why lists and tuples?
● Immutability provides integrity
● Some built-in operations require tuples (argument lists)
● Guido was a mathematician: sets versus data structures
♦ A wrapper around C’s “stdio” file system (io module in 3.X)
♦ The builtin ‘open’ function returns a file object
♦ File objects export methods for file operations
♦ Files are not sequences or mappings (methods only)
♦ Files are a built-in C extension type
About
3.X files: this section covers basic file
interfaces. See the Advanced
Topics section for coverage of 3.X distinction between text files—whose content is normal strings, may be passed a Unicode
encoding type, and perform automatic Unicode encoding/decoding on input/output;
and binary files—whose content is
bytes strings and do not perform Unicode encoding/decoding or line-end
translations. In 2.X, normal files are
the same as 3.X binary files (8-bit byte data), and the codecs module supports
Unicode file encodings like 3.X text files.
Common file operations
Operation |
Interpretation |
O =
open('/tmp/spam', 'w') |
create
output file |
I =
open('data', 'r') |
create
input file |
I.read(),
I.read(1) |
read
file, byte |
I.readline(),
I.readlines() |
read
line, lines list |
O.write(S),
O.writelines(L) |
write
string, lines |
O.close() |
manual
close (or on free) |
Files in action
# more at the end of the next section
>>> newfile = open('test.txt', 'w')
>>> newfile.write(('spam' * 5) + '\n')
>>> newfile.close()
>>> myfile = open('test.txt')
>>> text = myfile.read()
>>> text
'spamspamspamspamspam\n'
Related Python tools (day 2 or 3)
● Descriptor based files: os module
● DBM keyed files
● Persistent object shelves
●
Pipes, fifos, sockets
Type categories revisited
♦ Objects share operations according to their category
♦ Only mutable objects may be changed in-place
Object type |
Category |
Mutable? |
Numbers |
Numeric |
No |
Strings |
Sequence |
No |
Lists |
Sequence |
Yes |
Dictionaries |
Mapping |
Yes |
Tuples |
Sequence |
No |
Files |
Extension |
n/a |
Generality
♦ Lists, dictionaries, and tuples can hold any kind of object
♦ Lists, dictionaries, and tuples can be arbitrarily nested
♦ Lists and dictionaries can dynamically grow and shrink
Nesting example
>>> L = ['abc', [(1, 2), ([3], 4)], 5]
>>> L[1][1]
([3], 4)
>>> L[1][1][0]
[3]
>>> L[1][1][0][0]
3
Shared references
♦ Assignments always create references to objects
♦ Can generate shared references to the same object
♦ Changing a mutable object impacts all references
♦ To avoid effect: make copies with X[:], list(X), etc.
♦ Tip: distinguish between names and objects!
► Names have no "type", but objects do
>>> X = [1, 2, 3]
>>> L = ['a', X, 'b']
>>> D = {'x':X, 'y':2}
>>> X[1] = 'surprise' # changes all 3 references!
>>> L
['a', [1, 'surprise', 3], 'b']
>>> D
{'x': [1, 'surprise', 3], 'y': 2}
Equality and truth
♦ Applied recursively for nested data structures
♦ ‘is’ tests identity (object address)
♦ True: non-zero number or non-empty data structure
♦ “None” is a special empty/false object
>>> L1 = [1, ('a', 3)] # same value, unique objects
>>> L3 = [1, ('a', 3)]
>>> L1 == L3, L1 is L3 # equivalent?, same object?
(True, False) # (True==1, False==0)
Other comparisons
♦ Applied recursively for nested data structures
♦ Strings compared lexicographically
♦ Lists and tuples compared depth-first, left-to-right
♦ Dictionaries compared by sorted (key, value) lists
♦ Disctionaries don’t compare in 3.X, but their .items() do
>>> L1 = [1, ('a', 3)]
>>> L2 = [1, ('a', 2)]
>>> L1 < L2, L1 == L2, L1 > L2
(False, False, True)
♦ Everything is an ‘object’ type in Python: “first class”
♦ Types are objects too: “type(X)” returns type object of X
♦ Preview: C extension modules and types use same mechanisms as Python types
How to break your code’s flexibility…
>>> L
= [1, 2, 3]
>>> if
type(L) == type([]):
print 'yes'
yes
>>> if
type(L) == list:
print 'yes'
yes
>>> if
isinstance(L, list):
print 'yes'
yes
Newer types
● Decimal, fraction (modules): see above
● Boolean (bool, True, False): see next section
● Sets: 2.4 (module in 2.3), 3.X/2.7 literal/comprehension
● Other extension types: namedtuple, collection (std lib)
>>> True + 2 # bool: True/False like 1/0 (next section)
3
Sets
>>> x = set('abcde') # set constructor
>>> y = set('bdxyz')
>>> x
set(['a', 'c', 'b', 'e', 'd'])
>>> 'e' in x # membership
True
>>> x – y # difference
set(['a', 'c', 'e'])
>>> x | y # union
set(['a', 'c', 'b', 'e', 'd', 'y', 'x', 'z'])
>>> x & y # intersection
set(['b', 'd'])
In Python 2.7 and 3.X
C:\class> py -3
>>> x = {'a', 'b', 'c', 'd'} # 3.X set literal
>>> {'b', 'd'} < x # subset test
True
>>> {ord(c) for c in 'spam'} # 3.X set comprehension (ahead)
{112, 97, 115, 109}
>>> {c: ord(c) for c in 'spam'} # 3.X dict comprehension (ahead)
{'m': 109, 'p': 112, 'a': 97, 's': 115}
■ Assignment creates references, not copies
>>> L = [1, 2, 3]
>>> M = ['X', L, 'Y']
>>> M
['X', [1, 2, 3], 'Y']
>>> L[1] = 0
>>> M
['X', [1, 0, 3], 'Y']
■ Repetition adds 1-level deep
>>> L = [4, 5, 6]
>>> X = L * 4 # like [4, 5, 6] + [4, 5, 6] + ...
>>> Y = [L] * 4 # [L] + [L] + ... = [L, L,...]
>>> X
[4, 5, 6, 4, 5, 6, 4, 5, 6, 4, 5, 6]
>>> Y
[[4, 5, 6], [4, 5, 6], [4, 5, 6], [4, 5, 6]]
>>> L[1] = 0
>>> X
[4, 5, 6, 4, 5, 6, 4, 5, 6, 4, 5, 6]
>>> Y
[[4, 0, 6], [4, 0, 6], [4, 0, 6], [4, 0, 6]]
■ Cyclic structures print oddly (loop in 1.5)
>>> L = ['hi.']; L.append(L) # append reference to self
>>> L # dots=cycle today (no loop)
■ Immutable types can’t be changed in-place
T = (1, 2, 3)
T[2] = 4 # error!
T = T[:2] + (4,) # okay: (1, 2, 4)
Click here to go to
lab exercises
Click here to go to
exercise solutions
Click here to go to
solution source files
Click here to go to
lecture example files