In [3]:
    
class Foo:
    def __getitem__(self, pos):
        return range(0, 30, 10)[pos]
    
In [4]:
    
f = Foo()
f[1]
    
    Out[4]:
In [5]:
    
for i in f: print(i)
    
    
In [6]:
    
20 in f
    
    Out[6]:
In [7]:
    
15 in f
    
    Out[7]:
In [9]:
    
from random import shuffle
l = list(range(10))
shuffle(l)
l
    
    Out[9]:
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)
    
    
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])
    
    
In [19]:
    
class Struggle:
    def __len__(self): return 23
    
from collections import abc
isinstance(Struggle(), abc.Sized)
    
    Out[19]:
In [ ]:
    
try:
    field_names = field_names.replace(',',' ').split()
except AttributeError:
    pass
field_names = tuple(field_names)
    
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)
    
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]:
In [8]:
    
f = Fake()
    
    
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))
    
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 [ ]: