7

I've been trying to figuring this out for the last few hours, and I'm about to give up.

How do you make sure that in python only a matching specific criteria will create the object?

For example, let's say I want to create an object Hand, and initialize a Hand only when I have enough Fingers in the initializer? (Please just take this as an analogy)

Say,

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

Thanks.

These are the closest questions I found, but one is in C++, the other does not answer my question.

checking of constructor parameter

How to overload __init__ method based on argument type?

2
  • 1
    What do you want to happen if this is not the case? Do you want it to raise some sort of exception? Commented Jun 2, 2012 at 23:36
  • I guess that would be a good way. Just to make sure that I don't create a wrong object. Commented Jun 2, 2012 at 23:52

2 Answers 2

7

You have to define __new__ for that:

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

That said, using __init__ and raising an exception on invalid args is generally much better:

class Foo(object):
    def __init__(self, arg):
        if arg > 10: #error!
            raise ValueError("invalid argument!") 
        # do stuff
Sign up to request clarification or add additional context in comments.

3 Comments

Defining __new__ is rarely needed, and returning None from it is horrible. Just throw an exception rather than going on for a couple of lines (or a dozen function calls, if you've got bad luck) before crashing with an inexplicable error.
@delnan - technically, if the OP is serious about "only a matching specific criteria will create the object," defining __new__ would be needed, because by the time __init__ is called an object has already been created (still, you're right that raising an exception in __new__ would be better than returning None). But I'm guessing the OP doesn't really mean that, in which case the __init__ version is definitely better.
@weronika Unless deep magic and awful hackery is involved, raising an exception in __init__ prevents everyone from getting a reference to the not-really-constructed object. So from an observer's POV there's no difference beside one being a terrible API.
0

Try asserting:

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

1 Comment

No, assert is for verifying internal invariants: Checking that your code isn't horribly broken. AssertionError conveys no useful information to the caller, and may make her think your code is broken. Besides, assertions are stripped by -O. Throw a ValueError or RuntimeError or whatever is appropriate for the specific use case.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.