Class instantiation question

Discussion in 'Python' started by Todd Johnson, Oct 7, 2003.

  1. Todd Johnson

    Todd Johnson Guest

    Ok, say I have a class MyClass and an __init__(self,
    a, b) Say that a and b are required to be integers
    for example. So my init looks like:

    __init__(self, a, b):
    try:
    self.one = int(a)
    self.two = int(b)
    except ValueError:
    #nice error message here
    return None

    I have even tried a similar example with if-else
    instead of try-except, but no matter what if I call

    thisInstance = MyClass(3, "somestring")

    it will set self.one to 3 and self.two will be
    uninitialised. The behavior I am hoping for, is that
    thisInstance is not created instead(or is None). How
    do I get the behavior I am looking for?

    Thanks in advance,
    Todd

    __________________________________
    Do you Yahoo!?
    The New Yahoo! Shopping - with improved product search
    http://shopping.yahoo.com
     
    Todd Johnson, Oct 7, 2003
    #1
    1. Advertising

  2. Todd Johnson

    anton muhin Guest

    Todd Johnson wrote:

    > Ok, say I have a class MyClass and an __init__(self,
    > a, b) Say that a and b are required to be integers
    > for example. So my init looks like:
    >
    > __init__(self, a, b):
    > try:
    > self.one = int(a)
    > self.two = int(b)
    > except ValueError:
    > #nice error message here
    > return None
    >
    > I have even tried a similar example with if-else
    > instead of try-except, but no matter what if I call
    >
    > thisInstance = MyClass(3, "somestring")
    >
    > it will set self.one to 3 and self.two will be
    > uninitialised. The behavior I am hoping for, is that
    > thisInstance is not created instead(or is None). How
    > do I get the behavior I am looking for?
    >
    > Thanks in advance,
    > Todd


    If I'm correct, __init__ method is somewhat different from what you
    expect: it *doesn't* return values (None is just a fake return value).
    Actually MyClass(...) proceeds more or less in the following way:

    1) create an object
    2) call __init__ with parameters passed
    3) return the object's reference.

    Therefore, you cannot prevent object creation in __init__. You can only
    throw an exception.

    Actually, I see no reason to use if/then instead try/except or maybe
    even simple self.one = int(a) (that will throw if anythins goes wrong),
    but if you want, for example, to create another object depending on
    parameters passed, take a look at __new__ method.

    regards,
    anton.
     
    anton muhin, Oct 7, 2003
    #2
    1. Advertising

  3. Todd Johnson

    Carl Banks Guest

    Todd Johnson wrote:
    > Ok, say I have a class MyClass and an __init__(self,
    > a, b) Say that a and b are required to be integers
    > for example. So my init looks like:
    >
    > __init__(self, a, b):
    > try:
    > self.one = int(a)
    > self.two = int(b)
    > except ValueError:
    > #nice error message here
    > return None
    >
    > I have even tried a similar example with if-else
    > instead of try-except, but no matter what if I call
    >
    > thisInstance = MyClass(3, "somestring")
    >
    > it will set self.one to 3 and self.two will be
    > uninitialised. The behavior I am hoping for, is that
    > thisInstance is not created instead(or is None). How
    > do I get the behavior I am looking for?



    1. I highly recommend you rethink your programming. Are you planning
    to handle the error in the function that called the MyClass
    contructor? In other words, are you doing something like this:

    def some_function(a,b):
    thisInstance = MyClass(a,b)
    if thisInstance is None:
    handle_error()
    else:
    do_something_useful(thisInstance)

    If so, you are not taking full advantage of the exception handling
    mechanism. The best way to do it is like this:

    def some_function(a,b):
    try:
    thisInstance = MyClass(a,b)
    except ValueError:
    handler_error()
    else:
    do_something_useful(thisInstance)

    As always, a larger code snippet can help us help you with that, if
    you wish.


    2. If you're sure the behavior you want is to return None if a or b is
    not an integer, then I recommned you use a factory function:

    def my_class_maker(a,b):
    try:
    return MyClass(a,b)
    except ValueError:
    return None


    --
    CARL BANKS http://www.aerojockey.com/software

    As the newest Lady Turnpot descended into the kitchen wrapped only in
    her celery-green dressing gown, her creamy bosom rising and falling
    like a temperamental souffle, her tart mouth pursed in distaste, the
    sous-chef whispered to the scullery boy, "I don't know what to make of
    her."
    --Laurel Fortuner, Montendre, France
    1992 Bulwer-Lytton Fiction Contest Winner
     
    Carl Banks, Oct 7, 2003
    #3
  4. Todd Johnson

    David C. Fox Guest

    Todd Johnson wrote:

    > Ok, say I have a class MyClass and an __init__(self,
    > a, b) Say that a and b are required to be integers
    > for example. So my init looks like:
    >
    > __init__(self, a, b):
    > try:
    > self.one = int(a)
    > self.two = int(b)
    > except ValueError:
    > #nice error message here
    > return None
    >
    > I have even tried a similar example with if-else
    > instead of try-except, but no matter what if I call
    >
    > thisInstance = MyClass(3, "somestring")
    >
    > it will set self.one to 3 and self.two will be
    > uninitialised. The behavior I am hoping for, is that
    > thisInstance is not created instead(or is None). How
    > do I get the behavior I am looking for?


    As far as I know, the only way to prevent __init__ from creating an
    instance is for __init__ to raise an exception which is NOT caught and
    handled within __init__. In your example, I think simply doing

    class MyClass(self, a, b):
    def __init__(self, a, b):
    self.one = int(a)
    self.two = int(b)

    without the try...except block should do it. Then the calling code can
    handle the ValueError appropriately.

    David
     
    David C. Fox, Oct 7, 2003
    #4
  5. Todd Johnson

    Matt Brubeck Guest

    Todd Johnson <> wrote:

    > Ok, say I have a class MyClass and an __init__(self,
    > a, b) Say that a and b are required to be integers
    > for example. So my init looks like:
    >
    > __init__(self, a, b):
    > try:
    > self.one = int(a)
    > self.two = int(b)
    > except ValueError:
    > #nice error message here
    > return None
    >
    > I have even tried a similar example with if-else
    > instead of try-except, but no matter what if I call
    >
    > thisInstance = MyClass(3, "somestring")
    >
    > it will set self.one to 3 and self.two will be
    > uninitialised. The behavior I am hoping for, is that
    > thisInstance is not created instead(or is None). How
    > do I get the behavior I am looking for?


    Here's one option:

    >>> class C:

    .... def __init__(self, a):
    .... self.a = int(a)
    ....
    >>> c = C("hello")

    Traceback (most recent call last):
    File "<stdin>", line 1, in ?
    File "<stdin>", line 3, in __init__
    ValueError: invalid literal for int(): hello

    This also allows the following:

    >>> try: c = C("hello")

    .... except ValueError: c = None
    ....
    >>> print c

    None

    If you really want initialization to return None instead of raising an
    exception, you can override the __new__ method of a new-style class:

    >>> class C(object):

    .... def __new__(cls, a):
    .... try: a = int(a)
    .... except ValueError: return None
    .... return object.__new__(cls, a)
    .... def __init__(self, a):
    .... self.a = a
    ....
    >>> c = C(1)
    >>> c.a

    1
    >>> c = C("hello")
    >>> print c

    None
     
    Matt Brubeck, Oct 8, 2003
    #5
  6. Todd Johnson wrote:

    > Ok, say I have a class MyClass and an __init__(self,
    > a, b) Say that a and b are required to be integers
    > for example. So my init looks like:
    >
    > __init__(self, a, b):
    > try:
    > self.one = int(a)
    > self.two = int(b)
    > except ValueError:
    > #nice error message here
    > return None


    Any return statement in __init__ MUST return None (you
    get an error otherwise). The job of __init__ is
    preparing the self, which is already created.

    > I have even tried a similar example with if-else
    > instead of try-except, but no matter what if I call
    >
    > thisInstance = MyClass(3, "somestring")
    >
    > it will set self.one to 3 and self.two will be
    > uninitialised. The behavior I am hoping for, is that
    > thisInstance is not created instead(or is None). How
    > do I get the behavior I am looking for?


    It's not a nice architecture AT ALL, but if you
    insist you can have it -- as long at least as
    class MyClass is new-style, e.g., subclasses
    object -- by defining a __new__ method. The
    process of calling a class can be summarized as:

    [[ function equivalent to calling theclass with
    positional args *a and named args **k ...: ]]

    result = theclass.__new__(theclass, *a, **k)
    if isinstance(result, theclass):
    theclass.__init__(result, *a, **k)
    return result

    Normally, it's best to do all the work in __init__
    and thus to inherit __new__ from type object.
    But that's only for the NORMAL case, where one
    assumes that calling theclass always either
    raises / propagates an exception OR else returns
    an instance of theclass. Since you deliberately
    want to break this normal, expected rule --
    having the call to theclass return None instead! --
    you would need to define __new__.

    For example:


    class theclass(object):

    def __new__(cls, a, b):
    self = object.__new__(cls)
    try:
    self.one = int(a)
    self.two = int(b)
    except ValueError:
    #nice error message here
    return None
    else:
    return self

    I would still recommend you to reconsider the
    architecture you want. Why MUST you break all
    normal Pythonic expectations of users of your
    class...? If you must, Python lets you -- but
    MUST you, really...?


    Alex
     
    Alex Martelli, Oct 8, 2003
    #6
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Jeff Carver
    Replies:
    3
    Views:
    452
    Jeff Carver
    Aug 25, 2004
  2. E11
    Replies:
    1
    Views:
    4,850
    Thomas Weidenfeller
    Oct 12, 2005
  3. Replies:
    1
    Views:
    590
    Salt_Peter
    Dec 25, 2006
  4. Devon Null
    Replies:
    4
    Views:
    325
    Devon Null
    Jun 1, 2007
  5. Replies:
    8
    Views:
    300
    Bo Persson
    Jul 1, 2008
Loading...

Share This Page