Python constructor argument not random error?

I recently found this strange Python error, and I wanted to know if anyone knew about this!

for example take the python module:

import random class SaySomething: def __init__(self, value=random.randint(1, 3)): if value == 1: print 'one' elif value == 2: print 'two' elif value == 3: print 'three' a = 0 while a < 10: SaySomething() a += 1 

This code for any reason will print YOUR number 10 times !!! Now I dont understand. It seems that the constructor is being called with the same values ​​10 times in a row. But if you print each SaySomething() , you will see that they all have different pointer addresses, so they are not the same object.

Now if you change:

 SaySomething() 

to

 SaySomething(random.randint(1, 3)) 

Works as expected with actual random choices.

Does anyone know why this is happening?

+4
source share
4 answers

The problem is that the default arguments in Python are evaluated once when the function is created. To fix this, try:

  def __init__(self, value = None): if value is None: value = random.randint(1, 3) if value == 1: print 'one' elif value == 2: print 'two' elif value == 3: print 'three' 

Thus, we transfer randomization to the function itself, and not during the definition of the function.

+13
source

In python, default arguments are initialized once. This way you get the same value over and over again because it is the value when the default argument was initialized. See http://www.deadlybloodyserious.com/2008/05/default-argument-blunders/

+4
source

This is because when a class is compiled or interpreted, the value of the value variable is set to random.randint(1, 3) , and it does not change until you pass it some other value.

+3
source

For the same reason as in the Python constructor, doing strange things with optional parameters

the default value of the optional argument is the only instance and therefore is calculated only once for all instances.

To fix this:

 import random class saySomething: def __init__(self, value = None): random_value = random.randint(1, 3) if value == None else value if random_value in [1, 2, 3] print ['one', 'two', 'three'][random_value - 1] for a in xrange(10): saySomething() 
+1
source

All Articles