can i implement virtual functions in python ?

P

Prabu

Hi,

I'm new to python, so excuse me if i'm asking something dumb.
Does python provide a mechanism to implement virtual functions?
Can you please give a code snippet also...:)
Thanx in advance
-Prabu.
 
?

=?ISO-8859-1?Q?Gerhard_H=E4ring?=

Prabu said:
Hi,

I'm new to python, so excuse me if i'm asking something dumb.
Does python provide a mechanism to implement virtual functions? [...]

What do you mean with "virtual function"?

If you mean virtual methods in the C++ sense, all methods are "virtual"
in Python.

-- Gerhard
 
J

JCM

Prabu said:
I'm new to python, so excuse me if i'm asking something dumb.
Does python provide a mechanism to implement virtual functions?

Others have given good responses, but I'll jump in anyway.

Virtual functions (using C++ terminology) are something limited to
statically-typed languages. A virtual function call will be resolved
dynamically, based on the runtime type of the object. A non-virtual
call will be resolved at compile-time, based on the declared type of
the object. Since Python is dynamically typed, the only possibility
is for all methods to be "virtual".
 
P

Paradox

I think you can do something like this.

class Virtual:
def myFunc(self, x):
pass

class Implement(Virtual):
def myFunc(self, x):
return x * x
 
L

logistix at cathoderaymission.net

Hi,

I'm new to python, so excuse me if i'm asking something dumb.
Does python provide a mechanism to implement virtual functions?
Can you please give a code snippet also...:)
Thanx in advance
-Prabu.

As others have mentioned, all methods are overridable in python. But
if you want to create a genuine Abstract Base Class, raise
NotImplementedErrors for the virual methods. People will tell you
that this is not 'pythonic' (you should be using hasattr() to test for
interfaces) but I still find it useful from time to time.

PythonWin 2.3.2c1 (#48, Sep 30 2003, 09:28:31) [MSC v.1200 32 bit
(Intel)] on win32.
Portions Copyright 1994-2001 Mark Hammond ([email protected])
- see 'Help/About PythonWin' for further copyright information..... def __init__(self):
.... pass
.... def virtualMethod1(self):
.... raise NotImplementedError("virtualMethod1 is virutal and
must be overridden.")
.... def concreteMethod1(self):
.... print "The concrete method is implemented"
....
The concrete method is implemented
Traceback (most recent call last):
File "<interactive input>", line 1, in ?
.... def virtualMethod1(self):
.... print "sub class implemented virtualMethod1"
....
The concrete method is implemented
sub class implemented virtualMethod1
 
A

Andrew Dalke

logistix at cathoderaymission.net:
if you want to create a genuine Abstract Base Class, raise
NotImplementedErrors for the virual methods. People will tell you
that this is not 'pythonic' (you should be using hasattr() to test for
interfaces) but I still find it useful from time to time.

Really? I find hasattr to be non-Pythonic. Just get the object, like

try:
method = obj.function_name
except AttributeError:
... not implemented ...

However, I do use NotImplementedError so the exception
which percolates up is more obvious than AttributeError. It also
allows me to put in a docstring describing the interface requirements
of derived classes.

I also don't like the double attribute lookup in

if not hasattr(obj, "function_name"):
... not implemented ...
else:
obj.function_name(...)

but that's more a personal issue than Pythonic vs. non-Pythonic.

Andrew
(e-mail address removed)
 
P

Peter Otten

Andrew Dalke wrote:

I also don't like the double attribute lookup in

if not hasattr(obj, "function_name"):
... not implemented ...
else:
obj.function_name(...)

Have you considered using getattr() with a default?

class Test:
def there(self):
print "there"

def default():
print "default"

t = Test()
for name in "there notThere".split():
getattr(t, name, default)()


Peter
 
A

Andrew Dalke

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
(e-mail address removed)
 
A

Alex Martelli

Andrew Dalke wrote:
...
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

I think the "guaranteed to be unique" comment SHOULD make it
pretty obvious (to Pythonistas advanced enough to grasp the
try/except/else construct that we both prefer).
and it uses a standard construct instead of depending
on a class creation to make an object which is guaranteed
to be unique.

Actually if you object to the "class creation" (which IS also
a standard construct:), use ANY mutable object instead, e.g.:

_default = [] # ANY arbitrary mutable object, just for uniqueness
f = getattr(x, 'there', _default)
# etc etc

In any case, remember that I said it's a personal preference,

Yeah, that's probably what's rubbing on people's nerves -- there
is SUPPOSED TO BE "ideally only one obvious way". Maybe it
would help if we were Dutch;-).


