The reason that all instances of your class have the same value for the argument is because its default value is defined only once when the definition of the method in which it is part is compiled as part of the execution of the class statement.
Even though it was not intended for this, you can use Recipe 20.14 called “Automatically Initialize Attribute Attributes” from several Python Cookbook dated 2nd Edition to achieve what you want to do.
This applies to the sample code in your question:
class AutoAttr(object): def __init__(self, name, factory, *args, **kwds): self.data = name, factory, args, kwds def __get__(self, obj, cls=None): name, factory, args, kwds = self.data setattr(obj, name, factory(*args, **kwds)) return getattr(obj, name) import math import random class Test(object): r = AutoAttr('r', random.randrange, 0, math.pow(2,128)-1)
Output Example:
282,608,676,427,101,189,083,121,399,193,871,110,434 211,475,719,281,604,076,410,306,973,803,289,140,631 86,842,148,927,120,143,765,936,219,265,140,532,918 41,767,122,731,332,110,507,836,985,804,081,250,336 97,993,619,669,833,151,963,441,072,354,430,500,011 42
Here's how it works:
The auto_attr class from the recipe is called descriptor . One of them is assigned to the attribute of the Test class named r . The first time this attribute is accessed in a Test instance using self.r , Python notes that it is associated with the handle and calls its __get__() method with the Test instance as an obj argument.
The descriptor method __get__() calls the associated factory function and assigns the result to an instance attribute with the same name, so that all further references to this attribute through the instance will get its actual value instead of Test class auto_attr .