This is because the ResultProxy returned from conn.execute() is what
is known in Python as "iterable", which basically means that you can
iterate over it (for example, use it in a "for" loop or a list
comprehension).
The main catch is that you can only iterate over the ResultProxy once,
so the following wouldn't work:
rows = conn.execute(check)
# This line iterates over the ResultProxy, consuming it in the process
obj1 = [dict(row.items()) for row in rows]
# This line will not do what you expect because
# the ResultProxy has been consumed
obj2 = [dict(row.items()) for row in rows]
If you use .fetchall(), then "rows" is a simple python list, so you
can iterate over it as many times as you like. For what you are trying
to do, you don't need to iterate over it more than once, so it doesn't
really matter which you do.
There are other things to be aware of. You can't necessarily use the
len() function to get the length of an arbitrary iterable, you can't
sort them in place, and so on.
Hope that helps,
Simon