2011-06-24 35 views
4

我需要在__init__()中分配默認隨機值。例如:將隨機值分配給python程序中的參數

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秒的對象,但結果仍然相同。

回答

13

默認參數的值在創建函數時設置,而不是在被調用時設置 - 這就是每次都是一樣的原因。

解決此問題的典型方法是將默認參數設置爲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 
3

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 

代替。

1

當您將表達式放入構造函數頭(而不是構造函數體)內時,它只會被計算一次。

在身體試試這個:

self.r = random.randrange(0,math.pow(0,128)-1) 
+0

但是,當表達式用於定義構造函數參數的默認值時爲true,但一般而言,構造函數中的其他表達式在每次調用初始化實例時都會被計算。 – martineau

+0

@martineau:你指的是什麼其他表情? –

+0

@Ethan Furman:任何不用於定義構造函數參數默認值的表達式在每次被調用時都會被評估,比如那些出現在方法本體內部的表達式 - 比如本答案中所示。 – martineau

1

的原因,你的所有的類實例有參數相同的值,因爲它的默認值被確定只有一次,當方法定義,它是被編譯部分作爲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類是稱爲descriptor。其中一個被分配到Test類別屬性名稱r。第一次在Test使用self.r的實例中訪問此屬性時,Python會注意到它與描述符綁定,並將其__get__()方法與Test實例作爲obj參數進行調用。

描述符的__get__()方法調用相關的工廠功能和結果分配給具有相同名稱的實例屬性,以便於通過實例該屬性的所有引用會得到它的實際價值,而不是Test類的auto_attr的描述。

相關問題