Причина, по которой все экземпляры вашего класса имеют одинаковое значение для аргумента, заключается в том, что его значение по умолчанию определяется только один раз, когда определение метода, частью которого он является, компилируется как часть выполнения оператора class
.
Хотя это не то использование, для которого оно было разработано, вы можете использовать рецепт 20.14 под названием Автоматическая инициализация атрибутов экземпляра из несколько устаревшей Python Cookbook, 2nd Edition чтобы достичь того, что вы хотите сделать.
Это применимо к примеру кода в вашем вопросе:
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) # default value
def __init__(self, r=None):
if r is not None: # argument value supplied to override default?
self.r = r
print format(self.r, ',d')
for i in xrange(5):
Test()
Test(42) # override default random initial value
Пример вывода:
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
Вот какэто работает:
Класс auto_attr
из рецепта называется дескриптором .Один из них назначен атрибуту Test
class с именем r
.При первом обращении к этому атрибуту в экземпляре Test
с использованием self.r
Python замечает, что он связан с дескриптором, и вызывает его метод __get__()
с экземпляром Test
в качестве аргумента obj
.
Метод дескриптора __get__()
вызывает связанную фабричную функцию и присваивает результат атрибуту instance с тем же именем, так что все последующие ссылки на этот атрибут через экземпляр получат его фактическое значение вместодескриптор Test
класса *1037*.