1

In the below code I am not able to understand how the variables field and value are being used because they are being assigned in the next line in the for loop.

I looked at the for in this syntax and examples but couldn't find anything useful which can explain this behaviour.

match = re.search(someregx, some_text)
current_row = {
    field: value.strip() if value else '' for field, value in match.groupdict().items()
}
smci
  • 32,567
  • 20
  • 113
  • 146
Yogeshwar Singh
  • 1,245
  • 1
  • 10
  • 22
  • Please post your complete code – Mithilesh_Kunal Jul 04 '19 at 06:29
  • 8
    The expression is a [dict comprehension](https://www.python.org/dev/peps/pep-0274/). – Mark Tolonen Jul 04 '19 at 06:31
  • I don't think `for ...` is the next line, it's executed before the `if` phrase – AcaNg Jul 04 '19 at 06:34
  • Related, but not exact duplicate, since this is asking about the syntax in this specific case, including the conditional expression: [Create a dictionary with list comprehension](https://stackoverflow.com/questions/1747817/create-a-dictionary-with-list-comprehension), [How to use if/else in a dictionary comprehension?](https://stackoverflow.com/questions/9442724/how-to-use-if-else-in-a-dictionary-comprehension) – smci Jul 04 '19 at 08:57

2 Answers2

3

This is a dict comprehension. It creates a dict from the specified expressions. {...} is equivalent syntax to dict(...) in Python. (And in this particular case it's specifically creating a dict(iterable) from iterable; see bottom).

Ok so what does all this Python jargon mean? First, consider a list comprehension in Python which is an expression that creates a list from the given input, for example:

odd_numbers = [ n for n in range(100) if n%2 == 1 ] 

Analogously, let's start with the most basic dict comprehension:

{ k: v for k, v in ... } 

and note that the RHS match.groupdict().items() is an iterable, we're just iterating over the output from a regex match, as dictionary items. (Let's just write ... hereafter for the RHS, to minimize clutter).

Next, adding the v if v else '' is a conditional expression in Python, here it just handles the case if one of the value is None, and gives empty-string '' instead of None (which would (annoyingly) throw Exceptions if you tried to do further string-processing on it, and presumably we don't want to have to write try...except around every time we attempt to process the string value). It throws new users in Python a bit that the if in a conditional expression precedes the iterable that defines them, as you say. The first time you see it, it looks like a soup of keywords in the wrong order :) (The combination of comprehensions, conditional expressions and combining and nesting these allows Python to be really expressive while being compact.)

Hence we're looking at:

{ k: v if v else '' for k, v in ... } 

or in this particular case, and calling the key variable field:

{ field: value.strip() if value else '' for field, value in match.groupdict().items() }

Once you know that {...} is equivalent to dict(...), the help(dict) information helps you understand that this code is creating a dict(iterable) from iterable ; the 3rd case shown below in the syntax for dict(...):

class dict(object)
 |  dict() -> new empty dictionary
 |
 |  dict(mapping) -> new dictionary initialized from a mapping object's
 |      (key, value) pairs
 |
 |  dict(iterable) -> new dictionary initialized as if via:
 |      d = {}
 |      for k, v in iterable:
 |          d[k] = v
 | ...

Miscellanous tips:

  • Formatting: don't format braces on a separate line as if they were a C/C++/Java compound statement block, Python simply doesn't use braces like that, we're very proud of that :). In Python {...} is equivalent to dict(...). So whenever you see braces you're looking at a dict, nested dict, dict-of-list, JSON expression, etc. ...
  • ... or else a set. A set is essentially a dict that has keys but no value e.g. {'b', 'f', 'g'}. You can also have a set comprehension, except instead of { k: v for k, v ... } it's just { k for k in ... }. Here's an example: odd_numbers = { n for n in range(100) if n%2 == 1 }. In sets, order doesn't matter, unlike a tuple.
  • No surrounding spaces: I wrote the dict, list and set comprehensions with space around the [ ... ] or { ... }, but that was just for clarity in explaining the syntax. The Pythonic (PEP-8) way is not to write a space.
  • Brevity: it's conventional in dict comprehensions to give key, value very short or one-letter names { k: v for k, v in ... }, esp. if they're complicated expressions, so you don't repeatedly waste space and need huge or wrapped lines.
  • Related questions: Create a dictionary with list comprehension, How to use if/else in a dictionary comprehension?
  • Please also skim the Python Programming FAQ and Functional Programming HOWTO, just enough so you understand the concepts and will recognize the syntax in future whenever you see it being used, then you can go back and read up in more detail.
smci
  • 32,567
  • 20
  • 113
  • 146
  • 1
    thank you for the really good explanation... also the formatting tip I will keep in mind, I just realized it after reading your answer.. :) – Yogeshwar Singh Jul 04 '19 at 07:29
2

It's dictionary comprehension, and it's equivalent to

current_row = {}
for field, value in match.groupdict().items():
    if value:
        current_row[field] = value.strip()
    else:
        current_row[field] = ''
cyfex
  • 55
  • 10