CptS 481 - Python Software Construction

Unit 5: Statements

In [1]:
from IPython.display import HTML
HTML(open("notes.css", "r").read())
Out[1]:

Assignment Statements

in C,

a = 45;

is an expression, so

if (a = 45) { ... }
In [2]:
a = 45
if a = 45: print("hello")
  File "<ipython-input-2-3a8c02a375fa>", line 2
    if a = 45: print("hello")
         ^
SyntaxError: invalid syntax

Syntax:

target [= target]* = object

  • namespaces

  • the is operator (pointer equality -- usually)

In [ ]:
a = 42
b = a
a is b
In [ ]:
id(a)
In [ ]:
id(b)
In [3]:
x = 1000
y = 1000
print(x is y, x == y, id(x), id(y))
False True 139837844756688 139837844755248
In [4]:
i = 0
while True:
    x = i+1
    y = i+1
    if x is not y:
        break
    i += 1
print(i)
256
In [5]:
i = 0
while True:
    x = i-1
    y = i-1
    if x is not y:
        break
    i -= 1
print(i)
-5
In [6]:
a = 3
print(id(a))
a = a + 1
print(id(a))
9752224
9752256
In [7]:
x = 0.0
y = 0.0
print(x is y, id(x), id(y))
False 139837844755664 139837844756528

Assignment Semantics

Chain Assigments
In [8]:
a = b = 42.0
print(a is b)
True
In [9]:
a = 43.0
print(a is b)
False
Tuple (or List) Assignments
In [10]:
a, b = "doug", "dinsdale"
print(a, b)
doug dinsdale
In [11]:
a = "doug"
b = "dinsdale"
print(a,b)
doug dinsdale

This assignment is "parallel" and is equivalent to:

In [12]:
tmpB = b
tmpA = a
b = tmpA
a = tmpB
print(a,b)
dinsdale doug

Swapping does what you expect.

In [13]:
a, b = b, a
print(a, b)
doug dinsdale
Extended Iterable Unpacking

If you want only part of an iterable, this won't work:

In [14]:
letters = [ 'a', 'b', 'c', 'd' ]
(first, second) = letters
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-14-c03b7c76c5c1> in <module>
      1 letters = [ 'a', 'b', 'c', 'd' ]
----> 2 (first, second) = letters

ValueError: too many values to unpack (expected 2)
In [19]:
(first, second) = letters[:2] # probably more efficient
print(first,second)
a b
In [20]:
(first, second, *discarded) = letters
print(first,second)
a b
In [21]:
print(discarded)
['c', 'd']
In [22]:
(*beginningStuff, secondToLast, last) = letters
print(secondToLast)
print(last)
c
d
In [23]:
(first, second, *_) = letters # more pythonic
print(first,second)
a b
In [24]:
print(_)
['c', 'd']

So you can do this...

In [25]:
(first, second, *middle, last) = range(10)
print(first, second, last)
print(middle)
0 1 9
[2, 3, 4, 5, 6, 7, 8]
In [26]:
(a, b, c, *_) = (1, 2, 2, 2, 2, 3, 4, 5, 6, 7, 8, 9)
print(a, b, c, _)
1 2 2 [2, 2, 3, 4, 5, 6, 7, 8, 9]
Augmented Assignment

x += y

  • works for +, -, *, /, //, |, %, &, ^, >>, <<, **

  • ++, etc. were considered, but dropped (expression vs. statement)

In [27]:
x = 30
x %= 7
x
Out[27]:
2
target Syntax
  • going beyond name assignment

    • name

    • target.attributeName

    • target[intExpr]

      • indexing
    • target[key]

      • lookup
    • target[sliceSpec]

      • slicing
  • the latter four can be overridden with operator overloading (later), but the first cannot

In [28]:
None = True
  File "<ipython-input-28-77f9c7c0c953>", line 1
    None = True
    ^
SyntaxError: cannot assign to None
In [29]:
a = [1,2,3]
print(id(a))
a[2] = 32
a
139837896046080
Out[29]:
[1, 2, 32]
In [30]:
print(id(a))
139837896046080
In [31]:
r = range(10)
list(r[2:4])
Out[31]:
[2, 3]
Assignment Internals
In [32]:
RED = "RED"
GREEN = "GREEN"
color = RED
...
if color is RED: # slightly faster than ==
    print("red!")
red!

Simple vs. Compound Statements

  • You can put multiple simple statements on a line, separated by ;s.

  • Assignments are simple.

  • Most everything else is compound.

In [33]:
x = 19
y = 3 if x < 10 else 4
y
Out[33]:
4
In [34]:
x = 19; y = 3 if x < 10 else 4; y
Out[34]:
4
In [35]:
x = 19; y = 33
print(x,y)
if x == 19: print("x is 19")
else:       print("hello, world")
19 33
x is 19

The if Statement

In [36]:
x = 13
y = 19

if x < y:
    print('x is less than y')  # this is a block (or "suite")
    print("no, really!")
