在Python程序中为参数分配随机值
我想在 __init__()
里给一个默认的随机值。例如:
import math
import random
class Test:
def __init__(self, r = random.randrange(0, math.pow(2,128)-1)):
self.r = r
print self.r
如果我创建10个 Test 的实例,它们都会得到完全一样的随机值。我不明白为什么会这样。我知道可以在 __init__()
里面给随机值,但我很好奇为什么会出现这种情况。我最开始的猜测是随机数的种子是当前时间,而对象创建得太接近了,所以结果是一样的。我试着把对象创建间隔1秒,但结果还是一样。
4 个回答
你所有类的实例都有相同参数值的原因是,因为这个默认值只在方法定义被编译时确定一次,也就是在执行 class
语句的时候。
虽然这不是它设计的初衷,但你可以使用《Python Cookbook, 2nd Edition》中第20.14条的内容,标题为实例属性的自动初始化,来实现你想要的效果。
下面是应用到你问题中的示例代码:
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
类的一个属性,名为 r
。第一次你在 Test
的实例中通过 self.r
访问这个属性时,Python 会注意到它绑定了一个描述符,并调用它的 __get__()
方法,同时将 Test
实例作为 obj
参数传入。
描述符的 __get__()
方法会调用相关的工厂函数,并将结果赋值给一个同名的实例属性,这样之后通过实例对这个属性的所有引用都会得到它的实际值,而不是 Test
类的 auto_attr
描述符。
这里的 random.randrange(0, math.pow(2,128)-1)
是在函数定义的时候就被计算了,而不是在你实际调用这个函数的时候。
所以,应该使用
class Test:
def __init__(self, r = None):
if r is None:
r = random.randrange(0, math.pow(2,128)-1)
self.r = r
print self.r
来代替。
默认参数的值是在函数创建的时候就已经设定好的,而不是在函数被调用的时候设定的,所以每次调用的时候这个值都是一样的。
通常处理这个问题的方法是把默认参数设置为 None
,然后用 if
语句来检查它。
import math
import random
class Test:
def __init__(self, r = None):
if r is None:
r = random.randrange(0, math.pow(2,128)-1)
self.r = r
print self.r