• Stars
    star
    247
  • Rank 163,123 (Top 4 %)
  • Language
    Python
  • License
    MIT License
  • Created about 7 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Adds switch blocks to Python #pypackage

switchlang

Adds switch blocks to the Python language.

This module adds explicit switch functionality to Python without changing the language. It builds upon a standard way to define execution blocks: the with statement.

Example

from switchlang import switch

def main():
    num = 7
    val = input("Enter a character, a, b, c or any other: ")

    with switch(val) as s:
        s.case('a', process_a)
        s.case('b', lambda: process_with_data(val, num, 'other values still'))
        s.default(process_any)
    
def process_a():
    print("Found A!")
    
def process_any():
    print("Found Default!")
    
def process_with_data(*value):
    print("Found with data: {}".format(value))

main()

Installation

Simply install via pip:

pip install switchlang

Features

  • More explicit than using dictionaries with functions as values.
  • Verifies the signatures of the methods
  • Supports default case
  • Checks for duplicate keys / cases
  • Keys can be anything hashable (numbers, strings, objects, etc.)
  • Could be extended for "fall-through" cases (doesn't yet)
  • Use range and list for multiple cases mapped to a single action

Multiple cases, one action

You can map ranges and lists of cases to a single action as follows:

# with lists:
value = 4  # matches even number case

with switch(value) as s:
    s.case([1, 3, 5, 7], lambda: ...)
    s.case([0, 2, 4, 6, 8], lambda: ...)
    s.default(lambda: ...)
# with ranges:
value = 4  # matches first case

with switch(value) as s:
    s.case(range(1, 6), lambda: ...)
    s.case(range(6, 10), lambda: ...)
    s.default(lambda: ...)

Closed vs. Open ranges

Looking at the above code it's a bit weird that 6 appears at the end of one case, beginning of the next. But range() is half open/closed.

To handle the inclusive case, I've added closed_range(start, stop). For example, closed_range(1,5) -> [1,2,3,4,5]

Why not just raw dict?

The biggest push back on this idea is that we already have this problem solved. You write the following code.

switch = {
    1: method_on_one,
    2: method_on_two,
    3: method_three
}

result = switch.get(value, default_method_to_run)()

This works but is very low on the functionality level. We have a better solution here I believe. Let's take this example and see how it looks in python-switch vs raw dicts:

# with python-switch:

while True:
    action = get_action(action)

    with switch(action) as s:
        s.case(['c', 'a'], create_account)
        s.case('l', log_into_account)
        s.case('r', register_cage)
        s.case('u', update_availability)
        s.case(['v', 'b'], view_bookings)
        s.case('x', exit_app)
        s.case('', lambda: None)
        s.case(range(1,6), lambda: set_level(action))
        s.default(unknown_command)
    
    print('Result is {}'.format(s.result))

Now compare that to the espoused pythonic way:

# with raw dicts

while True:
    action = get_action(action)

    switch = {
        'c': create_account,
        'a': create_account,
        'l': log_into_account,
        'r': register_cage,
        'u': update_availability,
        'v': view_bookings,
        'b': view_bookings,
        'x': exit_app,
        1: lambda: set_level(action),
        2: lambda: set_level(action),
        3: lambda: set_level(action),
        4: lambda: set_level(action),
        5: lambda: set_level(action),
        '': lambda: None,
    }
    result = switch.get(action, unknown_command)()
    print('Result is {}'.format(result))

Personally, I much prefer to read and write the one above. That's why I wrote this module. It seems to convey the intent of switch way more than the dict. But either are options.

Why not just if / elif / else?

The another push back on this idea is that we already have this problem solved. Switch statements are really if / elif / else blocks. So you write the following code.

# with if / elif / else

while True:
    action = get_action(action)

    if action == 'c' or action == 'a':
        result = create_account()
    elif action == 'l':
        result = log_into_account()
    elif action == 'r':
        result = register_cage()
    elif action == 'a':
        result = update_availability()
    elif action == 'v' or action == 'b':
        result = view_bookings()
    elif action == 'x':
        result = exit_app()
    elif action in {1, 2, 3, 4, 5}:
        result = set_level(action)
    else:
        unknown_command()
        
    print('Result is {}'.format(result))

I actually believe this is a little better than the raw dict option. But there are still things that are harder.

  • How would you deal with fall-through cleanly?
  • Did you notice the bug? We forgot to set result in default case (else) and will result in a runtime error (but only if that case hits).
  • There is another bug. Update update_availability will never run because it's command (a) is bound to two cases. This is guarded against in switch and you would receive a duplicate case error the first time it runs at all.
  • While it's pretty clear, it's much more verbose and less declarative than the switch version.

Again, compare the if / elif / else to what you have with switch. This code is identical except doesn't have the default case bug.

while True:
    action = get_action(action)

    with switch(action) as s:
        s.case(['c', 'a'], create_account)
        s.case('l', log_into_account)
        s.case('r', register_cage)
        s.case('u', update_availability)
        s.case(['v', 'b'], view_bookings)
        s.case('x', exit_app)
        s.case('', lambda: None)
        s.case(range(1,6), lambda: set_level(action))
        s.default(unknown_command)
    
    print('Result is {}'.format(s.result))

More Repositories

1

python-jumpstart-course-demos

Contains all the "handout" materials for my Python Jumpstart by Building 10 Apps course. This includes try it yourself and finished versions of the 10 apps.
Python
746
star
2

write-pythonic-code-demos

Write Pythonic Code Like a Seasoned Developer video course demo materials.
Python
727
star
3

mongodb-quickstart-course

Course demos and handout material for Talk Python's MongoDB Quickstart course
Python
306
star
4

python-for-entrepreneurs-course-demos

Contains all the "handout" materials for Talk Python's Python for Entrepreneurs course. This includes notes and the final version of the website code.
Python
285
star
5

jinja_partials

Simple reuse of partial HTML page templates in the Jinja template language for Python web frameworks. #pypackage
Python
191
star
6

mongodb-for-python-developers

MongoDB for Python developers course handouts from Talk Python Training
Python
176
star
7

talk-python-transcripts

Transcripts for the Talk Python To Me episodes
145
star
8

fastapi-chameleon

Adds integration of the Chameleon template language to FastAPI. #pypackage
Python
139
star
9

async-await-jetbrains-webcast

Python
127
star
10

pyscript-pwa-example

JavaScript
106
star
11

ten-tips-for-pythonic-code-jetbrains-webcast

JetBrains / PyCharm webinar: 10 Tips for Pythonic Code by Michael Kennedy
Python
101
star
12

consuming_services_python_demos

Consuming HTTP and SOAP services in Python course handouts
Python
96
star
13

cookiecutter-course

Handout materials for our course on CookieCutter at Talk Python Training
Python
72
star
14

cookiecutter-pyramid-talk-python-starter

An opinionated Cookiecutter template for creating Pyramid web applications starting way further down the development chain. This cookiecutter template will create a new Pyramid web application with email, sqlalchemy, rollbar, and way more integrated.
Python
67
star
15

markdown-subtemplate

A template engine to render Markdown with external template imports and basic variable replacements. #pypackage
Python
63
star
16

restful-services-in-pyramid

RESTful / HTTP services in Pyramid and Python course handout materials
Python
58
star
17

umami-python

Umami Analytics Client for Python
Python
58
star
18

urlify

A simple macOS app to create valid file and url names from clipboard text. #pypackage
Python
52
star
19

write-pythonic-code-for-better-data-science-webcast

Python
41
star
20

python_bytes_show_notes

Show notes from the Python Bytes podcast
Python
40
star
21

cache-tier

Imagine you have a set of static files you want to serve to the world. Cache-tier allows you to quickly spin up a Linux web server in a location with cheap, plentiful bandwidth and serve those files to your users.
Python
31
star
22

ten-tips-python-web-devs

Repo for topics covered during the presentation
JavaScript
30
star
23

python-shorts

Learn Python tips, tools, and techniques in around 5 minutes each.
Python
30
star
24

pycon-sk-pythonic-talk

Python
29
star
25

docker-build-fastapi-app-april-2021

Python
27
star
26

jetbrains-webcast-build-with-mongodb

Code and handouts for my JetBrains webcast recorded January 30, 2018
Python
26
star
27

improve-mvc-perf-with-async-views

C#
25
star
28

pythons-gc-and-orms

A simple project to explore the number of GCs when doing basic ORM work.
Python
25
star
29

mongodb-query-helper-for-dotnet

C#
24
star
30

streamdeck-developer-profiles

A set of profiles for Elgato's Stream Deck aimed at programming tools
24
star
31

mastering-pycharm-course

Course demos and handouts for Talk Python's Mastering PyCharm course
24
star
32

listmonk

Listmonk Email App API Client for Python
Python
24
star
33

build-pypi-mongodb-webcast-series

Code demos and hand-outs for my webcast series with MongoDB (May - June 2018)
Python
22
star
34

optimistic_concurrency_mongodb_dotnet

This c# library adds optimistic concurrency control to MongoDB and acts as a MongoDB ORM foundation.
C#
20
star
35

chameleon_partials

Simple reuse of partial HTML page templates in the Chameleon template language for Python web frameworks. #pypackage
Python
14
star
36

server-hot-reload

Include in your web projects for dev-time auto reloading of web browser when any change is detected in content.
JavaScript
13
star
37

wakeup

A little Python app to make sure your server is warmed up
Python
10
star
38

pycon-sk-mongodb-workshop

Python
7
star
39

EssentialPythonDemos

Essential Python Demos
6
star
40

pyramid-web-builder-python-gui

Python
6
star
41

python-mongodb-intro-jetbrains-webcast

Demo code for my webcast on MongoDB hosted by the PyCharm team
6
star
42

managed_system_hooks

The class library can be used to create any type of system hook. There are two that come pre-built: MouseHook and KeyboardHook. We have also included specialized versions of these classes called MouseHookExt and KeyboardHookExt respectively. Following the model set by those classes, you can easily build system hooks for any of the 15 hook event types in the Win32 API. Also, the entire class library comes with a compiled HTML help file which documents the classes. Be sure to look at this help file if you decide to use this library in your applications.
C#
6
star
43

web-apps-hotkeys

C#
5
star
44

write-pythonic-code-va-meetup

Python
4
star
45

pyramid-cookiecutter-starter-chameleon

Python
4
star
46

windows-python-compatibility-pack

A few commands to make the command prompt identical with macOS and Linux terminals
Batchfile
4
star
47

tinydb-sample-blog

A (very) simple demo app using TinyDb
Python
4
star
48

python-virtual-conf-web-tips

Code and demos from my Python Virtual Conference 2020 talk
Python
4
star
49

fastapi-twitch-examples

Python
4
star
50

talk-python-search-service

An open-source adaption of the high perf search engine powering Talk Python's web properties
Python
3
star
51

enhanced_aspnet_mvc_views

Enhanced View Locations for MVC allows you to further organize your ASP.NET MVC views without your action methods or Html.RenderPartial / Html.RenderAction elements knowing or caring about how they are organized or re-organized.
C#
3
star
52

funny-web

Sample repo for funny web app, featured in Up and Running with Git course.
Python
2
star
53

jetbrains-git-webcast-2022

Python
2
star
54

asq

Automatically exported from code.google.com/p/asq
Python
2
star
55

sketchy-rock-paper-scissors

Sample repo for Rock Paper Scissors app, featured in Up and Running with Git course.
Python
2
star
56

text-encoding-aspnet-mvc-by-example

CSS
2
star
57

DevWeek2015

C#
1
star
58

suds_python

Python
1
star
59

python-for-dotnet-devs-ndc-oslo-2016

Live demo materials from my session at NDC Olso 2016.
Python
1
star
60

python-data-driven-nov9

Python
1
star
61

asq.docs

Automatically exported from code.google.com/p/asq.docs
HTML
1
star
62

portland-state-data-sci

Jupyter Notebook
1
star
63

SDDConf2015

C#
1
star
64

python_workshop_demos_april_2018

1
star
65

smarter_web_deploy

A library to extend Microsoft's Web Deploy feature in Visual Studio to create reliable and fast deploys on production sites running on IIS and Windows Servers.
C#
1
star