18. Advanced Features
Help you write more Pythonic code with some advanced features in Python.
- Conditional expressions
- List comprehensions
- Generator expressions
- any and all
- Sets
- Counters
- Named tuples
- Gathering keyword args
import math
x = float(input())
if x > 0:
y = math.log(x)
else:
y = float('nan') # a special floating-point value that represents “Not a Number”.
print(y)
A more concise expression:
y = math.log(x) if x > 0 else float('nan')
Another example:
def factorial(n):
if n == 0:
return 1
else:
return n * factorial(n-1)
def factorial(n):
return 1 if n == 0 else n * factorial(n-1)
def capitalize_all(t):
res = []
for s in t:
res.append(s.capitalize())
return res
def capitalize_all(t):
return [s.capitalize() for s in t]
List comprehensions can also be used for filtering.
def only_upper(t):
res = []
for s in t:
if s.isupper():
res.append(s)
return res
def only_upper(t):
return [s for s in t if s.isupper()]
Note: list comprehensions are harder to debug because you can’t put a print statement inside the loop. I suggest that you use them only if the computation is simple enough that you are likely to get it right the first time. And for beginners that means never.
L = [x * x for x in range(5)]
L
g = (x * x for x in range(5))
g
next(g)
next(g)
next(g)
next(g)
next(g)
next(g)
Another way to write generator: yield
def fib(max):
n, a, b = 0, 0, 1
while n < max:
yield b
a, b = b, a + b
n = n + 1
return 'done'
f = fib(4)
f
next(f)
next(f)
next(f)
next(f)
next(f)
any([False, False, True])
any(letter == 's' for letter in 'babson')
Python provides another built-in function, all
, that returns True
if every element of the sequence is True
.
all([False, True, True])
all([True, True, True])
all(letter == 'w' for letter in 'www')
s = set([1, 2, 3, 3])
s
s.add(4)
s
s.add(4)
s
set
works like set in math.
s1 = set([1, 2, 3])
s2 = set([2, 3, 4])
s1 & s2
s1 | s2
from collections import Counter
count = Counter('babson')
count
count['a']
count['c']
class Point:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def __str__(self):
return '(%g, %g)' % (self.x, self.y)
This is a lot of code to convey a small amount of information. Python provides a more concise way to say the same thing:
from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'])
Point
By using namedtuple
, Point
automatically provides methods like __init__
and __str__
so you don’t have to write them.
To create a Point
object, you use the Point
class as a function:
p = Point(1, 2)
p
p.x, p.y
namedtuple
provide a quick way to define simple classes. The drawback is that simple classes don’t always stay simple. You might decide later that you want to add methods to a named tuple. In that case, you could define a new class that inherits from the namedtuple
:
class Pointier(Point):
# add more methods here
def printall(*args):
print(args)
printall(1, 2.0, '3')
But the *
operator doesn’t gather keyword arguments:
printall(1, 2.0, third='3')
To gather keyword arguments, you can use the **
operator:
def printall(*args, **kwargs):
print(args, kwargs)
printall(1, 2.0, third='3')