0

Recently, to describe dictionary comprehensions in Python, I wrote:

dictionary comprehension is just a more compact & expressive way of writing the same logic as for loops (performance may differ).

  1. Is this a correct characterization of Python's dictionary comprehension?
  2. Is it possible to give an objective(-ish) definition of the term expressive used to describe computer code?
  3. Does it make sense to use expressive and compact together to describe code? What are some other examples?
  • 2
    "Compact" and "Expressive" are not formally defined terms, so there can be no correct answer, only opinions. – Doc Brown May 19 '15 at 5:50
  • @DocBrown How about relatively compact and expressive? – tchakravarty May 19 '15 at 5:51
  • 2
    You missed my point. Maybe you can improve your question by adding your definition of "compact" and "expressive". – Doc Brown May 19 '15 at 5:56
  • @fgnu Are you trying to ask "Are all Python list comprehensions equivalent to for loops?" That would probably be a good question. – Ixrec May 19 '15 at 6:35
  • 1
    Can you write a program to transform each valid dictionary comprension into its corresponding equivalent for-loop? If so, you could make the claim that the dictionary comprehension is "syntactic sugar", especially if the Python compiler actually does a similar transformation when compiling the code. I wouldn't say "syntatic sugar" is more 'expressive', just more convenient. – Brandin May 19 '15 at 9:26
3

To me, "expressive" means that you can express a large diversity of concepts with it.

In many programming languages, a foreach loop (iterating over a container) is less "expressive" than a for loop. Because you can always trivially rewrite the former in terms of the latter, but not vice versa.

Analogously, I would say that dictionary comprehensions are not more expressive than looping constructs, but less so.

  • For me, "expressive" corresponds to the fact that you can convey ideas is a readable and concise way (as opposed to boiler-plate). Thus, foreach loops and list comprehension are more expressive because they are straightforward to read and usually more concise. – SylvainD May 19 '15 at 8:00
  • @Josay Yup, that's definitely different from my definition of "expressive". – Atsby May 19 '15 at 8:04
  • 1
    'Expressive power' has a specific meaning when discussing computer languages, if you use 'expressive' by itself then half your audience will think you mean the non-technical 'effective at conveying meaning' and half will think you mean 'having a greater expressive power' – Pete Kirkham May 19 '15 at 8:16
  • might be worth pointing out that less expressive is potentially better IFF the things that cannot be expressed are error prone – jk. May 19 '15 at 10:09
  • With respect to the "rewrite" test, note that there are situations where a foreach loop cannot be rewritten in terms of an integer-based for-loop. This happens when the container is unordered, i.e. an unordered set, items in hash table, etc. So foreach and for had their own uniquely applicable situations. – rwong May 19 '15 at 11:15
3

A dictionary comprehension is expressive in the sense that by using one, you are expressing that your intent is to create a dictionary. You can always do the same thing in a for loop, but doing so does not express that intent. It is something the reader has to determine by code inspection. So consider this:

cache = {key:lookup(key) for key in keystore}

Now compare to a version without a dictionary comprehension:

cache = {}
for key in keystore:
    cache[key] = lookup(key)

The first version is a bit more compact. But more importantly, it directly expresses that your intent is to create a dictionary. In the for loop version, you have to read the code and see that this is what the result is.

The other point to consider is that a dictionary comprehension version is inherently simpler than a for loop version. A dictionary comprehension cannot fail to produce a dictionary. There are a number of mistakes that you could potentially make in the for loop version that cannot occur in the dictionary comprehension.

Here's an example of how a comprehension might help avoid a defect:

cache = {}
for key in keystore:
    cache[key] = lookup(key)

cache2 = {}
for key in keystore2:
    cache[key] = lookup(key)  # oops

We decided to use a second cache, but when copy-pasting, we introduced a defect. Now look at the dictionary comprehension version:

cache = {key:lookup(key) for key in keystore}
cache2 = {key:lookup(key) for key in keystore2}

Because cache appears twice in the for loop version, it is possible for those two instances to become misaligned. That is impossible with the dictionary comprehension because the target dictionary only appears once.

I know this example seems trivial, but in the real world, with more complex code (for instance, if you have an if/else clause) this problem becomes worse.

  • Can you elaborate on the last part? – tchakravarty May 19 '15 at 15:56
  • sure, I've added an example. – Gort the Robot May 19 '15 at 17:09
  • Your example would be a prime candidate for a function, which makes that problem go away. – Blrfl May 19 '15 at 17:42
1

IMO expressiveness is a trait of the language/framework/library as a whole - not of a single feature/function in it. Some operations can be better expressed with for loops, some with dictionary comprehensions - so I wouldn't say that one is more expressive than the other, but that Python as a whole is more expressive for having both.

Compactness is something that can be used to describe a single feature, but I wouldn't say that dictionary comprehensions are always more compact than for loops. For example, I'd argue that

for i in range(10):
    print(i)

is more compact than

def foo(x):
    print(x)

{i: foo(i) for i in range(10)}

Of course, this is a very obvious abuse of dictionary comprehensions, but there can also be less obvious abuses. The point is that list/dictionary comprehensions targets a more specific use cases than for loops, and they can be more compact only in these cases.

If you are looking for the right terminology, I'd say that:

dictionary comprehension is just a more functional way of writing the same logic as for loops (performance may differ).

Not the answer you're looking for? Browse other questions tagged or ask your own question.