pythondictionarylambdacastingpython-netifaces

Why what's wrong with this dict conversion of a lambda expression result object?


Was feeling smug thinking that I had the best lambda expression in the universe cooked up to return all the relevant network information ever needed using python and netifaces

>>> list(map(lambda interface: (interface, dict(filter(lambda ifaddress: ifaddress in (netifaces.AF_INET, netifaces.AF_LINK), netifaces.ifaddresses(interface) )))  , netifaces.interfaces()))

but I got this

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in <lambda>
TypeError: cannot convert dictionary update sequence element #0 to a sequence

scaling it back a bit

>>>dict(filter(lambda ifaddress: ifaddress in (netifaces.AF_INET, netifaces.AF_LINK), netifaces.ifaddresses("eth0")))

is where the problem is:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: cannot convert dictionary update sequence element #0 to a  sequence

but so I can convert the filter object to a list

 >>> list(filter(lambda ifaddress: ifaddress in (netifaces.AF_INET, netifaces.AF_LINK), netifaces.ifaddresses("eth0")))
 [17, 2]

but, that's not what I want. I want what it actually is:

>>> netifaces.ifaddresses("tun2")
{2: [{'addr': '64.73.0.0', 'netmask': '255.255.255.255', 'peer': '192.168.15.4'}]}
>>> type (netifaces.ifaddresses("eth0"))
<class 'dict'>

so what's mucking up my cast back back to dictionary?


Solution

  • When given a dictionary as input, filter will only iterate and return the keys from that dictionary.

    >>> filter(lambda x: x > 1, {1:2, 3:4, 5:6})
    [3, 5]
    

    Thus you are feeding just the sequence of filtered keys into the new dict, not the key-value-pairs. You could fix it like this: Note the call to items() and how the inner lambda is getting a tuple as input.

    list(map(lambda interface: (interface, dict(filter(lambda tuple: tuple[0] in (netifaces.AF_INET, netifaces.AF_LINK), 
                                                       netifaces.ifaddresses(interface).items()))), 
             netifaces.interfaces()))
    

    Now that's not very pretty... I suggest changing your code to a nested list- and dictionary-comprehension:

    [(interface, {ifaddress: value 
              for (ifaddress, value) in netifaces.ifaddresses(interface).items()
              if ifaddress in (netifaces.AF_INET, netifaces.AF_LINK)})
     for interface in netifaces.interfaces()]