Python Digs Sequences


In [3]:
class Foo:
    def __getitem__(self, pos):
        return range(0, 30, 10)[pos]

In [4]:
f = Foo()
f[1]


Out[4]:
10

In [5]:
for i in f: print(i)


0
10
20

In [6]:
20 in f


Out[6]:
True

In [7]:
15 in f


Out[7]:
False

Monkey-Patching to Implement a Protocol at Runtime


In [9]:
from random import shuffle
l = list(range(10))
shuffle(l)
l


Out[9]:
[5, 3, 7, 6, 9, 8, 4, 0, 1, 2]

In [10]:
import collections

Card = collections.namedtuple('Card', ['rank', 'suit'])

class FrenchDeck:
    ranks = [str(n) for n in range(2, 11)] + list('JQKA')
    suits = 'spades diamonds clubs hearts'.split()
    
    def __init__(self):
        self._cards = [Card(rank, suit) for suit in self.suits
                                        for rank in self.ranks]
        
    def __len__(self):
        return len(self._cards)
    
    def __getitem__(self, position):
        return self._cards[position]

In [13]:
deck = FrenchDeck()
shuffle(deck)


---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-13-073dfb875881> in <module>()
      1 deck = FrenchDeck()
----> 2 shuffle(deck)

c:\users\langestrst01\appdata\local\continuum\anaconda3\envs\fluentpy\lib\random.py in shuffle(self, x, random)
    270                 # pick an element in x[:i+1] with which to exchange x[i]
    271                 j = randbelow(i+1)
--> 272                 x[i], x[j] = x[j], x[i]
    273         else:
    274             _int = int

TypeError: 'FrenchDeck' object does not support item assignment

In [14]:
def set_card(deck, position, card):
    deck._cards[position] = card

In [15]:
FrenchDeck.__setitem__ = set_card

In [16]:
shuffle(deck)

In [18]:
print(deck[:5])


[Card(rank='Q', suit='clubs'), Card(rank='A', suit='hearts'), Card(rank='3', suit='diamonds'), Card(rank='J', suit='diamonds'), Card(rank='7', suit='hearts')]

Alex Martelli's Waterfowl


In [19]:
class Struggle:
    def __len__(self): return 23
    
from collections import abc
isinstance(Struggle(), abc.Sized)


Out[19]:
True

In [ ]:
try:
    field_names = field_names.replace(',',' ').split()
except AttributeError:
    pass
field_names = tuple(field_names)

Subclassing an ABC


In [21]:
import collections

Card = collections.namedtuple('Card', ['rank', 'suit'])

class FrenchDeck2(collections.MutableSequence):
    ranks = [str(n) for n in range(2, 11)] + list('JQKA')
    suits = 'spades diamonds clubs hearts'.split()
    
    def __init__(self):
        self._cards = [Card(rank, suit) for suit in self.suits
                                        for rank in self.ranks]
        
    def __len__(self):
        return len(self._cards)
    
    def __getitem__(self, position):
        return self._cards[position]
    
    def __setitem__(self, position, value):
        self._cards[position] = value
        
    def __delitem__(self, position):
        del self._cards[position]
        
    def insert(self, position, value):
        self._cards.insert(position, value)

Defining and Using an ABC


In [1]:
import abc

In [3]:
import abc

class Tombola(abc.ABC):
    
    @abc.abstractmethod
    def load(self, iterable):
        """Add items from an iterable"""
        
    @abc.abstractmethod
    def pick(self):
        """Remove item at random, returning it
        
        This method should raise 'LookupError' when the instance is empty.
        """
        
    def loaded(self):
        """Return 'True' if there's at least 1 item, 'False' otherwise."""
        return bool(self.inspect())
    
    def inspect(self):
        """Return a sorted tuple with the items currently inside."""
        items = []
        while True:
            try:
                items.append(self.pick())
            except LookupError:
                break
        self.load(items)
        return tuple(sorted(items))

In [4]:
class Fake(Tombola):
    def pick(self):
        return 13

In [7]:
Fake


Out[7]:
__main__.Fake

In [8]:
f = Fake()


---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-8-eb09ed8f651b> in <module>()
----> 1 f = Fake()

TypeError: Can't instantiate abstract class Fake with abstract methods load

Subclassing the Tombola ABC


In [12]:
import random

class BingoCage(Tombola):
    
    def __init__(self, items):
        self._randomizer = random.SystemRandom()
        self._items = []
        self.load(items)
        
    def load(self, items):
        self._items.extend(items)
        self._randomizer.shuffle(self._items)
        
    def pick(self):
        try:
            return self._items.pop()
        except IndexError:
            raise LookupError('pick from empty BingoCage')
            
    def __call__(self):
        self.pick()

In [13]:
import random

class LotteryBlower(Tombola):
    
    def __init__(self, iterable):
        self._balls = list(iterable)
        
    def load(self, iterable):
        self._balls.extend(iterable)
        
    def pick(self):
        try:
            position = random.randrange(len(self._balls))
        except ValueError:
            raise LookupError('pick from empty LotteryBlower')
        return self._balls.pop(position)
    
    def loaded(self):
        return bool(self._balls)
    
    def inspect(self):
        return tuple(sorted(self._balls))

A Virtual Subclass of Tombola


In [14]:
from random import randrange

@Tombola.register
class TomboList(list):
    
    def pick(self):
        if self:
            position = randrange(len(self))
            return self.pop(position)
        else:
            raise LookupError('pop from empty TomboList')
            
    load = list.extend
    
    def loaded(self):
        return bool(self)
    
    def inspect(self):
        return tuple(sorted(self))

In [ ]: