Show Lecture.Python as a slide show.
CT320 Python
Adapted from https://docs.python.org/3.4/tutorial/
Versions
- Python 1: lost in the distant past
- Python 2: a fine language, but …
- End-of-life scheduled for 2020‒01‒01.
- No more bug fixes / security patches!
- Python 3: better, but incompatible with Python 2
- Treat Python 2 and Python 3 as similar, but distinct, languages.
- This tutorial will discuss Python 3.
Invoking Python
- For backward compatibility, the default is Python 2.
- Therefore, you have to execute
python3
to get Python 3.
- Be explicit. If you want Python 2, run
python2
.
$ python -V
/tmp/pmwiki-bash-scriptChJKJ9: line 10: python: command not found
$ python2 -V
Python 2.7.18
$ python3 -V
Python 3.6.8
$ ls -l /usr/bin/python
/bin/ls: cannot access '/usr/bin/python': No such file or directory
Help
The pydoc3
program tells you about functions:
$ pydoc3 abs
Help on built-in function abs in module builtins:
abs(x, /)
Return the absolute value of the argument.
Help
pydoc3
can also tell you about control flow:
$ pydoc3 for
The "for" statement
*******************
The "for" statement is used to iterate over the elements of a sequence
(such as a string, tuple or list) or other iterable object:
for_stmt ::= "for" target_list "in" expression_list ":" suite
["else" ":" suite]
The expression list is evaluated once; it should yield an iterable
object. An iterator is created for the result of the
"expression_list". The suite is then executed once for each item
provided by the iterator, in the order returned by the iterator. Each
item in turn is assigned to the target list using the standard rules
for assignments (see Assignment statements), and then the suite is
executed. When the items are exhausted (which is immediately when the
sequence is empty or an iterator raises a "StopIteration" exception),
the suite in the "else" clause, if present, is executed, and the loop
terminates.
A "break" statement executed in the first suite terminates the loop
without executing the "else" clause’s suite. A "continue" statement
executed in the first suite skips the rest of the suite and continues
with the next item, or with the "else" clause if there is no next
item.
The for-loop makes assignments to the variables(s) in the target list.
This overwrites all previous assignments to those variables including
those made in the suite of the for-loop:
for i in range(10):
print(i)
i = 5 # this will not affect the for-loop
# because i will be overwritten with the next
# index in the range
Names in the target list are not deleted when the loop is finished,
but if the sequence is empty, they will not have been assigned to at
all by the loop. Hint: the built-in function "range()" returns an
iterator of integers suitable to emulate the effect of Pascal’s "for i
:= a to b do"; e.g., "list(range(3))" returns the list "[0, 1, 2]".
Note: There is a subtlety when the sequence is being modified by the
loop (this can only occur for mutable sequences, e.g. lists). An
internal counter is used to keep track of which item is used next,
and this is incremented on each iteration. When this counter has
reached the length of the sequence the loop terminates. This means
that if the suite deletes the current (or a previous) item from the
sequence, the next item will be skipped (since it gets the index of
the current item which has already been treated). Likewise, if the
suite inserts an item in the sequence before the current item, the
current item will be treated again the next time through the loop.
This can lead to nasty bugs that can be avoided by making a
temporary copy using a slice of the whole sequence, e.g.,
for x in a[:]:
if x < 0: a.remove(x)
Related help topics: break, continue, while
Interpretive mode
python3
, with no arguments, starts in a “calculator” mode:
$ python3
>>> 2+2
4
>>> a=10
>>> from math import sqrt
>>> sqrt(a)
3.1622776601683795
>>> control-D to exit
$
The previous lines can be edited using the arrow keys.
One-liner
To execute a single line of Python, use -c
:
$ python3 -c 'import math; print(math.atan(1)*4)'
3.141592653589793
$ python3 -c 'print(2**200)'
1606938044258990275541962092341162602522202993782792835301376
$ python3 -c 'print(1<<200)'
1606938044258990275541962092341162602522202993782792835301376
$ python3 -c 'print(0x100000000000000000000000000000000000000000000000000)'
1606938044258990275541962092341162602522202993782792835301376
$ python3 -c 'print(1606938044258990275541962092341162602522202993782792835301376)'
1606938044258990275541962092341162602522202993782792835301376
Script
A Python 3 script starts with: #! /usr/bin/python3 -Wd
#! /usr/bin/python3 -Wd
print("Hello, world!")
Hello, world!
The -Wd
enables warning messages. Warnings are your friends:
#! /usr/bin/python3 -Wd
handle = open('/etc/group', 'r')
sys:1: ResourceWarning: unclosed file <_io.TextIOWrapper name='/etc/group' mode='r' encoding='UTF-8'>
Names Do Matter
Some people name their Python scripts whatever.py, and execute
them like this:
python3 foo.py
Why? The user doesn’t care that your program is a Python script.
Think of object encapsulation—don’t unnecessarily expose implementation
details. A significant implementation detail is the implementation language.
If you’ve exposed the implementation language, like this,
then you’re no longer free to change it.
Data Type Overview
Name | Examples | Notes |
Boolean | True , False | capitalized |
Number | 1 , 3.4 , 4.5e8 , 2**1000 | big big big |
String | "Don't" 'believe' r'\all/' """you read!""" | immutable |
List | [1,2.3,"fruit",[45,5]] | mutable, heterogeneous |
Tuple | (23, "skidoo") , ('Jack', 59.99, "970-555-1212") | immutable, heterogeneous |
Set | {1,2,3} | mutable, heterogeneous |
Dictionary | {"Jack":"CT320", "Ben":"CS163"} | mutable, heterogeneous |
Variables
# Note lack of declaration and fixed type
val=42 # integer
print(val)
val+=1.2 # real
print(val)
val="hello there folks" # string
print(val)
val=[5, "Gold", "Rings"] # list
print(val)
val=(4, "Calling", "Birds") # tuple
print(val)
val={3, "French Hens"} # set
print(val)
42
43.2
hello there folks
[5, 'Gold', 'Rings']
(4, 'Calling', 'Birds')
{3, 'French Hens'}
Unicode!
Δ=0.01
π=3.14159
print(π/Δ)
print('Mi aerodeslizador está lleno de anguilas')
print("Το αερόστρωμνό μου είναι γεμάτο χέλια")
print("मेरी मँडराने वाली नाव सर्पमीनों से भरी हैं")
print('حَوّامتي مُمْتِلئة بِأَنْقَلَيْسون')
print("我的氣墊船裝滿了鱔魚")
314.159
Mi aerodeslizador está lleno de anguilas
Το αερόστρωμνό μου είναι γεμάτο χέλια
मेरी मँडराने वाली नाव सर्पमीनों से भरी हैं
حَوّامتي مُمْتِلئة بِأَنْقَلَيْسون
我的氣墊船裝滿了鱔魚
Indentation Determines Block Structure
Note the colon and lack of braces and then
/fi
a=123
if a>100:
print("Holy Toledo, a is too big at", a, '!')
a=100
b=a
Holy Toledo, a is too big at 123 !
- I like it! It eliminates the redundancy of indentation for the
human reader, and braces for the computer. Indentation no longer
reflects program structure, it determines program structure.
- Tabs are interpreted as every eight character positions.
- Changing the tab stops in your editor will not alter how
Python interprets tab characters.
- Wise Pythoners have their editor expand tabs to spaces,
which avoids the whole problem.
Indentation Examples
print("alpha")
if False:
print("beta")
print("gamma")
alpha
print("delta")
if False:
print("epsilon")
print("zeta")
delta
zeta
print("eta")
if False:
print("theta")
print("iota")
File ".py3", line 4
print("iota")
^
IndentationError: unindent does not match any outer indentation level
if
age=25
if age<30:
print("You’re a punk")
elif age>=65:
print("You’re a geezer")
elif age==50+12:
print("You’re the ideal age")
else:
print("OK, boomer.")
You’re a punk
- This is as close as we get to a switch statement.
- Don't forget the colon after the condition.
- You were so angry about indentation that you probably haven’t noticed
that semicolons aren’t needed.
while
a = 5
while a>=0:
print(a, end=' ')
a-=1 # No ++ or --
print("Blastoff!")
5 4 3 2 1 0 Blastoff!
- Don't forget the colon after the condition.
for
# The for loop iterates over a list:
for p in [2,3,5,7]:
print(p)
2
3
5
7
# Or anything else that's iterable:
total=0
for n in range(100):
total+=n
print(total)
4950
# Though a real Pythoner will do this:
print(sum(range(100)))
4950
Sorry, C fans: no C-style for loop. range()
does most of it, however.
break/continue/pass
break
: end this loop, as in C
continue
: go to the next iteration, as in C
pass
: do nothing—used when the syntax requires a statement
for/else
for n in range(2, 10):
for x in range(2, n):
if n % x == 0:
print(n, 'is', x, '*', n//x)
break
else:
# loop fell through without finding a factor
print(n, 'is prime')
2 is prime
3 is prime
4 is 2 * 2
5 is prime
6 is 2 * 3
7 is prime
8 is 2 * 4
9 is 3 * 3
The indentation is correct: the else
is associated with the
inner for
, not the if
! The else
clause is executed
if the for
loop ended “normally”, not via break
.
Why no result for 10?
Functions
def factorial(n):
if n<=1:
return n
else:
return n*factorial(n-1)
print(factorial(4), factorial(69))
24 171122452428141311372468338881272839092270544893520369393648040923257279754140647424000000000000000
Also:
- variable number of arguments
- default values for arguments
- keyword arguments
- lambda-expressions
Scope
Ignoring modules, there are only two scopes: global and function local.
Variables that are only read inside a function are implicitly global.
If a variable is assigned a value anywhere within the function’s body,
it’s assumed to be a local unless explicitly declared as global
.
Boolean Operators
Boolean operators: and
, or
, not
and
and or
are short-circuiting, and return the last value evaluated.
print(3 and 5)
print(9 and 0)
print(False or "hello")
print(True)
print(not True)
5
0
hello
True
False
Sorry, C fans: no &&
, ||
Get the case right
print(True, False)
True False
print(true, false)
Traceback (most recent call last):
File ".py3", line 1, in <module>
print(true, false)
NameError: name 'true' is not defined
Remember to get the case correct!
Arithmetic Operators
print(1+2)
print(2-3)
print(3*4)
print(100/6)
print(100//6)
print(3.5//1.1)
print(100%30)
print(2**10)
print(2**70)
3
-1
12
16.666666666666668
16
3.0
10
1024
1180591620717411303424
- And assignment versions:
+=
, /=
, etc.
- Note
//
for integer division.
- Sorry, C fans: no
++
or --
A Mystery
How does this work‽
a=12
--a
++a
++a
++a
++a
print(a)
12
Didn’t we say that there was no ++
or --
?
There are no ++
or --
operators. Those are multiple unary operators.
Bitwise operators
print(5 & 3)
print(5 | 3)
print(5 ^ 3)
print(~5)
print(5<<2)
print(5>>1)
1
7
6
-6
20
2
- And assignment versions:
&=
, <<=
, etc.
Comparison operators
if 1<2:
print("good")
if 2>=3:
print("bad")
if 1 < 2 <= 3:
print("excellent")
good
excellent
- Comparison operators can be chained:
a<b<c
- My C/C++ students do this anyway, despite it not working.
String Operators
print("hi"*3) # repetition
print("Foo" + 'bar') # concatenation
print("CT" "320") # concatenation
print('xyz' in 'Mxyzptlk') # string search
print('M.*k' in 'Mxyzptlk') # STRING search
print('xyz' not in 'Mxyzptlk') # string avoidance
print('%d/%d=%.2f' % (22,7,22.0/7)) # printf-ish formatting
hihihi
Foobar
CT320
True
False
False
22/7=3.14
- Comparison operators:
< > = <= >= !=
- strings are objects, with many methods.
Strings are immutable!
s="Luthor"
del s[3]
Traceback (most recent call last):
File ".py3", line 2, in <module>
del s[3]
TypeError: 'str' object doesn't support item deletion
s="Luthor"
s="Lex" # s now refers to a DIFFERENT string
print(s)
Lex
s="Luthor"
s=s[:3]+s[4:] # make a new string without h
print(s)
Lutor
Strings are iteratable
Several types, e.g., strings, lists, tuples, are iterable:
for n in [1,2,3]:
print(n)
for f in (1.1, 2.2, 3.3):
print(f)
for v in range(7,9):
print(v)
for c in "Dog":
print(c)
1
2
3
1.1
2.2
3.3
7
8
D
o
g
List Operators
authors = ["Asimov", "Niven", "Baum"]
authors += ["Carroll"]
print(authors)
del authors[1] # Au revoir, Larry!
print(authors)
authors += "Applin"
print(authors)
['Asimov', 'Niven', 'Baum', 'Carroll']
['Asimov', 'Baum', 'Carroll']
['Asimov', 'Baum', 'Carroll', 'A', 'p', 'p', 'l', 'i', 'n']
Lists are objects, with many methods.
Tuple Operators
t=(1,2,3)
print(t)
print(t+(3,1,99))
print(t*2)
a="alpha"; b="beta"
(c,d) = (a,b)
print(c)
print(d)
(1, 2, 3)
(1, 2, 3, 3, 1, 99)
(1, 2, 3, 1, 2, 3)
alpha
beta
Set Operations
authors = {"Asimov", "Niven"}
authors |= {"Carroll"}
authors.add("Baum")
print(authors)
authors.remove('Niven') # Au revoir, Larry!
print(authors)
{'Baum', 'Carroll', 'Asimov', 'Niven'}
{'Baum', 'Carroll', 'Asimov'}
s|r
: union
s&r
: intersection
s^r
: symmetric difference (things in s
or r
, but not in both)
s-r
: difference (things in s
but not in r
)
- Sets are objects, with many methods.
Dictionary Operations
colors = {"red":"#ff0000", "green":"#00ff00"}
colors['blue'] = '#0000ff'
del colors['green']
print(colors)
for d in colors:
print(d, "maps to", colors[d])
if "red" in colors: print("found red")
{'red': '#ff0000', 'blue': '#0000ff'}
red maps to #ff0000
blue maps to #0000ff
found red
Sequence Operators
Strings, lists, tuples, and sets are all sequences, with
many methods.
s=[1.1, 22, (33,44), "slow"]
print("Length of s is", len(s))
for v in s:
print(v)
if 22 in s:
print("22 is in ", s)
if 33 not in s:
print("33 is not in ", s)
if (33,44) in s:
print("(33,44) is in ", s)
Length of s is 4
1.1
22
(33, 44)
slow
22 is in [1.1, 22, (33, 44), 'slow']
33 is not in [1.1, 22, (33, 44), 'slow']
(33,44) is in [1.1, 22, (33, 44), 'slow']
Slices
- Slices from a string, list, or tuple are variable[start:end].
- Both start and end are optional.
- start is inclusive, end is exclusive.
- Negative indices count from the right.
s = list(range(11,100,11))
print(s)
print(s[2])
print(s[2:4])
print(s[2:])
print(s[:2])
print(s[-1])
print(s[-3:])
print(s[2:-1])
print(s[-5:7])
print(s[:])
[11, 22, 33, 44, 55, 66, 77, 88, 99]
33
[33, 44]
[33, 44, 55, 66, 77, 88, 99]
[11, 22]
99
[77, 88, 99]
[33, 44, 55, 66, 77, 88]
[55, 66, 77]
[11, 22, 33, 44, 55, 66, 77, 88, 99]
Primes
max = 100
s = set(range(2,max))
for candidate in range(2,max):
s -= set(range(candidate*2, max, candidate))
print(s)
{2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97}
Reference Semantics
A variable holds a reference to an object, like Java.
a=list(range(10,0,-1))
b=a
c=a[:]
a[-3] = 33
print(a)
print(b)
print(c)
[10, 9, 8, 7, 6, 5, 4, 33, 2, 1]
[10, 9, 8, 7, 6, 5, 4, 33, 2, 1]
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
List Comprehensions
Long way:
squares = []
for x in range(10):
squares.append(x**2)
print(squares)
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
Short way:
squares = [x**2 for x in range(10)]
print(squares)
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
Multiple for
loops and if
statements are allowed.
Output
print(value, …, sep=' ', end='\n', file=sys.stdout, flush=False)
- The
sep=
string (default space) is emitted between arguments.
- The
end=
string (default newline) is emitted after all of the arguments.
print(1, 2, 3, 4, 5, sep="※")
print(6, 7, end=' and now ')
print(8, 9)
1※2※3※4※5
6 7 and now 8 9
File I/O
Show nameserver
lines in /etc/resolv.conf
:
f = open('/etc/resolv.conf', 'r')
for line in f:
if "nameserver" in line:
print(line, end='')
f.close()
nameserver 129.82.45.181
nameserver 129.82.103.78
nameserver 129.82.103.79
or:
with open('/etc/resolv.conf', 'r') as f:
for line in f:
line = line.rstrip() # Remove \n
if line.startswith("nameserver"):
print(line)
nameserver 129.82.45.181
nameserver 129.82.103.78
nameserver 129.82.103.79
File object methods
f.read(n)
: read up to n
bytes
f.read()
: read the rest of the file
f.readline()
f.write(string)
f.close()
Not appearing in this lecture