1

I'm trying to understand following python code as I'm new to it.

import random

howMany = random.randint(0,1000)
stats = {}
for i in range(howMany):
   value = random.randint(0,500)
   stats.setdefault(value,0)
   stats[value]+=1
for item in stats:
   if stats[item] > 1:
       print item

Here is what I have understood so far, my questions will follow afterwards:

  1. howMany stores the random number generated between 0 & 1000 inclusive of both.

  2. stats = {} declares an empty dictionary

  3. i will run depending upon the value of howMany. For example if howMany was 2 so i will run for two times with values is 0 and 1.

  4. value variable stores random number between 0 & 500 inclusive of both

  5. I didn't understand stats.setdefault(value,0). For example, the value variable has value 4, then stats.setdefault(4,0) means what?

  6. What does stats[value]+=1 do? The expanded form of stats[value]+=1 is stats[value] = value + 1?

  7. I understood the following paragraph:

    for item in stats:
       if stats[item] > 1:
           print item
    

    Those values are printed which are greater than 1 in the stats dictionary. Please correct me if I'm wrong somewhere.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Tan
  • 1,433
  • 5
  • 27
  • 47

5 Answers5

3

5. dict.setdefault(key, default) does this:

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 it makes sure all keys start with 0 as the associated value.

stats.setdefault(value, 0)

is therefore equivalent to

if value not in stats:
    stats[value] = 0

6. No. But these are equivalent (good catch, glglgl):

stats[value] += 1
stats[value] = stats[value] + 1

They result in two different method calls in stats (__iadd__ vs. __setitem__), so for some objects they do differ, but here they're equivalent. See the excellent link in Ashwini's answer for examples of this.

7. This code prints out all values that occur more than once.

In python 2.7+, your code sample would be better written using the collections.Counter class:

import random
import collections

howMany = random.randint(0,1000)
stats = collections.Counter(random.randint(0, 500) for i in range(howMany))
for item in stats:
   if stats[item] > 1:
       print item
Lauritz V. Thaulow
  • 49,139
  • 12
  • 73
  • 92
2

stats.setdefault(value,0) means if a key named value is present in stats then return its value otherwise create a new key named value and set it's value to 0 and then return 0.

>>> dic = {}
>>> dic.setdefault("foo",5)  #creates a new key "foo" with value 5 and returns 5
5
>>> dic
{'foo': 5}
>>> dic.setdefault("foo",10)  # "foo" is already present then simply return it's value
5

help on dict.setdefault:

>>> dict.setdefault?
String Form:<method 'setdefault' of 'dict' objects>
Namespace:  Python builtin
Docstring:  D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D

What does stats[value]+=1 do?

stats[value]+=1 is equivalent to stats[value] = stats[value] +1

Though += can behave differently for different objects, for details read this:

When is "i += x" different from "i = i + x" in Python?

Community
  • 1
  • 1
Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504
  • For immutable values, `a += b` is indeed equivalent to `a = a + b`, but for *mutable* values that is not necessarily true. For a list `a`, `a += b` means `a.extend(b)` for example. In-place operations can behave differently. – Martijn Pieters May 08 '13 at 08:47
2

I didn't understand "stats.setdefault(value,0)". For example, the "value" variable has value 4, then stats.setdefault(4,0) means what?

The setdefault() method of dictionaries returns a value, when the key passed in does not match. value is the key being searched for, and 0 is the value to set and return when no key is found.

It is used to avoid the KeyError exception, and to set default values for keys that don't exist:

>>> d = {'a': 1}
>>> d['b']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'b'
>>> d.setdefault('b',2)
2
>>> d
{'a': 1, 'b': 2}

What does "stats[value]+=1" does? Is the expanded form of stats[value]+=1 is stats[value] = value + 1 ?

Not quite, it means stats[value] = stats[value] + 1.

Burhan Khalid
  • 169,990
  • 18
  • 245
  • 284
1

stats.setdefault(value,0) will set the default value for stats[value] to 0. That is, the value 0 is associated with the key value only if it doesn't have a value associated with it before. It effecitvley is the same as:

if not stats.has_key(value):
    stats[value] = 0

This means that the first time value is seen, it will have a value of 0 associated with it. This is important as you couldn't do the next step stats[value]+=1 which expands to stats[value] = stats[value]+1, as it requires stats[value] to be defined, in this case it is defined as zero (if this is the first occurance of value, due to the .setdefault(value,0)). After which point it's incremented and the next time around, stats.setdefault(value,0) is redundant as it already has a value.

The following should make what setdefault does more obvious:

>>> d = {} #make a dictionary
>>> d.setdefault("key",100) #associate the value 100, with the key "key"
100
>>> d["key"] #see what is associated with "key"
100
>>> d["key"]+=100 #increment by 100
>>> d["key"] #test to see if incrementing worked
200
>>> d["notkey"]+=100 #demo to show what happens if we hadn't done defaultdict


Traceback (most recent call last):
  File "<pyshell#9>", line 1, in <module>
    d["notkey"]+=100
KeyError: 'notkey'

>>> d.setdefault("notkey",100) #set a default
100
>>> d["notkey"]+=100
>>> d["notkey"]
200
HennyH
  • 7,794
  • 2
  • 29
  • 39
1

5) from documentation:

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.

6) Almost the same as stats[value] = stats[value] + 1

Operator += performs an operation "in place" and in some cases can modify an existing object. Also, these operators may be different behavior, since it is determined by different methods __add__ and __iadd__. However, in most cases you should not be concerned, because if method __iadd__ is not explicitly overridden, the augmented assignment falls back to the method __add__.

Example of different behavior:

>>> y = x = [1, 2, 3]
>>> x + [4, 5]   # create *new* list
[1, 2, 3, 4, 5]
>>> y
[1, 2, 3]        # old list is not modified

>>> y = x = [1, 2, 3]
>>> x += [4, 5]  # the operation is performed "in place", new object is not created
>>> y
[1, 2, 3, 4, 5]  # value of list changes
defuz
  • 26,721
  • 10
  • 38
  • 60