Today: comprehensions, truthy logic, format strings
>>> nums = [1, 2, 3, 4, 5, 6] >>> [n for n in nums if n > 3] [4, 5, 6] >>> [n * n for n in nums if n > 3] [16, 25, 36]
Can get into Comprehension Fever - trying to write your whole program as nested comprehensions. Probably 1-line is the sweet spot.
Fine to use regular functions, loops etc. for longer phrases of code.
Section on server: Comprehensions
> diff21
Solutions
def dif21(nums):
return [abs(n - 21) for n in nums]
def teen_only(nums):
return [n for n in nums if n >= 13 and n <= 19]
These are all 1-liner solutions with comprehensions. We'll just do 1 or 2 of these.
Syntax reminder - e.g. make a list of nums doubled where n > 3
[2 * n for n in nums if n > 3]
> first_up
first_up: Given a list of non-empty strings. return a list of their first chars converted to upper case.
> up_only
up_only: Given a list of non-empty strings. Return a list made of just the strings that begin with an uppercase char. Write as a 1-line comprehension. Use if
# int 3 100 -2 # float, has a "." 3.14 -26.2 6.022e23
/ always yields float
>>> 5 / 2 # / yields float 2.5 >>> 4 / 2 2.0 >>> >>> 1 + 1 + 1 3 >>> 1 + 1 + 1.0 # float promotion 3.0 >>> 3.14 * 2 6.28 >>>
>>> float('3.14') # str -> float
3.14
>>> int(3.14) # float -> int, truncation
3
>>> int('16')
16
>>> int('3.14')
ValueError: invalid literal for int() with base 10: '3.14'
>>> 0.1 0.1 >>> 0.1 + 0.1 0.2 >>> 0.1 + 0.1 + 0.1 # this is why we can't have nice things 0.30000000000000004 >>> >>> 0.1 + 0.1 + 0.1 + 0.1 0.4 >>> 0.1 + 0.1 + 0.1 + 0.1 + 0.1 0.5 >>> 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 0.6 >>> 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 0.7 >>> 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 0.7999999999999999 # here the garbage is negative
Another example with 3.14
>>> 3.14 * 3 9.42 >>> 3.14 * 4 12.56 >>> 3.14 * 5 15.700000000000001 # d'oh
Conclusion: float math is slightly wrong
The short answer, is that with a fixed number of bytes to store a floating point number in memory, there are some unavoidable problems where numbers have these garbage digits on the far right. It is similar to the impossibility of writing number 1/3 precisely as a decimal number — 0.3333 is close, but falls a little short.
>>> a = 3.14 * 5 >>> b = 3.14 * 6 - 3.14 >>> a == b # Observe == not working right False >>> b 15.7 >>> a 15.700000000000001
>>> abs(a-b) < 0.00001 True
For more detail see "truthy" section in the if-chapter Python If - Truthy
s = 'hello'
# Could do this:
if len(s) > 0:
print('not empty')
# Equivalent this way:
if s:
print('not empty')
Truthy logic says that "empty" values count as False. These all count as False - zero, emtpy-string, empty-list,...
# Count as False:
0
0.0
None
''
[]
{}
Any other value counts as True
# Count as True
6
3.14
'Hello'
[1, 2]
{1: 'b'}
The bool() function takes
any value and returns a formal bool False/True value, so it's a way for us to see how truthy logic works in the interpreter:
>>> bool(0)
False
>>> bool(0.0)
False
>>> bool('') # empty string - False
False
>>> bool([]) # empty list - False
False
>>> bool(None)
False
>>> bool(6) # non-zero int - True
True
>>> bool('hi') # non-empty string - True
True
>>> bool([1, 2]) # list of something - True
True
>>> bool('False') # ??? - what's this one?
???
>>> bool([0, 0]) # ???
???
>>>
Why does the truthy system exist? It makes it easy to test, for example, for an empty string like the following. Testing for "empty" data is such a common case, it's nice to have a shorthand for it. For CS106A, you don't ever need to use this shorthand, but it's there if you want to use it. Also, many other computer languages also use this truthy system.
# long form screen out empty string
if len(s) > 0:
print(s)
# shorter way, handy!
if s:
print(s)
s = f'A format string'
Try in the interpreter:
>>> name = 'Sally'
>>> scores = [19, 34, 22]
>>>
>>> s = f'Name:{name} count:{len(scores)}'
>>> s
'Name:Sally count:3'
>>> s = f'Name:{name} count:{len(scores)} max score:{max(scores)}'
>>> s
'Name:Sally count:3 max score:34'
Amazingly, within the curly braces, just write any old expression like {name} referring to a variable, or even max(scores) which calls a function, pasting in what it returns.
To include a literal { or } in the string, double them up - so {{ to make one {
>>> f'A curly brace: {{'
'A curly brace: {'
Within the curly braces, a colon : added to the end of a value enables various format options. For floating point, adding :.4 after the floating point value will limit the number fraction digits shown to 4, like this:
>>> 2 / 3
0.6666666666666666
>>> x = 2 / 3
>>> f'val: {x}' # {x} - too many digits
'val: 0.6666666666666666'
>>> f'val: {x:.4}' # {x:.4} - limit digits
'val: 0.6667'
Visit lecture-23 - finish off packet demo - how internet works. Show ping and traceroute.