Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass in a dictionary with additional elements in python?

I have a dictionary:

big_dict = {1:"1",
            2:"2",
            ...
            1000:"1000"}

(Note: My dictionary isn't actually numbers to strings)

I am passing this dictionary into a function that calls for it. I use the dictionary often for different functions. However, on occasion I want to send in big_dict with an extra key:item pair such that the dictionary I want to send in would be equivalent to:

big_dict[1001]="1001"

But I don't want to actually add the value to the dictionary. I could make a copy of the dictionary and add it there, but I'd like to avoid the memory + CPU cycles this would consume.

The code I currently have is:

big_dict[1001]="1001"
function_that_uses_dict(big_dict)
del big_dict[1001]

While this works, it seems rather kludgy.

If this were a string I'd do:

function_that_uses_string(myString + 'what I want to add on')

Is there any equivalent way of doing this with a dictionary?

like image 311
Mitch Avatar asked Dec 16 '14 15:12

Mitch


3 Answers

As pointed out by Veedrac in his answer, this problem has already been solved in Python 3.3+ in the form of the ChainMap class:

function_that_uses_dict(ChainMap({1001 : "1001"}, big_dict))

If you don't have Python 3.3 you should use a backport, and if for some reason you don't want to, then below you can see how to implement it by yourself :)


You can create a wrapper, similarly to this:

class DictAdditionalValueWrapper:
    def __init__(self, baseDict, specialKey, specialValue):
        self.baseDict = baseDict
        self.specialKey = specialKey
        self.specialValue = specialValue

    def __getitem__(self, key):
        if key == self.specialKey:
            return self.specialValue

        return self.baseDict[key]

    # ...

You need to supply all other dict method of course, or use the UserDict as a base class, which should simplify this.

and then use it like this:

function_that_uses_dict(DictAdditionalValueWrapper(big_dict, 1001, "1001"))

This can be easily extended to a whole additional dictionary of "special" keys and values, not just single additional element.


You can also extend this approach to reach something similar as in your string example:

class AdditionalKeyValuePair:
    def __init__(self, specialKey, specialValue):
        self.specialKey = specialKey
        self.specialValue = specialValue

    def __add__(self, d):
        if not isinstance(d, dict):
            raise Exception("Not a dict in AdditionalKeyValuePair")

        return DictAdditionalValueWrapper(d, self.specialKey, self.specialValue)

and use it like this:

function_that_uses_dict(AdditionalKeyValuePair(1001, "1001") + big_dict)
like image 80
BartoszKP Avatar answered Oct 17 '22 08:10

BartoszKP


If you're on 3.3+, just use ChainMap. Otherwise use a backport.

new_dict = ChainMap({1001: "1001"}, old_dict)
like image 28
Veedrac Avatar answered Oct 17 '22 08:10

Veedrac


You can add the extra key-value pair leaving original dictionary as such like this:

>>> def function_that_uses_bdict(big_dict):
...    print big_dict[1001]
... 
>>> dct = {1:'1', 2:'2'}
>>> function_that_uses_bdict(dict(dct.items()+[(1001,'1001')]))
1001
>>> dct  
{1: '1', 2: '2'}  # original unchanged
like image 22
Irshad Bhat Avatar answered Oct 17 '22 08:10

Irshad Bhat