Summary

A discussion of a simple method in Python to implement the equivalent of a c programming style switch.

Story

Recently, I was working on an example where I would have used something like this if I was programming in C (emphasis on like)

#include <stdio.h>

typedef enum {
    op0,
    op1,
    op2,
    op3
} opcodes_t;

int main(int argc,char **argv)
{
    opcodes_t excode = op1;

    switch(excode)
    {
        case 0:
            printf("opcode 0");
            break;
        case 1:
            printf("opcode 1");
            break;
        case 2:
            printf("opcode 2");
            break;
        case 3:
            printf("opcode 3");
            break;

    }

}

And, as you know, I am not a real Python programmer.  I tried switch… obviously to no avail.  So now what?  Well in the example above I have

  • A list of keys, the enumerated opcode_t
  • That have a values e.g. “opcode 0” etc.

Sounds like a dictionary.  Here is the equivalent code in Python:

opcode_t = {
    0:"opcode 0",
    1:"opcode 1",
    2:"opcode 2",
    3:"opcode 3",
}

ex1 = 1

print(opcode_t[ex1])

But what happens if a key is missing?  The bracket[] method of a dictionary is equivalent to the dictionary method “get”.   The “get” method has a default case if they key is missing from the dictionary.  Here is the example code:

opcode_t = {
    0:"opcode 0",
    1:"opcode 1",
    2:"opcode 2",
    3:"opcode 3",
}

ex1 = 1

# will return "not found" if the key is not in the dictionary
print(opcode_t.get(ex1,"Not Found"))

What if you want to do something?  Values in dictionaries can be “function pointers” (is what I would call them in C).  They are probably properly called references in Python.  Regardless, here is some absurd code that demonstrates the example.

def opcode0():
    return "opcode 0"

def opcode1():
    return "opcode 1"

def opcode2():
    return "opcode 2"

def opcode3():
    return "opcode 3"

opcode1_t = {
    0:opcode0,
    1:opcode1,
    2:opcode2,
    3:opcode3,
}

ex1 = 1

print(opcode1_t[ex1]())

My mDNS Example

The example that lead me to this problem was decoding mDNS headers which have 8 fields of different lengths and possible values.  Here is what I actually did:

    qrText = {0:"Query",1:"Response"}
    opcodeText = {0:"Query",1:"IQuery",2:"Status",3:"reserved",4:"Notify",5:"Update"}
    aaText = {0:"Non Authoratative",1:"Authoratative"}
    tcText = {0:"No Truncation",1:"Truncation"}
    rdText = {0:"No Recursion",1:"Recursion"}
    raText = {0:"No Recursion Available",1:"Recursion Available"}
    zText = {0:"Reserved"}
    rcodeText = {
        0:"No Error",
        1:"Format Error",
        2:"Server Failure",
        3:"Name Error",
        4:"Not implemented",
        5:"Refused - probably a policy reason",
        6:"A name exists when it should not",
        7:"a resource record set exists that should not",
        8:"NX RR Set - A resource record set that should exist does not",
        9:"Not Authorized",
        10:"Not Zone",
    }

    def printHeader(self):
        print(f"id = {self.id}")
        print(f"qr = {self.qr} {self.qrText.get(self.qr,'Unknown')}")
        print(f"opcode = {self.opcode} {self.opcodeText.get(self.opcode,'Unknown')}")
        print(f"aa = {self.aa} {self.aaText.get(self.aa,'Unknown')}")
        print(f"tc = {self.tc} {self.tcText.get(self.tc,'Unknown')}")
        print(f"rd = {self.rd} {self.rdText.get(self.rd,'Unknown')}")
        print(f"ra = {self.ra} {self.raText.get(self.ra,'Unknown')}")
        print(f"z = {self.z} {self.zText.get(self.z,'Unknown')}")
        print(f"response code = {self.rcode} {self.rcodeText.get(self.rcode,'Unknown')}")
        print(f"rc question count = {self.qdcount}")
        print(f"answer count = {self.ancount}")
        print(f"name server count = {self.nscount}")
        print(f"additional record count = {self.arcount}")

Recommended Posts

No comment yet, add your voice below!


Add a Comment

Your email address will not be published. Required fields are marked *