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}")

No comment yet, add your voice below!