2012-06-02 40 views
5

我一直試圖在過去的幾個小時里弄清楚這一點,而我即將放棄。Python檢查__init__參數

你如何確保在Python中只有匹配的特定條件纔會創建對象?

例如,假設我想創建一個對象Hand,並且只在初始化程序中有足夠的Fingers時初始化一個Hand? (請只是以此爲比喻)

說,

class Hand: 
    def __init__(self, fingers): 
    # make sure len(fingers)==5, and 
    #only thumb, index, middle, ring, pinky are allowed in fingers 
    pass 

感謝。

這些是我發現的最接近的問題,但一個是在C++中,另一個不回答我的問題。

checking of constructor parameter

How to overload __init__ method based on argument type?

+1

如果情況並非如此,您會發生什麼?你想讓它產生某種異常嗎? – BrenBarn

+0

我想這將是一個好方法。只是爲了確保我不會創建錯誤的對象。 – chemelnucfin

回答

5

你必須定義__new__爲:

class Foo(object): 
    def __new__(cls, arg): 
     if arg > 10: #error! 
      return None 
     return super(Foo, cls).__new__(cls) 

print Foo(1) # <__main__.Foo object at 0x10c903410> 
print Foo(100) # None 

也就是說,使用__init__和提高對INVA異常蓋子的參數通常要好很多:

class Foo(object): 
    def __init__(self, arg): 
     if arg > 10: #error! 
      raise ValueError("invalid argument!") 
     # do stuff 
+5

很少需要定義'__new__',並且從中返回'None'是非常可怕的。只是拋出一個異常,而不是在發生莫名其妙的錯誤之前進行幾行(或十幾個函數調用,如果運氣不好)。 – delnan

+0

@delnan - 從技術上講,如果OP認真對待「只有匹配的特定條件纔會創建該對象,」將需要定義'__new__',因爲在調用__init__時已經創建了一個對象(仍然,你是對的,在'__new__'中引發異常比返回None要好。但我猜測OP並不是真的意味着,在這種情況下'__init__'版本肯定會更好。 – weronika

+0

@weronika除非涉及深度魔法和可怕的hackery,否則引發'__init__'中的異常會阻止所有人獲得對非真正構造對象的引用。所以從觀察者的POV來看,除了一個糟糕的API之外沒有什麼區別。 – delnan

0

嘗試斷言:

class Hand(object): 
    def __init__(self,fingers): 
     assert len(fingers) == 5 
     for fing in ("thumb","index","middle","ring","pinky"): 
      assert fingers.has_key(fing) 
+4

不,'assert'用於驗證內部不變量:檢查*你的*代碼沒有被破壞。 'AssertionError'不會向呼叫者傳達有用的信息,並可能使她認爲你的代碼被破壞了。此外,斷言被「-O」剝離。拋出一個'ValueError'或'RuntimeError'或任何適合特定用例的東西。 – delnan