can i implement virtual functions in python ?

Discussion in 'Python' started by Prabu, Sep 30, 2003.

  1. Prabu

    Prabu Guest

    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.
    Prabu, Sep 30, 2003
    #1
    1. Advertising

  2. Prabu wrote:
    > 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
    =?ISO-8859-1?Q?Gerhard_H=E4ring?=, Sep 30, 2003
    #2
    1. Advertising

  3. Prabu

    franck Guest

    my friend python coder, tell me all function are virtual in python , so...

    "Prabu" <> a écrit dans le message news:
    ...
    > 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.
    franck, Sep 30, 2003
    #3
  4. Prabu

    JCM Guest

    Prabu <> wrote:
    ....
    > 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".
    JCM, Sep 30, 2003
    #4
  5. Prabu

    Miki Tebeka Guest

    Miki Tebeka, Sep 30, 2003
    #5
  6. Prabu

    Paradox Guest

    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
    Paradox, Sep 30, 2003
    #6
  7. (Prabu) wrote in message news:<>...
    > 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 ()
    - see 'Help/About PythonWin' for further copyright information.
    >>> class virtualClass:

    .... 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"
    ....

    >>> x = virtualClass()


    >>> x.concreteMethod1()

    The concrete method is implemented

    >>> x.virtualMethod1()

    Traceback (most recent call last):
    File "<interactive input>", line 1, in ?
    File "<interactive input>", line 5, in virtualMethod1
    NotImplementedError: virtualMethod1 is virutal and must be overridden.

    >>> class subClass(virtualClass):

    .... def virtualMethod1(self):
    .... print "sub class implemented virtualMethod1"
    ....

    >>> y = subClass()


    >>> y.concreteMethod1()

    The concrete method is implemented

    >>> y.virtualMethod1()

    sub class implemented virtualMethod1

    >>>
    logistix at cathoderaymission.net, Sep 30, 2003
    #7
  8. Prabu

    Andrew Dalke Guest

    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
    Andrew Dalke, Oct 1, 2003
    #8
  9. Prabu

    Peter Otten Guest

    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
    Peter Otten, Oct 1, 2003
    #9
  10. Prabu

    Andrew Dalke Guest

    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
    Andrew Dalke, Oct 1, 2003
    #10
  11. 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
    Alex Martelli, Oct 1, 2003
    #11
  12. On 30 Sep 2003 07:53:07 -0700, (Prabu) wrote:

    >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.


    --
    Steve Horne

    steve at ninereeds dot fsnet dot co dot uk
    Stephen Horne, Oct 1, 2003
    #12
  13. "Andrew Dalke" <> wrote in message news:<jtseb.10860$>...
    > 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.
    >


    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. ;)
    logistix at cathoderaymission.net, Oct 1, 2003
    #13
  14. Prabu

    Andrew Dalke Guest

    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.



    > > 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;-).


    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
    Andrew Dalke, Oct 1, 2003
    #14
  15. Prabu

    Andrew Dalke Guest

    Me:
    > > 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.


    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
    Andrew Dalke, Oct 1, 2003
    #15
  16. "Andrew Dalke" <> wrote in message news:<dPGeb.11520$>...
    > Me:
    > > > 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.

    >
    > 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 ;)
    >



    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.
    logistix at cathoderaymission.net, Oct 2, 2003
    #16
    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. Michael Winter
    Replies:
    9
    Views:
    607
    Michael Winter
    Sep 24, 2003
  2. heted7
    Replies:
    33
    Views:
    1,015
    Chris Dearlove
    May 12, 2005
  3. Replies:
    3
    Views:
    365
    Nitin Motgi
    Jan 31, 2006
  4. Replies:
    7
    Views:
    367
    Richard
    Aug 28, 2006
  5. John Goche
    Replies:
    10
    Views:
    720
    Marcus Kwok
    Dec 8, 2006
Loading...

Share This Page