2012-06-02 118 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