Python Forum

Full Version: How does this if clause work?
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
In this thread from just a couple of days ago here, an elegant solution was given.

I was impressed, so I am trying to figure out how it works. Something similar may be useful for me.

But I cannot see how the if clause does its job.

Could some kind soul please enlighten me?

I tried taking away the if clause, then filter_dicts(data, *args, **kwargs) returns id and result from all the dictionaries in the list.

I added some bits to the solution given to make it more human-readable for me.

lexis = [{"id": 1, "a": 1, "b": 2, "result": 9.82},
        {"id": 2, "a": 1, "b": 2, "result": -5},
        {"id": 3, "a": 1, "b": 5, "result": 7.98},
        {"id": 4, "a": 1, "b": 2, "result": 11.1},
        {"id": 5, "a": 1, "b": 2, "result": -4},
        {"id": 6, "a": 1, "b": 5, "result": 6.33},
        {"id": 7, "a": 1, "b": 2, "result": 8.88},
        {"id": 8, "a": 1, "b": 2, "result": -2},
        {"id": 9, "a": 1, "b": 5, "result": 5.44},
        {"id": 10, "a": 1, "b": 5, "result": 10}]

def filter_dicts(data, *args, **kwargs):
    # added by me
    for a in args:
        print('args are:', a) # returns id and result
    for k in kwargs:
        print('kwargs are:', k) # returns a and b
    for row in data:
        print('data contains:', row)
        if row.items() >= kwargs.items():
            # row.items() is 4 tuples long, kwargs.items() is 2 tuples long 
            print('row.items are:', row.items())
            print('kwargs.items are:', kwargs.items()) 
    # end of added by me       
    return  ({key: row[key] for key in args}  for row in data  if row.items() >= kwargs.items())

res = filter_dicts(lexis, 'id', 'result', a=1, b=2)

for r in res:
    print(r)
Python's documentation explains that the objects returned by dict.items() are set-like and can therefore be compared
the documentation Wrote:Keys views are set-like since their entries are unique and hashable. If all values are hashable, so that (key, value) pairs are unique and hashable, then the items view is also set-like. (Values views are not treated as set-like since the entries are generally not unique.) For set-like views, all of the operations defined for the abstract base class collections.abc.Set are available (for example, ==, <, or ^).
Thanks for the tip.

I looked up sets and found >= means x1.issuperset(x2)

The function filter_dicts did not like that:

Quote:Traceback (most recent call last):
File "<pyshell#16>", line 1, in <module>
for r in res:
File "<pyshell#13>", line 12, in <genexpr>
return ({key: row[key] for key in args} for row in data if row.items().issuperset(kwargs.items()))
AttributeError: 'dict_items' object has no attribute 'issuperset'

So I went back to >=

But now I know how the if clause works!

Thank you!
set instances implement more methods than the collections.abc.Set abstract class. Classes such as dict_items that implement this interface need not implement all the set type's attributes.