Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python bidirectional mapping

Tags:

python

mapping

I'm not sure what to call what I'm looking for; so if I failed to find this question else where, I apologize. In short, I am writing python code that will interface directly with the Linux kernel. Its easy to get the required values from include header files and write them in to my source:

IFA_UNSPEC     =  0
IFA_ADDRESS    =  1
IFA_LOCAL      =  2
IFA_LABEL      =  3
IFA_BROADCAST  =  4
IFA_ANYCAST    =  5
IFA_CACHEINFO  =  6
IFA_MULTICAST  =  7

Its easy to use these values when constructing structs to send to the kernel. However, they are of almost no help to resolve the values in the responses from the kernel.

If I put the values in to dict I would have to scan all the values in the dict to look up keys for each item in each struct from the kernel I presume. There must be a simpler, more efficient way.

How would you do it? (feel free to retitle the question if its way off)

like image 994
tMC Avatar asked Feb 14 '12 19:02

tMC


3 Answers

Your solution leaves a lot of work do the repeated person creating the file. That is a source for error (you actually have to write each name three times). If you have a file where you need to update those from time to time (like, when new kernel releases come out), you are destined to include an error sooner or later. Actually, that was just a long way of saying, your solution violates DRY.

I would change your solution to something like this:

IFA_UNSPEC     =  0
IFA_ADDRESS    =  1
IFA_LOCAL      =  2
IFA_LABEL      =  3
IFA_BROADCAST  =  4
IFA_ANYCAST    =  5
IFA_CACHEINFO  =  6
IFA_MULTICAST  =  7
__IFA_MAX      =  8

values = {globals()[x]:x for x in dir() if x.startswith('IFA_') or x.startswith('__IFA_')}

This was the values dict is generated automatically. You might want to (or have to) change the condition in the if statement there, according to whatever else is in that file. Maybe something like the following. That version would take away the need to list prefixes in the if statement, but it would fail if you had other stuff in the file.

values = {globals()[x]:x for x in dir() if not x.endswith('__')}

You could of course do something more sophisticated there, e.g. check for accidentally repeated values.

like image 179
kratenko Avatar answered Nov 16 '22 04:11

kratenko


If you want to use two dicts, you can try this to create the inverted dict:

b = {v: k for k, v in a.iteritems()}
like image 21
Dan Gerhardsson Avatar answered Nov 16 '22 02:11

Dan Gerhardsson


What I ended up doing is leaving the constant values in the module and creating a dict. The module is ip_addr.py (the values are from linux/if_addr.h) so when constructing structs to send to the kernel I can use if_addr.IFA_LABEL and resolves responses with if_addr.values[2]. I'm hoping this is the most straight forward so when I have to look at this again in a year+ its easy to understand :p

IFA_UNSPEC     =  0
IFA_ADDRESS    =  1
IFA_LOCAL      =  2
IFA_LABEL      =  3
IFA_BROADCAST  =  4
IFA_ANYCAST    =  5
IFA_CACHEINFO  =  6
IFA_MULTICAST  =  7
__IFA_MAX      =  8

values = {
           IFA_UNSPEC    : 'IFA_UNSPEC',
           IFA_ADDRESS   : 'IFA_ADDRESS',
           IFA_LOCAL     : 'IFA_LOCAL',
           IFA_LABEL     : 'IFA_LABEL',
           IFA_BROADCAST : 'IFA_BROADCAST',
           IFA_ANYCAST   : 'IFA_ANYCAST',
           IFA_CACHEINFO : 'IFA_CACHEINFO',
           IFA_MULTICAST : 'IFA_MULTICAST',
           __IFA_MAX     : '__IFA_MAX'
         }
like image 1
tMC Avatar answered Nov 16 '22 04:11

tMC