elif x == y:
    print('x is equal to y')
    print((
           1, 2,
         3, 4,
       5, 6))
    print('hello'); print('world')
else:
    print('x is greater than y')
x is less than y
no, really!
  • The Case of the Missing Case

    • it can sometimes be done with a dict
In [37]:
y = "red"
x = { "green": 2*y,
      "blue": y[-2],
      "red": 3**4
    }[y]
print(x)
81

but this is not recommended, especially since all of the expression values will get evaluated.

Loops

The for Statement

C programmers are used to loops with integer indices:

for (i = 0; i < 23; i++)
   printf("%d",i);

But Python loops are over sequences, which can be integers:

In [38]:
for i in (1, 2, 3):
    print(i)
1
2
3
In [39]:
for i in range(10):
    print(i)
0
1
2
3
4
5
6
7
8
9

... or they can be more general.

While this works:

In [40]:
colors = [ 'red', 'green', 'blue' ]
for i in range(len(colors)):
	print(colors[i])
red
green
blue

This is more pythonic (and indicates your intent better):

In [41]:
for color in colors:
    print(color)
red
green
blue

Using the plural for sequences is recommended, but you can also take a mathematical approach which is still pythonic by putting an index in the element name:

In [42]:
greeks = ['alpha','beta','gamma']
list(zip(greeks,colors))
Out[42]:
[('alpha', 'red'), ('beta', 'green'), ('gamma', 'blue')]
In [43]:
for greek_i,color_i in zip(greeks,colors): 
    print(greek_i, color_i)
alpha red
beta green
gamma blue

Use enumerate() to get an index if you need it...

In [44]:
list(enumerate(colors))
Out[44]:
[(0, 'red'), (1, 'green'), (2, 'blue')]
In [45]:
for i, color in enumerate(colors): 
    print(i,color)
0 red
1 green
2 blue
The while Statement

This should be familiar...

In [46]:
x = 1
while x < 100:  # test being performed
	x = 2 * x
	print(x)
2
4
8
16
32
64
128

but Python has an "else" clause...

In [47]:
x = 1
while x < 100:  # test being performed
	x = 2 * x
	print(x)
	if x == 1000:
		break
else:
	print(f'loop finished without hitting break, x = {x}')
x
2
4
8
16
32
64
128
loop finished without hitting break, x = 128
Out[47]:
128

Comprehensions

Set Comprehensions
In [48]:
{ 2*i for i in range(20) }
Out[48]:
{0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38}

Note: These elements appear in order because that's the way they were created. In general, you cannot count on sets to have any order in Python.

List Comprehensions
In [54]:
[ 2*i for i in range(20) ]
Out[54]:
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38]
Dictionary Comprehensions
In [55]:
{ i:hex(i) for i in range(20) }
Out[55]:
{0: '0x0',
 1: '0x1',
 2: '0x2',
 3: '0x3',
 4: '0x4',
 5: '0x5',
 6: '0x6',
 7: '0x7',
 8: '0x8',
 9: '0x9',
 10: '0xa',
 11: '0xb',
 12: '0xc',
 13: '0xd',
 14: '0xe',
 15: '0xf',
 16: '0x10',
 17: '0x11',
 18: '0x12',
 19: '0x13'}
Comprehensions vs. Generators

Parentheses around a comprehension-like expression creates a generator.

In [68]:
gen = ( i**2 for i in range(20) )
gen
Out[68]:
<generator object <genexpr> at 0x7f2e73fef270>
In [69]:
gen.__next__()
Out[69]:
0
In [70]:
gen.__next__()
Out[70]:
1
In [71]:
gen.__next__()
Out[71]:
4
In [72]:
print(list(gen))
[9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225, 256, 289, 324, 361]

Comprehension evalations aren't lazy. (We'll explain.)

The del Statement

Applied to a name, it removes it from the namespace.

In [74]:
x = 42
y = x
print(x)
del x
print(y)
if 1:
    print(x)
42
42
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-74-0b0eaf7111a9> in <module>
      5 print(y)
      6 if 1:
----> 7     print(x)

NameError: name 'x' is not defined

Applied to a list or dictionary, can remove an element:

In [75]:
l = [ 1, 3, 5, 7 ]
print(l)
del l[1]
print(l)
[1, 3, 5, 7]
[1, 5, 7]
In [78]:
d = { 'red':"rojo", 'green':'verde', 'blue':'azul' }
print(d)
del d['blue']
print(d)
{'red': 'rojo', 'green': 'verde', 'blue': 'azul'}
{'red': 'rojo', 'green': 'verde'}
  • this is a simple statement
  • deleting names not usually necessary, but sometimes helpful in interactive testing

The pass Statement

In [ ]:
pass
  • does nothing
  • main use: a placeholder
  • this is a simple statement
In [ ]:
x = 94
if x == 3:
    pass
else:
    print("hello")
In [81]:
def aFunc():
    pass

aFunc()
In [ ]: