views:

30

answers:

1

I'm finding it useful to create "method factory functions" that wrap a parametrized object attribute in some logic.

For example:

"""Fishing for answers.

>>> one().number_fisher()
'one fish'
>>> one().colour_fisher()
'red fish'
>>> two().number_fisher()
'two fish'
>>> two().colour_fisher()
'blue fish'
"""


class one(object):
    def number(self):
        return 'one'
    def colour(self):
        return 'red'
    def _make_fisher(sea):
        def fisher(self):
            return '{0} fish'.format(getattr(self, sea)())
        return fisher
    number_fisher = _make_fisher('number')
    colour_fisher = _make_fisher('colour')

class two(one):
    def number(self):
        return 'two'
    def colour(self):
        return 'blue'

Is it necessary to pass the attribute to make_fisher as a string, or is there a better way to do this?

If I pass and use an actual attribute, this will break polymorphism, since instances of two will still be using that same reference to the attribute object.

I.E.

diff --git a/fishery.py b/fishery.py
index 840e85d..b98cf72 100644
--- a/fishery.py
+++ b/fishery.py
@@ -4,10 +4,12 @@
 'one fish'
 >>> one().colour_fisher()
 'red fish'
+
+This version does not implement polymorphism, and so this happens:
 >>> two().number_fisher()
-'two fish'
+'one fish'
 >>> two().colour_fisher()
-'blue fish'
+'red fish'
 """


@@ -18,10 +20,10 @@ class one(object):
         return 'red'
     def _make_fisher(sea):
         def fisher(self):
-            return '{0} fish'.format(getattr(self, sea)())
+            return '{0} fish'.format(sea(self))
         return fisher
-    number_fisher = _make_fisher('number')
-    colour_fisher = _make_fisher('colour')
+    number_fisher = _make_fisher(number)
+    colour_fisher = _make_fisher(colour)

 class two(one):
     def number(self):

It seems a bit weak to have to use a string to reference the attribute, but I'm not seeing another way to do this. Is there?

+2  A: 

"One more level of indirection" (sometimes proposed as programming's magic panacea;-) -- just like for typical decorators like property. E.g.:

def makefisher(fun):
  def fisher(self):
    return '{0} fish'.format(fun(self))
  return fisher

class one(object):
  def number(self): return self._number()
  def _number(self): return 'one'
  number_fisher = makefisher(number)

class two(one):
  def _number(self): return 'two'

Basically, the function you wrap is the "organizing function" in a peculiarly simple variant of the Template Method DP, and the one you override is the "hook function" in that same DP. Or at least, that's one way to look at it, the other being the "extra level of indirection" one I started out with;-).

Alex Martelli