Peter Otten:
Have you considered using getattr() with a default?
Yes, I have. It isn't always the right solution, unless
you do a bit of trickery.
Consider
class Test:
def there(self):
return DBConnect("example.com", "user", "passwd")
class TestNotThere:
pass
if random.choice([0, 1]) == 1:
x = Test()
else:
x = TestNotThere()
if hasattr(x, "there"):
conn = x.there()
conn.query("this where that is the other").dump()
print "There you go", conn.username
conn.shutdown()
You can't replace the hasattr(x, "there") with a
getattr(x, "there", default_function) because even if
the default function returned an object which implements
'query', 'shutdown' and 'user' correctly, the output will
contain the text "There you go", which shouldn't happen.
A better option getattr solution is to compare the
returned object against the default
f = getattr(x, "there", None)
if f is not None:
conn = f()
...
(Note that you must use 'is' here and not == because
the latter can trigger arbitrary Python code, which has
a different behaviour than the hasattr approach.)
However, suppose TestNotThere.there is not a method
but is the None object. The original hasattr code raises
a 'TypeError - not callable' exception but this getattr
version won't, which means the API is different and
allows errors to slip silently by.
The better solution is to create an object which you
can guarantee is not present anywhere else. For
example, you could do
class _default: pass # guaranteed to be unique
f = getattr(x, "there", _default)
if f is not _default:
conn = f()
...
I don't consider that code all that clean. It isn't obvious
why the _default class is needed. Compare that to my
prefered code
try:
f = x.there
except AttributeError:
pass
else:
conn = f()
This code is longer, and I admit it isn't the clearest (I
would prefer the exception case be after the else case).
It's also slower because of the exception creation, unless
exceptions are rare. But it exactly equivalent to the
hasattr test except without the double attribute lookup,
and it uses a standard construct instead of depending
on a class creation to make an object which is guaranteed
to be unique.
In any case, remember that I said it's a personal preference,
Plus, most of the time a getattr with a default value is
the right solution. It's just not a general panacea.
Andrew
da***@dalkescientific.com