Alex
 
S

Stephen Horne

Hi,

I'm new to python, so excuse me if i'm asking something dumb.
Does python provide a mechanism to implement virtual functions?
Can you please give a code snippet also...:)
Thanx in advance
-Prabu.

As others have said, in Python all methods are effectively virtual.

Late (or dynamic) binding is the object-oriented ideal, and that is
what virtual methods give you in C++.

In C++, dynamic binding requires a 'virtual table' to provide the link
from an instance object to the appropriate implementation of a virtual
method. The instance object contains a pointer to the virtual table,
which in turn contains effectively a function pointer for each virtual
method.

This is done purely so that the caller need not know exactly what
class it is calling and yet the correct implementation of the method
will be invoked. The decision of exactly what implementation of that
function to call is made at runtime (ie late) rather than at compile
time.

The trouble is that this virtual-table lookup is sometimes considered
slow. A statically bound (or early bound) method is a little faster
because the decision of what implementation to call has been made by
the compiler at each point where the method is called. Virtual table
lookup isn't needed.

Basically, a C++ virtual method call is implemented something like the
following...

(instance_obj->vtable [method_id]) (instance_obj, other_args);

Whereas a C++ non-virtual method call is simply...

method_fn (instance_obj, other_args);

(this is, I think, only the single inheritance case - things may be a
bit more complex for multiple inheritance)

Python is a much more dynamic language than terms such as 'early
binding' would imply. Each call has a lookup by name at the time it is
called. This certainly supports dynamic binding, but goes further -
you can pass any instance object that provides the required set of
methods to a function and that function will just work.

If your reason for using a base class to your subclasses is simply so
that the same functions/classes can call shared methods in the
subclasses, this is unnecessary and provides few benefits in Python.
Python classes tend to share a 'protocol' rather than an explicit
interface. At least 90% of the time, inheritance in Python is just a
shorthand for creating a class which implements the same protocol (and
a way of making the relationship more explicit in the source code, of
course). Actually checking the type of an instance object is quite
rare in my experience.
 
L

logistix at cathoderaymission.net

Andrew Dalke said:
logistix at cathoderaymission.net:

Really? I find hasattr to be non-Pythonic. Just get the object, like

try:
method = obj.function_name
except AttributeError:
... not implemented ...

However, I do use NotImplementedError so the exception
which percolates up is more obvious than AttributeError. It also
allows me to put in a docstring describing the interface requirements
of derived classes.

I also don't like the double attribute lookup in

if not hasattr(obj, "function_name"):
... not implemented ...
else:
obj.function_name(...)

but that's more a personal issue than Pythonic vs. non-Pythonic.

Yes, try...except is equally valid, but I'm still brainwashed to
believe that exceptions are bad and should be avoided if possible. I
still cringe when I write code that throws a 'StopIteration'
exception. Like you say, its a personal issue, and I'll bring it up
with my therapist.

The point I was trying to make is that the least pythonic way to test
is use inheritance based interfaces and issubclass() or isinstance().
I've got yelled at every time I've posted code here that does it.

Still, once you get beyond trivial examples and you're writing special
purpose code I find it handy. For example, what's the best way to
test for an interface in this code?

