list comprehension
l = [i * 2 for i in range(10)] # list
d = {i: i * 2 for in in range(10)} # dict
s = {i for i in range(10)} # set
g = (i for i in range(10)) # generator
combine two comprehension
[(x,y) for x in range(5) for y in range(3)]
this is equal to
l = []
for x in range(5):
for y in range(3):
l.append((x,y))
combine if statement with comprehension
values = [x / (x -y)
for x in range(100)
if x > 50]
this is equal to
values = []
for x in range(100):
if x > 50:
values.append(x/(x-y))
### map
map takes a function, and an iteratable, and return a map function object, it will be evaluated until it was called, aka lazy loading
for c in map(ord, 'some char'):
print(c)
ord is a function convert char to codepoint
def combine(size, color, animal):
return '{} {} {}'.format(size, color, animal)
sizes = ['small', 'medium', 'large']
colors = ['lavender', 'teal', 'burnt orange']
animals = ['koala', 'platypus', 'salamander']
list(map(combine, sizes, colors, animals))
filter
filter(is_odd, [1,2,3,4,5,6])
reduce
from functools import reduce
import operator
reduce(operator.add, [1,2,3,4,5])
iterable
an object which implements the __iter__()
method and which implements the __next__()
method, and raise StopIteration
when finish iterator
class ExampleIterator:
def __init__(self, data):
self.index = 0
self.data = data
def __iter__(self):
return self
def __next__(self):
if self.index >= len(self.data):
raise StopIteration()
rslt = self.data[self.index]
self.index += 1
return rslt
class ExampleIterable:
def __init__(self):
self.data = [1,2,3]
def __iter__(self):
return ExampleIterator(self.data)
or we can implement __getitem__
as an alternative approach
class AlternateIterable:
def __init__(self):
self.data = [1,2,3]
def __getitem__(self, idx):
return self.data[idx]
iter
iter(calable, sentinel)
iteration stops when callable produces the value same as sentinel
for example:
import datetime
i = iter(datetime.datetime.now, None)
next(i)
next(i)
datetime.datetime.now is a function, and it will never return None, so this become an infinite iter
summary
import datetime
import itertools
import random
import time
class Sensor:
def __iter__(self):
return self
def __next__(self):
return random.random()
sensor = Sensor()
timestamps = iter(datetime.datetime.now, None)
for stamp, value in itertools.islice(zip(timestamps, sensor), 10):
print(stamp, value)
time.sleep(1)
container protocol
to implement __contains__
, you can test if the element in the container by calling item in container
class TestContainerProtocal(unittest.TestCase):
def setUp(self):
self.s = SortedSet([6,7,4,9])
def test_positive_contained(self):
self.assertTrue(6 in self.s)
def test_negative_contained(self):
self.assertFalse(2 in self.s)
def test_positive_not_contained(self):
self.assertTrue(5 not in self.s)
class SortedSet:
def __init__(self, items=None):
self._items = sorted(items) if items is not None else []
def __contains__(self, item):
return item in self._items
sized protocol
Number of items using len(sized) function
Must not consume or modify collection
to implement the special method __len__()
def __len__(self):
return len(self._items)
iter protocol
class SortedSet:
def __init__(self, items=None):
self._items = sorted(set(items)) if items is not None else []
def __iter__(self):
return iter(self._items)
class TestIterableProtocol(unittest.TestCase):
def setUp(self):
self.s = SortedSet([2,3,1,4])
def test_for_loop(self):
index = 0
expected = [1,2,3,4]
for item in self.s:
self.assertEqual(item, expected[index])
index += 1
sequence protocol
to implement __getitem__
method, we can call item[5] this is same as c# list accessor
class SortedSet:
def __init__(self, items=None):
self._items = sorted(set(items)) if items is not None else []
def __getitem__(self, index):
result = self._items[index]
return SortedSet(result) if isinstance(index, slice) else result
def __repr__(self):
return "SortedSet({})".format(
repr(self._items) if self._items else ''
)
class TestSequenceProtocol(unittest.TestCase):
def setUp(self):
self.s = SortedSet([1,4,56,3,2])
def test_index_zero(self):
self.assertEqual(self.s[0], 1)
def test_index_one_beyond_the_end(self):
with self.assertRaises(IndexError):
self.s[5]
def test_slice_to_end(self):
self.assertEqual(self.s[:3], SortedSet([1,2,3]))
to implment slice function list[:3]
, we need to check if the second parameter of __getitem__
is instanceof slice, if it is slice, then return a new SortedSet, otherwise return the result, this still cannot pass the test
because we haven’t implement equal function to test if two SortSet are equal
### implement __eq__
and __ne__
python check for reference by default, by implement __eq__
and __ne__
we can test two object
notice that it’s return
NotImplemented instead of raise
NotImplemented
```
def eq(self, rhs):
if not isinstance(rhs, SortedSet):
return NotImplemented
return self._items == rhs._items
def nq(self, rhs): if not isinstance(rhs, SortedSet): return NotImplemented return self._items != rhs._items ```
inherate from collections.abc.Sequence
abc stands for abstract base class
from collections.abc import Sequence
class SortedSet(Sequence):
pass
__add__
from itertools import chain
def __add__(self, rsh):
return SortedSet(chain(self._items, rhs._items)
__mul__() and __rmul()__
def __mul__(self, rhs):
return self if rhs > 0 else SortedSet()
blog comments powered by Disqus