RT Security
RT Security

Reputation: 47

How do you update a dictionary value that is a set?

I'm trying to create a function that will track IP assignments for unique mac addresses. I plan on doing this by creating a dictionary that uses the MAC + Location as the key, and the value will be a set() as a way of tracking unique IP assignments per mac address.

I can't seem to append new IP addresses to the set() dictionary value though using the below:

Function:

def trackmac(ip, location, mac):
    if ip_tracker.get(f'{mac} {location}') == None:
        ip_tracker[f'{mac} {location}'] = set((ip,))
        print(f'[!] First ip entry: {ip}')
    elif ip_tracker.get(f'{mac} {location}') != None:
        print('[!] not first ip entry')
        update_iplist = ip_tracker.get(f'{mac} {location}')
        ip_tracker[f'{mac} {location}'] = update_iplist.add(ip)

Output:

Once I test the function the first time the key (MAC + Location) has been seen it creates a set and adds the IP address.

>>> trackmac('192.168.1.10', 'home', 'AA:AA:AA:AA:AA:AA')
[!] First ip entry: 192.168.1.10
>>> print(ip_tracker)
{'AA:AA:AA:AA:AA:AA home': {'192.168.1.10'}}
>>> trackmac('192.168.1.11', 'home', 'BB:BB:BB:BB:BB:BB')
[!] First ip entry: 192.168.1.11
>>> print(ip_tracker)
{'AA:AA:AA:AA:AA:AA home': {'192.168.1.10'}, 'BB:BB:BB:BB:BB:BB home': {'192.168.1.11'}}

Error:

The second time it returns the value of that key as None rather than adding the new IP address to the set() value.

>>> trackmac('192.168.1.12', 'home', 'BB:BB:BB:BB:BB:BB')
[!] not first ip entry
>>> print(ip_tracker)
{'AA:AA:AA:AA:AA:AA home': {'192.168.1.10'}, 'BB:BB:BB:BB:BB:BB home': None}

Upvotes: 1

Views: 108

Answers (3)

kederrac
kederrac

Reputation: 17322

How do you update a dictionary value that is a set in Python?

my_dict[key_with_set].add(my_value)

your issue is the fact that set.add returns None, this line ip_tracker[f'{mac} {location}'] = update_iplist.add(ip) will make ip_tracker[f'{mac} {location}'] to be equal with None since update_iplist.add(ip) returns None

you can use:

def trackmac(ip, location, mac):
    ip_tracker.setdefault(f'{mac} {location}', set()).add(ip)

Upvotes: 1

Daniele Grattarola
Daniele Grattarola

Reputation: 1537

The culprits are these lines:

update_iplist = ip_tracker.get(f'{mac} {location}')
ip_tracker[f'{mac} {location}'] = update_iplist.add(ip)

When you call update_iplist.add(ip) on the set of IP addresses, the return value of the function add() is None, because it only has a side effect of adding your new IP address to the set. The assignment then overwrites the value stored in the dictionary with None.
The wrong assumption here is that the add() function actually returns the set, when in truth it doesn't.

You can easily fix it by replacing those two lines as follows:

ip_tracker[f'{mac} {location}'].add(ip)

This is safe to do because you already checked that the key exists in the dictionary.

Hope this helps

Upvotes: 1

blhsing
blhsing

Reputation: 106465

The set.add method modifies the set in-place and returns None, so your:

ip_tracker[f'{mac} {location}'] = update_iplist.add(ip)

would override the value of that key with None.

You can instead use the dict.setdefault method to initialize each new key with an empty set, and then call the set.add method to add an IP to it:

def trackmac(ip, location, mac):
    ip_tracker.setdefault(f'{mac} {location}', set()).add(ip)

Upvotes: 1

Related Questions