def foo(x):
x.a()
x.b()
x.c()

Either using hasattr or or a try...except clause gets a little clunky.
I'd just rather do something like:

class abstract:
def a(self): raise NotImplementedError("Virtual Method")
def b(self): raise NotImplementedError("Virtual Method")
def c(self): raise NotImplementedError("Virtual Method")

class implementation(abstract):
def a(self): print "a"
def b(self): print "b"
def c(self): print "c"

def foo(x):
assert isinstance(x, abstract), "foo expects an 'abstract'
interface"
x.a()
x.b()
x.c()

Or I suppose I could just let the interpreter throw an exception for
me when it can't find any of the appropriate methods. ;)
 
A

Andrew Dalke

Alex:
I think the "guaranteed to be unique" comment SHOULD make it
pretty obvious (to Pythonistas advanced enough to grasp the
try/except/else construct that we both prefer).

True. I don't like making the comment since it feels like I'm
using a side effect of the implementation.
Actually if you object to the "class creation" (which IS also
a standard construct:), use ANY mutable object instead, e.g.:

Ahh, of course. Is that guaranteed in the language spec?
For example, suppose I had

x = []
y = []
assert x is not y

Could a future Python implementation support copy-on-write
and return a reference to the same empty list, but which
becomes a different list on mutation?

Here's what the docs say:
] Every object has an identity, a type and a value. An object's
] identity never changes once it has been created; you may
] think of it as the object's address in memory. The `is' operator
] compares the identity of two objects; the id() function returns
] an integer representing its identity (currently implemented as its
] address).

In order for my conjecture to occur, x and y would have to
have the same id, as that's what the 'is' test uses. But since
since the id is fixed over the lifetime of an object, copy-on-write
won't change it, so all lists which start as [] would have the
same id. Since I'm supposed to think of the id as a position
in memory, I have to assume that two objects with the same
id are the same object, so no, a future implementation cannot
make this change.


Yeah, that's probably what's rubbing on people's nerves -- there
is SUPPOSED TO BE "ideally only one obvious way". Maybe it
would help if we were Dutch;-).

I'm 1/4th Dutch; is that my problem? :)

No, you're right. I'm a proponent of the "preferably only one
obvious way to do it" guideline. Why do I consider this a personal
preference?

When I use default arguments and need to distinguish between
a 1 argument and a 2 argument call (which is rare), I'll use

class _undefined: pass

def function(a, b = _undefined):
if b is _undefined:
...

In addition, if I need to do several test for exists/doesn't exist
(also rare) then I'll do

class _undefined: pass

x = getattr(obj, "blah", _undefined)
if x is _undefined:
...
y = getattr(obj, "blarg", _undefined)
if y is _undefeind:
...

because it's more concise than the try/except/else approach.

Interesting. I looks like my internal guideline is to use
t/e/e iff the test is needed once and if a _undefined object
is not defined in the module, else use an _undefined.

That seems inelegant. If there's a prefered style for this
then it seems it should be the use of an _undefined object
and not t/e/e.

Comments?

Andrew
(e-mail address removed)
 
A

Andrew Dalke

Me:
logistix at cathoderaymission.net:
Either using hasattr or or a try...except clause gets a little clunky.
I'd just rather do something like:

class abstract:
def a(self): raise NotImplementedError("Virtual Method")
def b(self): raise NotImplementedError("Virtual Method")
def c(self): raise NotImplementedError("Virtual Method")

Well, I agreed with you ;)

I think this is the right way, and it lets you include a
docstring to describe the interface better.

Andrew
(e-mail address removed)
 
L

logistix at cathoderaymission.net

Andrew Dalke said:
Me:

logistix at cathoderaymission.net:

Well, I agreed with you ;)


DOH! You did agree with me ;) Sorry about that. I thought you were
talking about re-raising an AttributeError as a NotImplementedError in
the except clause.
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top