Clean way to not get object back from instantiation attempt gone bad
Steven D'Aprano
steve at REMOVEME.cybersource.com.au
Tue Aug 15 21:19:08 EDT 2006
On Tue, 15 Aug 2006 16:04:12 -0700, tobiah wrote:
> Suppose I do:
>
>
> myfoo = Foo('grapes', 'oranges')
>
> And in the __init__() of Foo, there is
> a real problem with the consumption of fruit.
> Is there a clean way to ensure that myfoo
> will be None after the call?
I don't believe so.
Generally, in the event of an error, you should raise an exception:
class Foo():
def __init__(self, *fruits):
if "grapes" in fruits:
raise AllergyError("I'm allergic to grapes")
# process fruits
Then handle the exception:
try:
myfoo = Foo('grapes', 'oranges')
except AllergyError:
# recover gracefully
handle_failed_instance()
If you wish, you can wrap it in a function:
def safe_foo(*fruits):
try:
return Foo(*fruits)
except AllergyError:
return None
myfoo = safe_foo('grapes', 'oranges')
The disadvantage of this is now your code has to be sprinkled with a
million tests "if myfoo is not None: process(myfoo)".
> Would the
> __init__() just do del(self), or is there
> a better way to think about this?
An alternative is to use a propagating "not a Foo" Foo object, like NaNs
and INFs in floating point.
class Foo():
def __init__(self, *fruits):
if "grapes" in fruits:
self._state = "failed" # NaNs use special bit patterns
else:
# process fruits
self._state = "okay"
def method(self, *args):
if self._state != "failed":
# process instance
else:
pass # do nothing
def __add__(self, other):
if self._state == "failed":
return self
elif other._state == "failed":
return other
else:
# process Foo addition
return something
Now you can call Foo methods regardless of whether the instance is valid
or not, errors will propagate cleanly, and you only need to check whether
the instance is valid at the very end of your code.
However, unless there is a clear advantage of doing this, you're creating
a fair bit of extra work for yourself.
--
Steven D'Aprano
More information about the Python-list
mailing list