{ "cells": [ { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Intro to Enums\n", "\n", "> Andrew Kubera\n", "\n", "> COhPy - Feb 26, 2018" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### What is an Enumerated Type?\n", "\n", "* Simply a type comprising a finite-set of named values" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "* Standard example is a card suit:\n", "```\n", " Hearts, Spades, Diamonds, Clubs\n", "```" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "* Most languages store these internally as as simple integers\n", " * Compilers often typecheck, providing some safety\n", " * Easily copiable " ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "Enumerated types are a common tool in programming languages:\n", "\n", "* C-based\n", "* Java\n", "* Rust\n", "* Swift\n", "* TypeScript\n", "* Haskell\n", "* Lisp" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "- Missing : JavaScript, Ruby, *Python???*\n", " - Unnecessary in dynamically-typed languages?" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "`enum` module added to Python standard library in version *3.4*" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Here's how to use it:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "from enum import Enum" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "class A(Enum):\n", " X = 1\n", " Y = 2\n", " Z = 3" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Access members as usual:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "A.X" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": false, "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "A.X == 1" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "A.X == A.X" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "A.Y == A.X" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "a = A.X\n", "b = A.X\n", "\n", "a is b" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "Values may be looked up by \"name\" using `[ ]` notation" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "key = \"Y\"\n", "\n", "...\n", "\n", "A[key]" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Enums have dict-like access!" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "A[key] is A.Y" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Also supports \"backwards\" lookup via `( )`:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "A(1)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "(note: this would *usually* be creating a new object of type `A`)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "**Bidirectional mapping** between a name (string) and some value!" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### \"Standard\" errors when doing lookups" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "A.W # AttributeError" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "A['W'] # KeyError" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "A[1] # KeyError" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "A(9) # ValueError" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Iteration over members\n", "\n", "Enums are *iterable* over all values (order is preserved)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "list(A)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Alternative means of construction" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "B = Enum(\"B\", \"X Y Z\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "B.X" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "B(3)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "B = Enum(\"B\", [('X', 90), ('Y', 45)])" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "B.X" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Lets look more at the values..." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "# Values can be mixed types\n", "class B(Enum):\n", " X = 1\n", " Y = \"some string.\"\n", " Z = 0.3\n", " L = [] # note the list!" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "B(\"some string.\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "B([])" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": true, "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "B(0.3)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "BTW, you should **NOT** use floating points to do indexing" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "key = 0.1 + 0.2" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "B(key) # B(0.3)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Namedtuple like behavior" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "# Cannot reassign values\n", "B.X = 2" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "B.L.append(1)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "We will have to start thinking differently....." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Look deeper at the values" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "class A(Enum):\n", " X = 1\n", " Y = 2\n", " Z = 3" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "A.X" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "isinstance(A.X, int)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "isinstance(A.X, A)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "type(A.X)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "When creating the class:\n", "\n", "* The members are \"intercepted\" and wrapped with instances of the class.\n", "* After that, the class is \"frozen\" and *no further instances* may be created" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "One little \"goof\":" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "A.X.X.Y" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "-" } }, "source": [ "^ Because instances of objects have access to members of their class, all enums have each-other as attributes (Don't use this!)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "So where are `1, 2, 3` in A?" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "A.X.value" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "A.X.name" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "The `value` & `name` attributes are ***the*** important things to know about python Enums " ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "B.L" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "B.L.value.append(7)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "B.L" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "So they are *semi-*immutable (like tuples)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Methods" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "class A(Enum):\n", " X = 1\n", " Y = 2\n", " \n", " def add_ten(self):\n", " return self.value + 10" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": true, "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "list(A)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "`add_ten` **not** included as enum member -- behaves as typical python method" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "A.add_ten" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "A.X.add_ten()" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "class C(Enum):\n", " X = 1\n", " Y = lambda a: print('Y(a=%r)' % a)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "list(C)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "C.X.Y() " ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "So lambdas are interpreted as methods (as usual)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "Can I get a little crazy now?" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "class A(Enum):\n", " \n", " class J:\n", " def __init__(self):\n", " print(\"constructing J\")\n", " \n", " class M:\n", " def __init__(self):\n", " print(\"constructing M\")\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "list(A)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "m = A.M.value()" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "type(m)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "class A(Enum):\n", " \n", " class J:\n", " def __init__(self):\n", " print(\"constructing J\")\n", " \n", " class M:\n", " def __init__(self):\n", " print(\"constructing M\")\n", "\n", " def New(self):\n", " return self.value()\n", " \n", " @classmethod\n", " def From(cls, foo):\n", " return cls[foo.upper()].New()" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "classname = 'J'\n", "A[classname].New()" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "A.From('m')" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "Back to basics..." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Cannot subclass Enums" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "class A(Enum):\n", " X = 1\n", " Y = 2" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": true, "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "# TypeError: Cannot extend enumerations\n", "class B(A):\n", " Z = 3" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "[(a.name, a.value) for a in A] " ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": true, "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "B = Enum(\"B\", [(a.name, a.value) for a in A] + [('Z', 3)])\n", "list(B)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Other Enums" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### IntEnum\n", "\n", "* The values must be integers\n", " * Or rather, they are `int()` compatible\n", "* The type inherits from `int`, so comparisons works \n", " * no need for `.value`" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "from enum import IntEnum" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "class A(IntEnum):\n", " X = 1\n", " Y = 2" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "A.X" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "A.X == 1" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "class B(IntEnum):\n", " X = 1\n", " Y = '2'" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "B.Y == 2" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "B('2')" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### Flag & IntFlag\n", "\n", "* New in py3.6\n", "* Flags support bitwise `&`, `|` operations to *combine* enumerated values\n", "* Bitflags should be kept to powers of two" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "from enum import Flag, IntFlag" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "class A(Flag):\n", " X = 1 # 1 << 0\n", " Y = 2 # 1 << 1\n", " Z = 4 # 1 << 2" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "a = A.X | A.Z\n", "a" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "isinstance(a, A)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "a & A.X" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "a & A.Y" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "a & A.Z" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "auto-enumeration works as expected" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "A = IntFlag(\"A\", \"W X Y Z\")\n", "list(A)" ] }, { "cell_type": "code", "execution_count": 229, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 229, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A(13)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "for a in A:\n", " print(f'{a.name} = 0b{a:05b}')" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### When to use?\n", "\n", "* When you have finite set of things and want name & value lookup + iteration for free\n", " * \"Finite\" means \"Nameable\"\n", "\n", "* Examples:\n", " * Finite states:\n", " * On/Off\n", " * Low, Medium, High\n", " * String or Byte \"validation\" (IntFlag)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Example: Suit Of Cards" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "class Suit(Enum):\n", " Hearts = 1\n", " Clubs = 2\n", " Spades = 3\n", " Diamonds = 4\n", " \n", " def is_red(self):\n", " return self in (Suit.Hearts, Suit.Diamonds)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "list(Suit)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "Suit.Diamonds.is_red()" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "from itertools import product\n", "deck = list(product(Suit, range(1, 14)))" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "deck[:5]" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "from random import shuffle\n", "shuffle(deck)\n", "deck[:6]" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "class Card:\n", " def __init__(self, suit, face):\n", " if isinstance(suit, str):\n", " suit = Suit[suit]\n", " self.suit = suit\n", " self.face = face\n", "\n", " def __repr__(self):\n", " if 1 < self.face < 11:\n", " f = self.face\n", " else:\n", " f = self.FaceToLetter(self.face).name\n", " return \"\" % (f, self.suit.name)\n", "\n", " class FaceToLetter(Enum):\n", " A = 1\n", " J = 11\n", " Q = 12\n", " K = 13" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "from itertools import starmap\n", "deck = list(starmap(Card, product(Suit, range(1, 14))))" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "deck[::5]" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Example: Unix File Permissions" ] }, { "cell_type": "code", "execution_count": 219, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "class Perm(IntFlag):\n", " READ = 1\n", " WRITE = 2\n", " EXEC = 4\n", " \n", " def __str__(self):\n", " return (('r' if self & self.READ else '-') +\n", " ('w' if self & self.WRITE else '-') +\n", " ('x' if self & self.EXEC else '-'))" ] }, { "cell_type": "code", "execution_count": 220, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "'r-x'" ] }, "execution_count": 220, "metadata": {}, "output_type": "execute_result" } ], "source": [ "'%s' % (Perm.READ | Perm.EXEC)" ] }, { "cell_type": "code", "execution_count": 226, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 226, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Perm(6)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "* Full UNIX file permission has a \"Perm\" for `user`, `group`, `all`.\n", "* NOT a good case for Enum\n", " - Many (3 × 2^3) states to choose from\n", " - You do not want to name them all!" ] }, { "cell_type": "code", "execution_count": 232, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "class UnixPermission:\n", " def __init__(self, user: Perm, group: Perm, all: Perm):\n", " self.user = user\n", " self.group = group\n", " self.all = all\n", " \n", " @classmethod\n", " def from_int(cls, num):\n", " return cls(Perm((num >> 6) & 7),\n", " Perm((num >> 3) & 7),\n", " Perm((num >> 0) & 7))\n", "\n", " def __str__(self):\n", " return '%s%s%s' % (self.user, self.group, self.all)" ] }, { "cell_type": "code", "execution_count": 235, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "'rwxr-xr-x'" ] }, "execution_count": 235, "metadata": {}, "output_type": "execute_result" } ], "source": [ "str(UnixPermission.from_int(0o755))" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Example : HTTP Methods & Status Codes\n", "\n", "\n", "* [HTTP Methods](https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Summary_table)\n", "* [HTTP Status Codes](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes)\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Famous Status Codes:\n", " * 200 - OK\n", " * 404 - Not Found\n", " * 500 - Internal Server Error" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "HttpMethod = Enum(\"HttpMethod\", \"GET POST PUT DELETE\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "try:\n", " method = HttpMethod[method_str] \n", "except KeyError:\n", " raise UnknownHttpMethodException(method_str)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "class HttpStatus(IntEnum):\n", " OK = 200\n", " NOT_FOUND = 404\n", " INTERNAL_SERVER_ERROR = 500" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "class HttpError(Exception):\n", " pass\n", "\n", "class HttpErrorNotFound(HttpError):\n", " status = HttpStatus.NOT_FOUND\n", "\n", "class HttpErrorISE(HttpError):\n", " status = HttpStatus.INTERNAL_SERVER_ERROR\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "from http import HTTPStatus\n", "HTTPStatus" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "HTTPStatus['OK']" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "HTTPStatus[\"OK\"].description" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "HTTPStatus(404)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "list(HTTPStatus)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Summary\n", "\n", "* Enums are a useful tool in your programming toolbox\n", " * Should be aware of them and when to use them\n", "* Nothing truely new (you could implement with dictionaries), but get automatic features\n", "* For more information, check the documentation https://docs.python.org/3/library/enum.html\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# END" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "celltoolbar": "Slideshow", "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.6.4" } }, "nbformat": 4, "nbformat_minor": 2 }