Pure virtual functions in Python?

Discussion in 'Python' started by lallous, Feb 20, 2010.

  1. lallous

    lallous Guest

    Hello

    How can I do something similar to pure virtual functions in C++ ?

    Let us consider this:

    class C1:

    # Pure virtual
    def cb(self, param1, param2):
    """
    This is a callback

    @param param1: ...
    @param param2: ...
    """
    raise NotImplementedError, "Implement me"

    # Implementation w/o a 'cb', thus 'cb' should not be used
    class C2(C1):
    def __init__(self):
    pass

    # Implementation w/ 'cb', thus 'cb' can be used
    class C3(C1):
    def __init__(self):
    pass

    def cb(self, param1, param2):
    print "i am c3 cb"

    # Dispatcher function that calls 'cb' only if 'cb' is implemented in
    child classes
    def dispatcher(c):
    if hasattr(c, 'cb'):
    c.cb("Hello", "World")

    dispatcher(C2())
    dispatcher(C3())

    What I want is the ability to have the dispatcher() not to call 'cb'
    if it was not implemented in one of the child classes.

    Please advise.
    lallous, Feb 20, 2010
    #1
    1. Advertising

  2. Martin v. Loewis, Feb 20, 2010
    #2
    1. Advertising

  3. Am 20.02.10 17:12, schrieb lallous:
    > Hello
    >
    > How can I do something similar to pure virtual functions in C++ ?
    >
    > Let us consider this:
    >
    > class C1:
    >
    > # Pure virtual
    > def cb(self, param1, param2):
    > """
    > This is a callback
    >
    > @param param1: ...
    > @param param2: ...
    > """
    > raise NotImplementedError, "Implement me"
    >
    > # Implementation w/o a 'cb', thus 'cb' should not be used
    > class C2(C1):
    > def __init__(self):
    > pass
    >
    > # Implementation w/ 'cb', thus 'cb' can be used
    > class C3(C1):
    > def __init__(self):
    > pass
    >
    > def cb(self, param1, param2):
    > print "i am c3 cb"
    >
    > # Dispatcher function that calls 'cb' only if 'cb' is implemented in
    > child classes
    > def dispatcher(c):
    > if hasattr(c, 'cb'):
    > c.cb("Hello", "World")
    >
    > dispatcher(C2())
    > dispatcher(C3())
    >
    > What I want is the ability to have the dispatcher() not to call 'cb'
    > if it was not implemented in one of the child classes.
    >
    > Please advise.


    There is nothing more beyond that what you already did. You can raise a
    NotImplementedError for classes that don't implement the method. That's it.

    Diez
    Diez B. Roggisch, Feb 20, 2010
    #3
  4. >> class C1:
    >>
    >> # Pure virtual
    >> def cb(self, param1, param2):
    >> """
    >> This is a callback
    >>
    >> @param param1: ...
    >> @param param2: ...
    >> """
    >> raise NotImplementedError, "Implement me"
    >>
    >> # Dispatcher function that calls 'cb' only if 'cb' is implemented in
    >> child classes
    >> def dispatcher(c):
    >> if hasattr(c, 'cb'):
    >> c.cb("Hello", "World")
    >>
    >> dispatcher(C2())
    >> dispatcher(C3())
    >>
    >> What I want is the ability to have the dispatcher() not to call 'cb'
    >> if it was not implemented in one of the child classes.
    >>
    >> Please advise.

    >
    > There is nothing more beyond that what you already did. You can raise a
    > NotImplementedError for classes that don't implement the method. That's it.


    That's not true. Currently, the hasattr() call would report that cb is
    available, when it is actually not implemented. It would be possible to
    do something like

    if hasattr(c, 'cb') and not is_pure(c.cb):
    c.cb("Hello", "World")

    is_pure could, for example, look at a function attribute of the
    callback. You'd write something like

    @pure_virtual
    def cb(self, param1, param2):
    not_implemented

    Regards,
    Martin
    Martin v. Loewis, Feb 20, 2010
    #4
  5. Sorry, I totally mis-read the OP, too tired. You are right of course.

    Diez
    Diez B. Roggisch, Feb 20, 2010
    #5
  6. On Saturday 20 February 2010 11:46:42 Diez B. Roggisch wrote:
    > Am 20.02.10 17:12, schrieb lallous:
    > > Hello
    > >
    > > How can I do something similar to pure virtual functions in C++ ?
    > >
    > > Let us consider this:
    > >
    > > class C1:
    > >
    > > # Pure virtual
    > > def cb(self, param1, param2):
    > > """
    > > This is a callback
    > >
    > > @param param1: ...
    > > @param param2: ...
    > > """
    > > raise NotImplementedError, "Implement me"
    > >
    > > # Implementation w/o a 'cb', thus 'cb' should not be used
    > > class C2(C1):
    > > def __init__(self):
    > > pass
    > >
    > > # Implementation w/ 'cb', thus 'cb' can be used
    > > class C3(C1):
    > > def __init__(self):
    > > pass
    > >
    > > def cb(self, param1, param2):
    > > print "i am c3 cb"
    > >
    > > # Dispatcher function that calls 'cb' only if 'cb' is implemented in
    > > child classes
    > > def dispatcher(c):
    > > if hasattr(c, 'cb'):
    > > c.cb("Hello", "World")
    > >
    > > dispatcher(C2())
    > > dispatcher(C3())
    > >
    > > What I want is the ability to have the dispatcher() not to call 'cb'
    > > if it was not implemented in one of the child classes.
    > >
    > > Please advise.

    >
    > There is nothing more beyond that what you already did. You can raise a
    > NotImplementedError for classes that don't implement the method. That's it.
    >
    > Diez
    >


    Perhaps you could use an easier-to-ask-forgiveness-than-permission idiom?

    def dispatcher(c):
    try:
    c.cb("Hello", "World")
    except NotImplementedError:
    pass



    ----
    Rami Chowdhury
    "Passion is inversely proportional to the amount of real information
    available." -- Benford's Law of Controversy
    408-597-7068 (US) / 07875-841-046 (UK) / 01819-245544 (BD)
    Rami Chowdhury, Feb 20, 2010
    #6
  7. lallous

    Peter Otten Guest

    Peter Otten, Feb 20, 2010
    #7
  8. lallous <> writes:

    > Hello
    >
    > How can I do something similar to pure virtual functions in C++ ?
    >
    > Let us consider this:
    >
    > class C1:
    >
    > # Pure virtual
    > def cb(self, param1, param2):
    > """
    > This is a callback
    >
    > @param param1: ...
    > @param param2: ...
    > """
    > raise NotImplementedError, "Implement me"


    Why define it if it is virtual?

    > # Implementation w/o a 'cb', thus 'cb' should not be used
    > class C2(C1):
    > def __init__(self):
    > pass
    >
    > # Implementation w/ 'cb', thus 'cb' can be used
    > class C3(C1):
    > def __init__(self):
    > pass
    >
    > def cb(self, param1, param2):
    > print "i am c3 cb"
    >
    > # Dispatcher function that calls 'cb' only if 'cb' is implemented in
    > child classes
    > def dispatcher(c):
    > if hasattr(c, 'cb'):
    > c.cb("Hello", "World")
    >
    > dispatcher(C2())
    > dispatcher(C3())
    >
    > What I want is the ability to have the dispatcher() not to call 'cb'
    > if it was not implemented in one of the child classes.


    If you don't define cb in the parent class, it'll work.

    --
    Arnaud
    Arnaud Delobelle, Feb 20, 2010
    #8
  9. lallous

    lallous Guest

    On Feb 20, 6:08 pm, "Martin v. Loewis" <> wrote:
    > >> class C1:

    >
    > >>      # Pure virtual
    > >>      def cb(self, param1, param2):
    > >>          """
    > >>          This is a callback

    >
    > >>          @param param1: ...
    > >>          @param param2: ...
    > >>          """
    > >>          raise NotImplementedError, "Implement me"

    >
    > >> # Dispatcher function that calls 'cb' only if 'cb' is implemented in
    > >> child classes
    > >> def dispatcher(c):
    > >>      if hasattr(c, 'cb'):
    > >>          c.cb("Hello", "World")

    >
    > >> dispatcher(C2())
    > >> dispatcher(C3())

    >
    > >> What I want is the ability to have the dispatcher() not to call 'cb'
    > >> if it was not implemented in one of the child classes.

    >
    > >> Please advise.

    >
    > > There is nothing more beyond that what you already did. You can raise a
    > > NotImplementedError for classes that don't implement the method. That's it.

    >
    > That's not true. Currently, the hasattr() call would report that cb is
    > available, when it is actually not implemented. It would be possible to
    > do something like
    >
    >   if hasattr(c, 'cb') and not is_pure(c.cb):
    >       c.cb("Hello", "World")
    >
    > is_pure could, for example, look at a function attribute of the
    > callback. You'd write something like
    >
    >   @pure_virtual
    >   def cb(self, param1, param2):
    >       not_implemented
    >
    > Regards,
    > Martin


    Hello Martine,

    Can you elaborate more on how to use the mechanism you described?

    Thanks,
    Elias
    lallous, Feb 21, 2010
    #9
  10. lallous

    lallous Guest

    Thanks everyone for the answers.

    The dispatcher() is actually sits in C++ code.

    So my code receives an object that is an instance of the base class,
    it PyObject_GetAttrString(py_obj, 'funcname'). If the attribute exists
    I will call PyObject_CallMethod on it.

    If the base defines the method and it was empty, then my C++ code
    would still call the function. This is not optimal because I don't
    want to go from C++ to Python if the _derived_ class does not
    implement the cb. Now the base class should define it so that doc
    parsers properly describe the base class.

    The recipe suggested is not worth the trouble.
    Unfortunately I cannot use abc module since I use Python 2.5
    lallous, Feb 21, 2010
    #10
  11. >> That's not true. Currently, the hasattr() call would report that cb is
    >> available, when it is actually not implemented. It would be possible to
    >> do something like
    >>
    >> if hasattr(c, 'cb') and not is_pure(c.cb):
    >> c.cb("Hello", "World")
    >>
    >> is_pure could, for example, look at a function attribute of the
    >> callback. You'd write something like
    >>
    >> @pure_virtual
    >> def cb(self, param1, param2):
    >> not_implemented
    >>
    >> Regards,
    >> Martin

    >
    > Hello Martine,
    >
    > Can you elaborate more on how to use the mechanism you described?


    There are various ways to do it; the one I had in mind uses function
    attributes:

    def pure_virtual(func):
    func.pure_virtual = True # only presence of attribute matters,
    # not value
    return func

    def is_pure(method): # method might be either a method or a function
    try:
    func = method.im_func
    except AttributeError:
    func = method
    return hasattr(func, 'pure_virtual')

    not_implemented = object() # could also write pass instead, or raise

    HTH,
    Martin
    Martin v. Loewis, Feb 21, 2010
    #11
  12. lallous

    Lie Ryan Guest

    On 02/21/10 19:27, lallous wrote:
    <snip>
    > If the base defines the method and it was empty, then my C++ code
    > would still call the function. This is not optimal because I don't
    > want to go from C++ to Python if the _derived_ class does not
    > implement the cb.


    That sounds like a microoptimization; have you profiled your code and
    determined that calling empty function causes a bottleneck? I doubt it.

    > Now the base class should define it so that doc
    > parsers properly describe the base class.


    > The recipe suggested is not worth the trouble.
    > Unfortunately I cannot use abc module since I use Python 2.5


    Because nobody here could have guessed that your dispatcher was written
    in C++; your problem is near trivial if your dispatcher is a pure-python
    code.
    Lie Ryan, Feb 21, 2010
    #12
  13. lallous wrote:
    > If the base defines the method and it was empty, then my C++ code
    > would still call the function. This is not optimal because I don't
    > want to go from C++ to Python if the _derived_ class does not
    > implement the cb.


    I would simply not implement the method at all in the base
    class. Then the C++ code can do an attribute lookup for
    the method, and if it's not found, do nothing.

    --
    Greg
    Gregory Ewing, Feb 21, 2010
    #13
  14. Arnaud Delobelle wrote:
    > lallous <> writes:
    >
    >
    >> Hello
    >>
    >> How can I do something similar to pure virtual functions in C++ ?
    >>
    >> Let us consider this:
    >>
    >> class C1:
    >>
    >> # Pure virtual
    >> def cb(self, param1, param2):
    >> """
    >> This is a callback
    >>
    >> @param param1: ...
    >> @param param2: ...
    >> """
    >> raise NotImplementedError, "Implement me"
    >>

    >
    > Why define it if it is virtual?
    >


    Slightly off topic but this is often useful when writing interfaces. You
    can then properly document what should any subclass (interface
    implemention) be doing.
    The thing is that in case of virtual methods, you *do want* to raise the
    notImplemented exceptions, meaning you've failed to implement all the
    required methods.
    Strange thing that the OP want to silently call nothing at all when
    calling a virtual method, he looses all the benefits from a virtual design.
    Anyway, I don't deal into code optimization, this is not healthy :)

    JM
    Jean-Michel Pichavant, Feb 24, 2010
    #14
  15. lallous

    lallous Guest

    On Feb 21, 11:21 am, Lie Ryan <> wrote:
    > On 02/21/10 19:27,lallouswrote:
    > <snip>
    >
    > > If the base defines the method and it was empty, then my C++ code
    > > would still call the function. This is not optimal because I don't
    > > want to go from C++ to Python if the _derived_ class does not
    > > implement the cb.

    >
    > That sounds like a microoptimization; have you profiled your code and
    > determined that calling empty function causes a bottleneck? I doubt it.
    >
    > > Now the base class should define it so that doc
    > > parsers properly describe the base class.
    > > The recipe suggested is not worth the trouble.
    > > Unfortunately I cannot use abc module since I use Python 2.5

    >
    > Because nobody here could have guessed that your dispatcher was written
    > in C++; your problem is near trivial if your dispatcher is a pure-python
    > code.


    You are right. I haven't checked how much it costs to continuously
    call an empty function, but why do it if I know (during initialization
    from my C++ dispatcher code) that certain Python object should not
    have certain methods called.

    I still prefer not to call at all, even if it was an empty function.

    Regards,
    Elias
    lallous, Feb 25, 2010
    #15
  16. lallous

    lallous Guest

    On Feb 22, 12:42 am, Gregory Ewing <>
    wrote:
    > lallouswrote:
    > > If the base defines the method and it was empty, then my C++ code
    > > would still call the function. This is not optimal because I don't
    > > want to go from C++ to Python if the _derived_ class does not
    > > implement the cb.

    >
    > I would simply not implement the method at all in the base
    > class. Then the C++ code can do an attribute lookup for
    > the method, and if it's not found, do nothing.
    >
    > --
    > Greg



    That is what I currently do. But if I comment out the implementations
    (empty ones) then the documentation generation tool will not document
    the callbacks.
    lallous, Feb 25, 2010
    #16
  17. lallous wrote:
    > I still prefer not to call at all, even if it was an empty function.
    >
    > Regards,
    > Elias
    >


    Is there any way we could convince you that there is no point caring
    about this ? Even if you were trying to optimize speed, it would still
    require proof that an empty function is part of the problem.
    It sounds like someone stating "I prefer to write difficult-to-read
    code, because in 1978, code size used to matter".

    JM
    Jean-Michel Pichavant, Feb 25, 2010
    #17
  18. lallous

    Aahz Guest

    In article <>,
    lallous <> wrote:
    >On Feb 22, 12:42=A0am, Gregory Ewing <>
    >wrote:
    >> lallouswrote:
    >>>
    >>> If the base defines the method and it was empty, then my C++ code
    >>> would still call the function. This is not optimal because I don't
    >>> want to go from C++ to Python if the _derived_ class does not
    >>> implement the cb.

    >>
    >> I would simply not implement the method at all in the base
    >> class. Then the C++ code can do an attribute lookup for
    >> the method, and if it's not found, do nothing.

    >
    >That is what I currently do. But if I comment out the implementations
    >(empty ones) then the documentation generation tool will not document
    >the callbacks.


    Maybe deleting the method after the class would work.
    --
    Aahz () <*> http://www.pythoncraft.com/

    "Many customs in this life persist because they ease friction and promote
    productivity as a result of universal agreement, and whether they are
    precisely the optimal choices is much less important." --Henry Spencer
    Aahz, Feb 25, 2010
    #18
    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. IK
    Replies:
    2
    Views:
    605
    hemraj
    Jul 23, 2004
  2. Todd Aspeotis
    Replies:
    3
    Views:
    458
    Kanenas
    May 30, 2005
  3. John Goche
    Replies:
    10
    Views:
    735
    Marcus Kwok
    Dec 8, 2006
  4. Replies:
    7
    Views:
    586
    James Kanze
    May 2, 2007
  5. a
    Replies:
    7
    Views:
    361
    dasjotre
    Jun 28, 2007
Loading...

Share This Page