Limited typecasting with regex I'm learning Python, and found a fun little video on YouTube called "Learn Python through public data hacking".  In essence it uses the CTA unofficial API to do some parsing of XML data.  In taking things further than inline code, I'm chunking behaviors into modules and classes to further understand how Python works.

The XML from the API looks something like this:



&lt;buses rt="22"&gt;
&lt;time&gt;1:40 AM&lt;/time&gt;
    &lt;bus&gt;
        &lt;id&gt;4194&lt;/id&gt;
        &lt;rt&gt;22&lt;/rt&gt;
        &lt;d&gt;East Bound&lt;/d&gt;
        &lt;dd&gt;Northbound&lt;/dd&gt;
        &lt;dn&gt;E&lt;/dn&gt;
        &lt;lat&gt;41.88327006970422&lt;/lat&gt;
        &lt;lon&gt;-87.62828115689553&lt;/lon&gt;
        &lt;pid&gt;5421&lt;/pid&gt;
        &lt;pd&gt;Northbound&lt;/pd&gt;
        &lt;run&gt;P238&lt;/run&gt;
        &lt;fs&gt;Howard&lt;/fs&gt;
        &lt;op&gt;49875&lt;/op&gt;
        &lt;dip&gt;5314&lt;/dip&gt;
        &lt;bid&gt;7323287&lt;/bid&gt;
        &lt;wid1&gt;0P&lt;/wid1&gt;
        &lt;wid2&gt;238&lt;/wid2&gt;                
    &lt;/bus&gt;
    &lt;!-- bus... n --&gt;
&lt;/buses&gt;


I'm using the python-requests module for the HTTP side, and once the XML is downloaded, I parse each &lt;bus&gt; node into a Bus class, assign each of the child nodes into a dictionary, and make that visible with a get(prop) statement, so I can just call bus.get('lat') to retrieve the latitude, etc.  However, in order to do the correct calculations on it (i.e. arithmetic) each node's value needs to be returned as the correct type.  By default, they're all read as strings.

Considering that Python doesn't have a "switch" statement like most other languages, someone at SO said to use a dictionary. Is this the/a correct way of doing something like this? Or is there some nifty builtin that I don't know of?



def dyncast(value):
    _type = type(value)
    types = {
        "FloatType": (r'^[\d]{2}\.[\d]+$', lambda f : float(f)),
        "IntType" : (r'^[\d]+$', lambda i : int(i)),
        "StrType" : (r'^[a-zA-z]+$', lambda s : str(s))
    }
    for typeval in types:
        pattern = types[typeval][0]
        fn = types[typeval][1]
        match = re.match(pattern, value)

        # if it matches a regex and has a group(), return the
        # lambda calculation (typecast)
        if match and match.group():
            return fn(value)

    # return straight up if no matches
    return value

# Called via:
for elm in node:
    self._data[elm.tag] = dyncast(elm.text)
# where node is the bus node, and elm are the child nodes


It seems to work well, as I get returns such as:

# print bus.get('fs'), type(bus.get('fs'))
Harrison &lt;type 'str'&gt;

# print bus.get('lat'), type(bus.get('lat'))
41.9027030677 &lt;type 'float'&gt;
Makes sense to me. A couple small things:

lambda f: float(f) should be equivalent to just float if I'm not mistaken. You can simplify the loop a bit too since you're not actually using the dictionary keys.

types = [
  (r'(regex)', float),
  (r'(regex)', int),
  (r'(regex)', str),
]
for pattern, fn in types:
  match = ...