strategy pattern and non-public virtual functions

P

pythoncurious

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?
 
D

Duncan Booth

wrote:
The users of the derived classes are unable to bypass this base class
function.

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

=?ISO-8859-1?Q?=22Martin_v=2E_L=F6wis=22?=

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?

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

2. Should I be doing this at all? Any thoughts?

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

Maric Michaud

Le Lundi 05 Juin 2006 16:07, (e-mail address removed) a écrit :
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();
}

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(object) :
def __call__(self, *sa) : raise NotImplementedError('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(self, strat) :
if not isinstance(strat, strategyBase) :
raise ValueError("strat must be of type strategyBase")
self.__strat = strat

strategy = property(fget=lambda s : s.__strat, fset=__setStrategy)

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
 
J

John J. Lee

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

http://www.aleax.it/Python/os03_template_dp.pdf


John
 
B

Bruno Desthuilliers

(e-mail address removed) a écrit :
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();
}

<ot>
This is eventually the template method pattern, but certainly not the
strategy pattern.
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.

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

(snip - cf other posts in this thread)
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?

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

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,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top