strategy pattern and non-public virtual functions

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • pythoncurious@gmail.com

    #1

    strategy pattern and non-public virtual functions

    Hi python experts

    In C++ I can do something like this:
    class Base {
    public:
    void f() { this->f_(); }
    private:
    virtual void f_() = 0;
    };

    class Derived : public Base {
    private:
    void f_() { // Do something }
    };

    int main() {
    Derived d;
    d.f();
    }

    The point of this is that the a number of classes will inherit from
    Base and only implement a private member function that only will be
    accessed from the base class public 'f' function.
    The Base::f() can then perform validation of input/return values, add
    logging and things like that.
    The users of the derived classes are unable to bypass this base class
    function.

    I've been wanting to do the same thing in python, to make sure that
    there is no confusion about what function to call.

    Just translating this code to python won't work, due to the name
    mangling of private functions:
    class B(object):
    def f(self):
    self.__f()

    class D(B):
    def __f(self):
    pass

    d = D()
    d.f()

    Traceback (most recent call last):
    File "<stdin>", line 1, in ?
    File "<stdin>", line 3, in f
    AttributeError: 'D' object has no attribute '_B__f'

    So my questions are:
    1. Is there a "pythonic" way to do what I'm trying to do?
    2. Should I be doing this at all? Any thoughts?

  • Duncan Booth

    #2
    Re: strategy pattern and non-public virtual functions

    wrote:
    [color=blue]
    > The users of the derived classes are unable to bypass this base class
    > function.[/color]

    Just to be clear, the users of the derived C++ classes *are* able to bypass
    the base class function and call f_() directly, they just have to be
    prepared to twist the rules somewhat. I know: I've been in the situation
    where there was absolutely no other way to get the job done other than to
    call a private method in a class supplied in a library which I couldn't
    change.

    To do the same in Python you simply make a rule 'dont call f_ directly' and
    you get effectively the same thing: users can call f_ if they really want,
    but they are breaking the rules if they do. The difference in Python is
    that you don't have to go to such extremes to break the rules.

    The Pythonic way to do it:

    class B(object):
    def f(self):
    self._f()

    class D(B):
    def _f(self):
    pass

    d = D()
    d.f()

    Calling a method with a single leading underscore from outside the
    implementation of the class is generally accepted in Python to be 'breaking
    the rules' and therefore something only to be done by consenting adults in
    the full knowledge of the consquences of their actions.

    Comment

    • Martin v. Löwis

      #3
      Re: strategy pattern and non-public virtual functions

      pythoncurious@g mail.com wrote:[color=blue]
      > Just translating this code to python won't work, due to the name
      > mangling of private functions:
      > class B(object):
      > def f(self):
      > self.__f()
      >
      > class D(B):
      > def __f(self):
      > pass
      >
      > d = D()
      > d.f()
      >
      > So my questions are:
      > 1. Is there a "pythonic" way to do what I'm trying to do?[/color]

      Just use a single underscore, i.e. "_f" instead of "__f".

      [color=blue]
      > 2. Should I be doing this at all? Any thoughts?[/color]

      I can't spot the strategy pattern here; neither in the C++ code
      nor in the Python code. For this to be the strategy pattern,
      you should have two objects: the context, and the strategy
      object. So for example, you could have

      class Context:
      def f(self):
      return self.strategy.f ()

      class D:
      def f(self):
      pass

      Then, assigning to context.strateg y lets you change the
      strategy dynamically.

      It's not clear to what you are trying achieve with your
      pattern, so it is hard to tell whether you should do this
      at all. Most likely, the answer is "no".

      If you are really looking for the strategy pattern:
      be aware that people often use the strategy pattern
      as a work-around for functions not being first-class
      objects. In Python, they are, so you can often allow
      for arbitrary callables in the strategy pattern.

      Regards,
      Martin

      Comment

      • Maric Michaud

        #4
        Re: strategy pattern and non-public virtual functions

        Le Lundi 05 Juin 2006 16:07, pythoncurious@g mail.com a écrit :[color=blue]
        > class Base {
        >   public:
        >     void f() { this->f_(); }
        >   private:
        >     virtual void f_() = 0;
        > };
        >
        > class Derived : public Base {
        >   private:
        >     void f_() { // Do something }
        > };
        >
        > int main() {
        >     Derived d;
        >     d.f();
        > }[/color]

        This is just polymorphism, not strategy pattern, and I would expect f_ to be
        protected here not private.

        You want to ensure derived class will use a given method in the Base class,
        this could be done explicit with a good naming convention as Duncan said, but
        here is a strategy pattern to ensure a sanity check for example :

        class strategyBase(ob ject) :
        def __call__(self, *sa) : raise NotImplementedE rror('abstract class')

        class InputProcessor( object) :

        def sanitize(self, *a) :
        return a

        def f(self, *a) :
        sa = self.sanitize(* a)
        return self.strategy(* sa)

        def __setStrategy(s elf, strat) :
        if not isinstance(stra t, strategyBase) :
        raise ValueError("str at must be of type strategyBase")
        self.__strat = strat

        strategy = property(fget=l ambda s : s.__strat, fset=__setStrat egy)

        The main purpose of this is to define a common API for all Strategies, and
        this is really useful if you intend to manage many of them.

        --
        _____________

        Maric Michaud
        _____________

        Aristote - www.aristote.info
        3 place des tapis
        69004 Lyon
        Tel: +33 426 880 097

        Comment

        • John J. Lee

          #5
          Re: strategy pattern and non-public virtual functions

          pythoncurious@g mail.com writes:
          [color=blue]
          > Hi python experts
          >
          > In C++ I can do something like this:
          > class Base {
          > public:
          > void f() { this->f_(); }
          > private:
          > virtual void f_() = 0;
          > };
          >
          > class Derived : public Base {
          > private:
          > void f_() { // Do something }
          > };
          >
          > int main() {
          > Derived d;
          > d.f();
          > }[/color]
          [...]

          The others have already answered the Python question and pointed out
          this isn't really the Strategy Pattern.

          Still, these slides from Alex Martelli specifically on the Template
          Method DP in Python are probably very relevant to you:




          John

          Comment

          • Bruno Desthuilliers

            #6
            Re: strategy pattern and non-public virtual functions

            pythoncurious@g mail.com a écrit :[color=blue]
            > Hi python experts
            >
            > In C++ I can do something like this:
            > class Base {
            > public:
            > void f() { this->f_(); }
            > private:
            > virtual void f_() = 0;
            > };
            >
            > class Derived : public Base {
            > private:
            > void f_() { // Do something }
            > };
            >
            > int main() {
            > Derived d;
            > d.f();
            > }[/color]

            <ot>
            This is eventually the template method pattern, but certainly not the
            strategy pattern.
            </ot>

            [color=blue]
            > The point of this is that the a number of classes will inherit from
            > Base and only implement a private member function that only will be
            > accessed from the base class public 'f' function.
            > The Base::f() can then perform validation of input/return values, add
            > logging and things like that.[/color]

            This is usually done in Python with function decorators. But the
            implementer of the derived class

            (snip - cf other posts in this thread)
            [color=blue]
            > So my questions are:
            > 1. Is there a "pythonic" way to do what I'm trying to do?
            >
            > 2. Should I be doing this at all? Any thoughts?[/color]

            Doing what ? adding logging, validation etc, or using the template
            method pattern ?-)


            Comment

            Working...