can i implement virtual functions in python ?

Andrew Dalke adalke at mindspring.com
Wed Oct 1 03:21:24 EDT 2003


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
                    dalke at dalkescientific.com






More information about the Python-list mailing list