-2

Python stores key/values in dictionaries.

In this example values (which are dictionaries themselves) are stored in "lut".

lut = {}
pair="  "
line = "halhak"
for letter in line.strip() + ' ':
                d = lut.setdefault(pair, {})
                d[letter] = d.get(letter, 0) + 1
                pair = pair[1] + letter

The key / values are:

for key in lut:
    print key, "/", lut[key]

   / {'h': 1}
ak / {' ': 1}
al / {'h': 1}
lh / {'a': 1}
ha / {'k': 1, 'l': 1}
 h / {'a': 1}

My question: I don't see where the loop assigns any values to "lut" different from "{}".

Gantter
  • 13
  • 4

3 Answers3

1

d is always a reference to some element of lut. Here's a similar example that shows how it works.

>>> lut = {1 : {}}
>>> d = lut[1]
>>> d is lut[1]
True

lut[1] is a reference to some dictionary, and the value of d is a reference to that same dictionary, as verified by the is operator. Operations on d and operations on lut[1] operate on the same object.

In your actual code, a call to setdefault is involved:

d = lut.setdefault(pair, {})

The setdefault method does two things: if pair is not in lut, it first sets the value of lut[pair] to the given value. Then it returns the value of lut[pair]. It's identical to the following code

if pair not in lut:
    lut[pair] = {}
d = lut[pair]
chepner
  • 497,756
  • 71
  • 530
  • 681
0

Only empty dicts {} are directly added to lut, using setdefault().

As described in the documentation, setdefault always returns a value for any given key:

setdefault(key[, default])

If key is in the dictionary, return its value. If not, insert key with a value of default and return default. default defaults to None.

So d is always a dict - one of the values in the outer lut dict.

However, the next line modifies one of these (initially empty) dicts out of lut, which is why you see populated dicts in the results.

DNA
  • 42,007
  • 12
  • 107
  • 146
  • I was not aware that "=" is an assignement in this case. Is there a rule in Python when "=" assigns values or references? – Gantter May 28 '15 at 20:26
0

The expression d = lut.setdefault(pair, {}) does one of two things, depending on wether or not the pair key is present:

  1. pair is present; return a reference to the value
  2. pair is not present; set lut[pair] to the second argument ({}), and return it.

Either way, you now have a reference to the object referenced by lut[pair], which is always a dictionary.

Modifying that dictionary means that all references everywhere can see those changes. d[letter] = d.get(letter, 0) + 1 will set a key-value pair in that dictionary. Since both d and lut[pair] reference that dictionary, you can later iterate over lut to see those changes.

A quick demo:

>>> lut = {}
>>> d = lut.setdefault('foo', {})
>>> lut
{'foo': {}}
>>> d
{}
>>> d is lut['foo']
True
>>> d['bar'] = 42
>>> d
{'bar': 42}
>>> lut
{'foo': {'bar': 42}}
>>> lut['foo']
{'bar': 42}
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • Thanks! For simple variables "=" assigns values. Is there a rule when "=" is a reference or value? – Gantter May 28 '15 at 20:23
  • @Gantter: everything in Python is an object, and assignment always gives you a reference to that object. – Martijn Pieters May 28 '15 at 20:26
  • @Gantter: some object types are immutable, so operations produce *new* objects; `foo = 10; foo = foo + 5` gives you a new object, `15`. But a dictionary is a mutable object, so you can manipulate it directly. `dict.setdefault()` is a method that manipulates the object, and `dictobject[key] = new_value` assigns directly to a key on the dictionary, not the `dictobject` name. – Martijn Pieters May 28 '15 at 20:28
  • @Gantter: also see [Immutable vs mutable types - Python](http://stackoverflow.com/q/8056130) – Martijn Pieters May 28 '15 at 20:28
  • a = 7; b = 8; a = b; print a; b = 9; print a; print b -> 8; 8; 9 (ie. a keeps the value 8) – Gantter May 28 '15 at 20:29
  • @Gantter: yes, because `b` is rebound to a different object. `b = 9` changes what `b` references, not what `a` references. They may have started referencing the same thing, but don't continue to do so. See http://nedbatchelder.com/text/names.html and, for a visualisation: http://www.pythontutor.com/visualize.html#code=a+%3D+7%0Ab+%3D+8%0Aa+%3D+b%0Aprint+a%0Ab+%3D+9%0Aprint+a%0Aprint+b&mode=display&origin=opt-frontend.js&cumulative=false&heapPrimitives=true&textReferences=false&py=2&rawInputLstJSON=%5B%5D&curInstr=0 – Martijn Pieters May 28 '15 at 20:39
  • Thanks a lot for the comments which introduce me to the beginning of deeper understandig of programming! – Gantter May 28 '15 at 21:05