开发者

The most Pythonic way of checking if a value in a dictionary is defined/has zero length

开发者 https://www.devze.com 2023-04-13 06:34 出处:网络
Say I have a dictionary, and I want to check if a key is mapped to a nonempty value.One way of doing this would be the len function:

Say I have a dictionary, and I want to check if a key is mapped to a nonempty value. One way of doing this would be the len function:

mydict = {"key" : "value", "emptykey" : ""}
print "True" if len(mydict["key"]) > 0 else "False"  # prints true
print "True" if len(mydict["emptykey"]) > 0 else "False"  # prints false

However, one can rely on the semantics of Python and how if an object is defined it evaluates to true and leave out the len call:

mydict = {"key" : "value", "emptykey" : ""}
print "True" if mydict["key"] else "False"  # prints true
print "True" if mydict["emptykey"] else "False"  # prints false

However, I'm not sure which is more Pythonic. The first feels "explicit is better than implicit", however the second feels "simple is better than complex".

I also wonder if the leaving out the len call could bite me as the dict I'm working with doesn't necessarily contain strings, but could contain other len-able types (lists, sets, etc). OTOH, in the former (with the len call) if None gets stored as a value the code will blow up, whereas the 开发者_C百科non-len version will work as expected (will eval to false).

Which version is safer and more Pythonic?

Edit: clarifying assumptions: I know the key is in the dictionary, and I know values will be len-able. I also cannot avoid having zero-length values enter the dictionary.

Edit #2: It seems like people are missing the point of my question. I'm not trying to determine the most Pythonic/safest way of checking if a key is present in a dictionary, I'm trying to check if a value has zero length or not


If you know the key is in the dictionary, use

if mydict["key"]:
    ...

It is simple, easy to read, and says, "if the value tied to 'key' evaluates to True, do something". The important tidbit to know is that container types (dict, list, tuple, str, etc) only evaluate to True if their len is greater than 0.

It will also raise a KeyError if your premise that a key is in mydict is violated.

All this makes it Pythonic.


print (bool(mydict.get('key')))

or, in an if statement:

print ('True' if mydict.get('key') else 'False')

If you the value not being present is an error case (i.e. you expect it to be there), you should choose solution #2, i.e.

print ('True' if mydict['key'] else 'False')

That allows mydict['key'] to choose the most efficient definition for being empty. For some objects (such as ones in clusters), determining the actual length is a fairly complicated operation, whereas it's simple to determine whether the object is empty or not.

You could also compare to '', i.e. mydict['key'] == '', to make your expression abundantly clear. Using len works, but is not as intuitive.

In summary, leave it to the tested object to define whether it's empty or not and just cast it to bool.


I'd use a variation of the first option:

>>> mydict = {"key" : "value", "emptykey" : ""}
>>> print bool(mydict["key"])
True
>>> print bool(mydict["emptykey"])
False

Any class that provides __len__ can be converted into a boolean directly (see Truth Value Testing), so bool(container) is the equivalent of bool(len(container)). A length of 0 will become the boolean False while all other lengths will be True. You'll never have a negative length object. Also, the booleans True and False can be printed directly via print, so you don't need the conditional.


From here:

In the context of Boolean operations, and also when expressions are used by control flow statements, the following values are interpreted as false: False, None, numeric zero of all types, and empty strings and containers (including strings, tuples, lists, dictionaries, sets and frozensets). All other values are interpreted as true.

I think it's safe to say that directly evaluating it is your best option - although, as @phihag said, it's safer to use get instead, as it will protect you from a KeyError.


The title and the first sentence actually express two slightly different questions.

For the title question

The most Pythonic way of checking if a value in a dictionary is defined

I'd go with

"key" in mydict

and for the second question

Say I have a dictionary, and I want to check if a key is mapped to a nonempty value.

I'd go with

"key" in mydict and bool(mydict["key"])

The first part of which checks to see whether "key" is present in mydict and the second part returns true for all values of "key" other then False, None, the empty string, the empty dictionary, the empty list and 0.


Of your two examples I prefer the second.

However, I advise against storing the empty keys. Also a defaultdict would work well here:

>>> from collections import defaultdict
>>> d = defaultdict(list)
>>> d[1].append(1)
>>> 1 in d
True

If you must store empty keys you don't need the string values "True" and "False". Just do this:

print bool(mydict[key])


You can simply check that any value in the dict is zero length or not by :

# To get keys which having zero length value:
keys_list = [key for key,val in mydict.items() if not val]


# To check whether the dict has any zero length value in it (returns True or False):
any_empty_vals = bool(len(['' for x in data_dict.values() if not x]))


Since I came here to know whether we can check the dictionary key is present or not for those the answer is:

if mydict.get(key,0):
    ---

and for the length of the key > 0, the answer is already provided by @Ethan Furman

if mydict[key]:
    ---


mydict = {"key" : "value", "emptykey" : ""}

if not mydict["emptykey"]:
   print("empty value")
else:
   print("value of emptykey",mydict["emptykey"])

Output

empty value


The most Pythonic way would be to not define the undefined value (although whether this is usable depends on what you're using it for) and use in:

mydict = {"key" : "value"}
print "True" if "key" in mydict else "False"  # prints true
print "True" if "emptykey" in mydict else "False"  # prints false

Otherwise, you have three options:

  1. Use mydict.get. You should use this if the key might or might not be in the dictionary.
  2. Use mydict[key]. You should use this if you are certain the key you want is in the dict.
  3. Use len(mydict[key]) > 0. This only works if the value has __len__ defined. Usually, the truth value of a container value depends on the __len__ anyway, so the above are preferable.


When parsing a function's kwargs, it does make sense why the dictionary might contain a key whose value is None, and that you'd need to know whether that function's argument was passed in equal to None, or just not defined. Here's the simplest way to disabiguate:

def myfunct(**kwargs):
    if 'thiskey' not in kwargs:
        # this means that 'thiskey' was never passed into myfunct().
        kwargs['thiskey'] = <default value>
    else:
        # you can define the defaults differently; 
        # if was defined as None, keep it set to None this way.
        kwargs['thiskey'] = kwargs.get('thiskey', None)
        # otherwise, any defined value passes through.
    # do stuff...


I wanted to know which key is missing, so I could go fix it (in the db for example), but I also didn't want to do an if statement for each key in my dictionary! Here is my code:

def do_sth_with_data(data):

        assert isinstance(data, dict)
      
        expected_data_keys = {
            "id",
            "title",
            "date",
            "key4",
            "key5",
            "key6"

        }

        empty_keys = [key for key in expected_data_keys if not data.get(key)]
        if empty_keys:
            raise ValueError(f"{empty_keys} keys are not provided or are empty!")

If you also want to distinguish between key missing and value for the key is missing, you could add a script like this (change the code logic based on your need):

assert expected_data_keys.issubset(set(data.keys()))

Remember that data.get(key) will return None by default if either the key doesn't exist or the key exists but the corresponding value is empty (e.g. [], {}, None, "")


Your initial conditions are not Pythonic. Why are you storing a key with an empty value? Can you delete the key instead of setting it to None?

The Pythonic way is to check key existence with if key in dictionary, not checking for a non-empty value.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号