{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Chapter 1 — The Python Data Model\n", "\n", "**Sections with code snippets in this chapter:**\n", "\n", "* [A Pythonic Card Deck](#A-Pythonic-Card-Deck)\n", "* [Emulating Numeric Types](#Emulating-Numeric-Types)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## A Pythonic Card Deck" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Example 1-1. A deck as a sequence of playing cards" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import collections\n", "\n", "Card = collections.namedtuple('Card', ['rank', 'suit'])\n", "\n", "class FrenchDeck:\n", " ranks = [str(n) for n in range(2, 11)] + list('JQKA')\n", " suits = 'spades diamonds clubs hearts'.split()\n", "\n", " def __init__(self):\n", " self._cards = [Card(rank, suit) for suit in self.suits for rank in self.ranks]\n", "\n", " def __len__(self):\n", " return len(self._cards)\n", "\n", " def __getitem__(self, position):\n", " return self._cards[position]" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Card(rank='7', suit='diamonds')" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "beer_card = Card('7', 'diamonds')\n", "beer_card" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "52" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "deck = FrenchDeck()\n", "len(deck)" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Card(rank='2', suit='spades')" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "deck[0]" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Card(rank='A', suit='hearts')" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "deck[-1]" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Card(rank='6', suit='diamonds')" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# NBVAL_IGNORE_OUTPUT\n", "from random import choice\n", "\n", "choice(deck)" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[Card(rank='2', suit='spades'),\n", " Card(rank='3', suit='spades'),\n", " Card(rank='4', suit='spades')]" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "deck[:3]" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[Card(rank='A', suit='spades'),\n", " Card(rank='A', suit='diamonds'),\n", " Card(rank='A', suit='clubs'),\n", " Card(rank='A', suit='hearts')]" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "deck[12::13]" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Card(rank='2', suit='spades')\n", "Card(rank='3', suit='spades')\n", "Card(rank='4', suit='spades')\n", "Card(rank='5', suit='spades')\n", "Card(rank='6', suit='spades')\n", "Card(rank='7', suit='spades')\n", "Card(rank='8', suit='spades')\n", "Card(rank='9', suit='spades')\n", "Card(rank='10', suit='spades')\n", "Card(rank='J', suit='spades')\n", "Card(rank='Q', suit='spades')\n", "Card(rank='K', suit='spades')\n", "Card(rank='A', suit='spades')\n", "Card(rank='2', suit='diamonds')\n", "Card(rank='3', suit='diamonds')\n", "Card(rank='4', suit='diamonds')\n", "Card(rank='5', suit='diamonds')\n", "Card(rank='6', suit='diamonds')\n", "Card(rank='7', suit='diamonds')\n", "Card(rank='8', suit='diamonds')\n", "Card(rank='9', suit='diamonds')\n", "Card(rank='10', suit='diamonds')\n", "Card(rank='J', suit='diamonds')\n", "Card(rank='Q', suit='diamonds')\n", "Card(rank='K', suit='diamonds')\n", "Card(rank='A', suit='diamonds')\n", "Card(rank='2', suit='clubs')\n", "Card(rank='3', suit='clubs')\n", "Card(rank='4', suit='clubs')\n", "Card(rank='5', suit='clubs')\n", "Card(rank='6', suit='clubs')\n", "Card(rank='7', suit='clubs')\n", "Card(rank='8', suit='clubs')\n", "Card(rank='9', suit='clubs')\n", "Card(rank='10', suit='clubs')\n", "Card(rank='J', suit='clubs')\n", "Card(rank='Q', suit='clubs')\n", "Card(rank='K', suit='clubs')\n", "Card(rank='A', suit='clubs')\n", "Card(rank='2', suit='hearts')\n", "Card(rank='3', suit='hearts')\n", "Card(rank='4', suit='hearts')\n", "Card(rank='5', suit='hearts')\n", "Card(rank='6', suit='hearts')\n", "Card(rank='7', suit='hearts')\n", "Card(rank='8', suit='hearts')\n", "Card(rank='9', suit='hearts')\n", "Card(rank='10', suit='hearts')\n", "Card(rank='J', suit='hearts')\n", "Card(rank='Q', suit='hearts')\n", "Card(rank='K', suit='hearts')\n", "Card(rank='A', suit='hearts')\n" ] } ], "source": [ "for card in deck:\n", " print(card)" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Card(rank='A', suit='hearts')\n", "Card(rank='K', suit='hearts')\n", "Card(rank='Q', suit='hearts')\n", "Card(rank='J', suit='hearts')\n", "Card(rank='10', suit='hearts')\n", "Card(rank='9', suit='hearts')\n", "Card(rank='8', suit='hearts')\n", "Card(rank='7', suit='hearts')\n", "Card(rank='6', suit='hearts')\n", "Card(rank='5', suit='hearts')\n", "Card(rank='4', suit='hearts')\n", "Card(rank='3', suit='hearts')\n", "Card(rank='2', suit='hearts')\n", "Card(rank='A', suit='clubs')\n", "Card(rank='K', suit='clubs')\n", "Card(rank='Q', suit='clubs')\n", "Card(rank='J', suit='clubs')\n", "Card(rank='10', suit='clubs')\n", "Card(rank='9', suit='clubs')\n", "Card(rank='8', suit='clubs')\n", "Card(rank='7', suit='clubs')\n", "Card(rank='6', suit='clubs')\n", "Card(rank='5', suit='clubs')\n", "Card(rank='4', suit='clubs')\n", "Card(rank='3', suit='clubs')\n", "Card(rank='2', suit='clubs')\n", "Card(rank='A', suit='diamonds')\n", "Card(rank='K', suit='diamonds')\n", "Card(rank='Q', suit='diamonds')\n", "Card(rank='J', suit='diamonds')\n", "Card(rank='10', suit='diamonds')\n", "Card(rank='9', suit='diamonds')\n", "Card(rank='8', suit='diamonds')\n", "Card(rank='7', suit='diamonds')\n", "Card(rank='6', suit='diamonds')\n", "Card(rank='5', suit='diamonds')\n", "Card(rank='4', suit='diamonds')\n", "Card(rank='3', suit='diamonds')\n", "Card(rank='2', suit='diamonds')\n", "Card(rank='A', suit='spades')\n", "Card(rank='K', suit='spades')\n", "Card(rank='Q', suit='spades')\n", "Card(rank='J', suit='spades')\n", "Card(rank='10', suit='spades')\n", "Card(rank='9', suit='spades')\n", "Card(rank='8', suit='spades')\n", "Card(rank='7', suit='spades')\n", "Card(rank='6', suit='spades')\n", "Card(rank='5', suit='spades')\n", "Card(rank='4', suit='spades')\n", "Card(rank='3', suit='spades')\n", "Card(rank='2', suit='spades')\n" ] } ], "source": [ "for card in reversed(deck):\n", " print(card)" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Card('Q', 'hearts') in deck" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Card('7', 'beasts') in deck" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Card(rank='2', suit='clubs')\n", "Card(rank='2', suit='diamonds')\n", "Card(rank='2', suit='hearts')\n", "Card(rank='2', suit='spades')\n", "Card(rank='3', suit='clubs')\n", "Card(rank='3', suit='diamonds')\n", "Card(rank='3', suit='hearts')\n", "Card(rank='3', suit='spades')\n", "Card(rank='4', suit='clubs')\n", "Card(rank='4', suit='diamonds')\n", "Card(rank='4', suit='hearts')\n", "Card(rank='4', suit='spades')\n", "Card(rank='5', suit='clubs')\n", "Card(rank='5', suit='diamonds')\n", "Card(rank='5', suit='hearts')\n", "Card(rank='5', suit='spades')\n", "Card(rank='6', suit='clubs')\n", "Card(rank='6', suit='diamonds')\n", "Card(rank='6', suit='hearts')\n", "Card(rank='6', suit='spades')\n", "Card(rank='7', suit='clubs')\n", "Card(rank='7', suit='diamonds')\n", "Card(rank='7', suit='hearts')\n", "Card(rank='7', suit='spades')\n", "Card(rank='8', suit='clubs')\n", "Card(rank='8', suit='diamonds')\n", "Card(rank='8', suit='hearts')\n", "Card(rank='8', suit='spades')\n", "Card(rank='9', suit='clubs')\n", "Card(rank='9', suit='diamonds')\n", "Card(rank='9', suit='hearts')\n", "Card(rank='9', suit='spades')\n", "Card(rank='10', suit='clubs')\n", "Card(rank='10', suit='diamonds')\n", "Card(rank='10', suit='hearts')\n", "Card(rank='10', suit='spades')\n", "Card(rank='J', suit='clubs')\n", "Card(rank='J', suit='diamonds')\n", "Card(rank='J', suit='hearts')\n", "Card(rank='J', suit='spades')\n", "Card(rank='Q', suit='clubs')\n", "Card(rank='Q', suit='diamonds')\n", "Card(rank='Q', suit='hearts')\n", "Card(rank='Q', suit='spades')\n", "Card(rank='K', suit='clubs')\n", "Card(rank='K', suit='diamonds')\n", "Card(rank='K', suit='hearts')\n", "Card(rank='K', suit='spades')\n", "Card(rank='A', suit='clubs')\n", "Card(rank='A', suit='diamonds')\n", "Card(rank='A', suit='hearts')\n", "Card(rank='A', suit='spades')\n" ] } ], "source": [ "suit_values = dict(spades=3, hearts=2, diamonds=1, clubs=0)\n", "\n", "def spades_high(card):\n", " rank_value = FrenchDeck.ranks.index(card.rank)\n", " return rank_value * len(suit_values) + suit_values[card.suit]\n", "\n", "for card in sorted(deck, key=spades_high):\n", " print(card)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Emulating Numeric Types" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Example 1-2. A simple two-dimensional vector class" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [], "source": [ "import math\n", "\n", "class Vector:\n", "\n", " def __init__(self, x=0, y=0):\n", " self.x = x\n", " self.y = y\n", "\n", " def __repr__(self):\n", " return 'Vector(%r, %r)' % (self.x, self.y)\n", "\n", " def __abs__(self):\n", " return math.hypot(self.x, self.y)\n", "\n", " def __bool__(self):\n", " return bool(abs(self))\n", "\n", " def __add__(self, other):\n", " x = self.x + other.x\n", " y = self.y + other.y\n", " return Vector(x, y)\n", "\n", " def __mul__(self, scalar):\n", " return Vector(self.x * scalar, self.y * scalar)" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Vector(4, 5)" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v1 = Vector(2, 4)\n", "v2 = Vector(2, 1)\n", "v1 + v2" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5.0" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v = Vector(3, 4)\n", "abs(v)" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Vector(9, 12)" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v * 3" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "15.0" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "abs(v * 3)" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.0" } }, "nbformat": 4, "nbformat_minor": 2 }