1

I'd like to construct a dictionary, but only add the item if the value of the item is truthy

I do the following

my_dict = {
          "key1": convert_value("foo"), 
          "key2": convert_value(None), 
          "key3": convert_value(""),
          "key4": "bar",
          "key5": ""
          }

Problem is, I do not want the key to be in the dictionary at all, if its converted_value() is falsy, for example key2 and key3, which will both be empty strings after converting it with the convert_value() function.

the resulting dictionary, as is, would look like this

{
 "key1": "foo", 
 "key2": "", 
 "key3": "",
 "key4": "bar",
 "key5": ""
}

however I'd like the resulting dict to be just this

{
 "key1": "foo",
 "key4": "bar",
 "key5": "",
}

without the keys2 and 3 which returned empty values after conversion. Is there any way to do this in-line - during the construction directly?

I cannot use dict comprehension because not all the values go through the convert_value function before getting added (those keys can have empty values), and removing them in hindsight seems wasteful

EDIT: What I'm really looking for is similar to providing a default value as follows

      "key2": convert_value("foo") or pass,

ie: skip this key entirely. That would be perfect.

c8999c 3f964f64
  • 1,430
  • 1
  • 12
  • 25
  • 1
    Could you use dic comprenhension, and use an intermediate function that calls to convert_value() when it is necessary or returns the same value when convert_value is not needed? – Sergio Ferrer Sánchez May 19 '20 at 13:55
  • Could you provide an example version of the `convert_value` function? Some context might help too - like why are you using empty strings instead of say, a sentinel `object`? – wjandrea May 19 '20 at 13:58
  • @SergioFerrerSánchez No, truthfully, its a long list of very different items. Some of them use the convert_value function, other use .pop from another dict, or get converted via strftime. its all very special-casey, unfortunately. I am specifically looking for something that skips keys that have no value - on a case-by-case basis. – c8999c 3f964f64 May 19 '20 at 14:00
  • @wjandrea Sure, some context might help. I am mainly using this to convert datetimes and then sending them to an api. Sadly, the API recipient won't accept an empty string - if the key "date" is present. It will however accept the request, if the "date" field is missing entirely. Sending it with a "date" field but "empty string" as its value will be rejected. I load my data from a database query - which will always return the field, even tho it is empty. I have to skip those keys if the value is empty in this step. date is just one example, lots of others work similarly. – c8999c 3f964f64 May 19 '20 at 14:10
  • @c89 Oh so the key is important? That's good to know! I was thinking before, you couldn't filter your current result since you'd only be looking at the values and two null strings are identical, but if the key is important, that gives you a way to filter it! – wjandrea May 19 '20 at 14:14
  • That `convert_value` function doesn't match your example data. `convert_value('foo')` -> `''` – wjandrea May 19 '20 at 14:22
  • yeah, I'm sorry, I shouldnt have named it convert_value, its a different one. As I said, there a multiple different ones. – c8999c 3f964f64 May 19 '20 at 14:24

1 Answers1

1

You can try emulating container types:

class CustomDict(dict): 
    def __setitem__(self, key, item): 
        if item: 
            super().__setitem__(key, item)

a = CustomDict()
a['1'] = 1
a['2'] = 0
a # should show {'1': 1}

I found this related question

Lucas Wieloch
  • 818
  • 7
  • 19
  • This is not bad, however, it will apply the "if item:" rule to ALL items, instead of only those keys I chose. Is there a way to check if item is itself a function, perhaps? – c8999c 3f964f64 May 19 '20 at 14:23
  • Yes, but that would be another `if`. You could also pass a tuples in place of `item` or `key` arguments and treat these tuples differently. But you see, you would always be adding more and more complexity to adding a key to the dictionary. Yet, this is intended to be very customisable, so I think you can surely adapt it to whatever you need – Lucas Wieloch May 19 '20 at 14:39
  • I see that, but I was really hoping for a "or pass" expression that I didnt know about. (similar to providing a default value, but removing the key entirely instead). Unfortunately it seems that doesnt exist. I'll accept this answer if nothing else surfaces – c8999c 3f964f64 May 19 '20 at 14:58
  • I implemented this, but was unable to pick up on "items" being a function - it seems they are converted to strings always, before the __setitem__ function can pick them up when they're still functions. Basically, it removes ALL items which are falsy, not just those who go through a converter function first - which isnt ideal, and not entirely what I hoped for – c8999c 3f964f64 May 20 '20 at 09:10