FAQ
OO refactoring trial
====================
Following is a simple trial structure of a refactoring (top-down to OO)
learning exercise I'm doing. Whether you call it a Factory pattern, COR
pattern, or some hinze 57, I don't know what class to use till run time and
I'm trying to avoid a lengthy "if" sequence, the test sequence is important,
and to avoid code duplication I'll be using code objects in the "doit"
methods.

You've already given me many good ideas in previous threads and this is where
it got you :~) This works, but would you please tell me:
1) What you don't like about the approach
2) The implications of using this in a recursive approach (referenced from
but outside the recursive function) and if the decorators help with such.
3) Any other comments you might offer

Thank you,
Lee C


=========== ootest.py
============
class MF(object):
@staticmethod
def findit(t):
for it in MF.__subclasses__():
if it.testit(t):
return it().doit

class A(MF):
@staticmethod
def testit(tv):
if tv == 'relates to A':
return True
else:
return False

def doit(self):
print '# did A #'

class B(MF):
@staticmethod
def testit(tv):
if tv == 'relates to B':
return True
else:
return False

def doit(self):
print '# did B #'

mydoit = MF.findit('relates to B')
mydoit()

mydoit = MF.findit('relates to A')
mydoit()

======== Test run ==============
Python 2.4.1 (#2, Mar 31 2005, 00:05:10)
[GCC 3.3 20030304 (Apple Computer, Inc. build 1666)]
Type "help", "copyright", "credits" or "license" for more information.
import ootest
# did B #
# did A #
>>>

Search Discussions

  • Peter Otten at Jun 28, 2005 at 6:22 am

    Chinook wrote:

    3) Any other comments you might offer
    if?tv?==?'relates?to?A':
    return?True
    else:
    return?False
    Make that

    return tv == 'relates to A'

    lest your zen master hit you.

    Peter
  • Chinook at Jun 28, 2005 at 6:44 am
    On Tue, 28 Jun 2005 02:22:13 -0400, Peter Otten wrote
    (in article <d9qq9a$qhj$04$1 at news.t-online.com>):
    Chinook wrote:
    3) Any other comments you might offer
    if?tv?==?'relates?to?A':
    return?True
    else:
    return?False
    Make that

    return tv == 'relates to A'

    lest your zen master hit you.

    Peter

    Thank you Peter,

    So wrapped up in the OO I overlooked the simpler aspects.

    Lee C
  • Chinook at Jun 28, 2005 at 11:31 am
    [[ This message was both posted and mailed: see
    the 'To' and 'Newsgroups' headers for details. ]]

    Clarifications:
    1) Truth test simplified after a %) by Peter Otten - thanks. In reality the
    "testit" methods will all be quite different as you might imagine (as will
    the "doit" methods).

    2) A final subclass will always return True, so there will always be a valid
    factory (?) result.

    ====================
    Following is a simple trial structure of a refactoring (top-down to OO)
    learning exercise I'm doing. Whether you call it a Factory pattern, COR
    pattern, or some hinze 57, I don't know what class to use till run time and
    I'm trying to avoid a lengthy "if" sequence, the test sequence is important,
    and to avoid code duplication I'll be using code objects in the "doit"
    methods.

    You've already given me many good ideas in previous threads and this is where
    it got you :~) This works, but would you please tell me:
    1) What you don't like about the approach and/or how I might improve it
    2) The implications of using this in a recursive approach (referenced from
    but outside the recursive function).
    3) Any other comments you might offer

    Thank you,
    Lee C


    =========== ootest.py
    ============
    class MF(object):
    @staticmethod
    def findit(t):
    for it in MF.__subclasses__():
    if it.testit(t):
    return it().doit

    class A(MF):
    @staticmethod
    def testit(tv):
    return (tv == 'relates to A')

    def doit(self):
    print '# did A #'

    class B(MF):
    @staticmethod
    def testit(tv):
    return (tv == 'relates to B')

    def doit(self):
    print '# did B #'

    mydoit = MF.findit('relates to B')
    mydoit()

    mydoit = MF.findit('relates to A')
    mydoit()

    ======== Test run ==============
    Python 2.4.1 (#2, Mar 31 2005, 00:05:10) [GCC 3.3 20030304 (Apple Computer,
    Inc. build 1666)] Type "help", "copyright", "credits" or "license" for more
    information.
    import ootest
    # did B #
    # did A #
    >>>
  • Chinook at Jun 28, 2005 at 11:49 am
    On Tue, 28 Jun 2005 07:31:43 -0400, Chinook wrote
    (in article [[ This message was both posted and mailed: see
    the 'To' and 'Newsgroups' headers for details. ]]
    Sorry for the duplication. I'm trying Hogwasher on OS X and it seems I
    better look around some more.
  • Chinook at Jun 28, 2005 at 11:39 am
    Clarifications:
    1) Truth test simplified after a %) by Peter Otten - thanks. In reality the
    "testit" methods will all be quite different as you might imagine (as will
    the "doit" methods).

    2) A final subclass will always return True, so there will always be a valid
    result.

    ====================
    Following is a simple trial structure of a refactoring (top-down to OO)
    learning exercise I'm doing. Whether you call it a Factory pattern, COR
    pattern, or some hinze 57, I don't know what class to use till run time and
    I'm trying to avoid a lengthy "if" sequence, the test sequence is important,
    and to avoid code duplication I'll be using code objects in the "doit"
    methods.

    You've already given me many good ideas in previous threads and this is where
    it got you :~) This works, but would you please tell me:
    1) What you don't like about the approach and/or how it might be improved
    2) The implications of using this in a recursive approach (referenced from
    but outside the recursive function)
    3) Any other comments you might offer

    Thank you, Lee C


    =========== ootest.py
    ============
    class MF(object):
    @staticmethod
    def findit(t):
    for it in MF.__subclasses__():
    if it.testit(t):
    return it().doit

    class A(MF):
    @staticmethod
    def testit(tv):
    return (tv == 'relates to A')

    def doit(self):
    print '# did A #'

    class B(MF):
    @staticmethod
    def testit(tv):
    return (tv == 'relates to B')

    def doit(self):
    print '# did B #'

    mydoit = MF.findit('relates to B')
    mydoit()

    mydoit = MF.findit('relates to A')
    mydoit()

    ======== Test run ==============
    Python 2.4.1 (#2, Mar 31 2005, 00:05:10) [GCC 3.3 20030304 (Apple Computer,
    Inc. build 1666)] Type "help", "copyright", "credits" or "license" for more
    information.
    import ootest
    # did B #
    # did A #
    >>>
  • Paul McGuire at Jun 28, 2005 at 2:22 pm
    Lee,

    Interesting idea, but I think the technique of "inherit from MF to
    automatically add class to the test chain" is a gimmick that wont
    scale.

    Here are some things to consider:

    - I'm not keen on the coupling of forcing your A,B,etc. classes to
    inherit from MF. Especially in a duck-typing language like Python, it
    adds no value, the subclasses receive no default behavior from their
    superclass, and I'm not keen on using the inheritance hierarchy to
    register test classes. What is the order of classes returned from
    __subclasses__()? Will you always want this order? Will you always
    want all subclasses? If this is part of a library that others will
    use, you may not be able to anticipate what subclasses someone else may
    stick on to your MF class.

    - The list of items should be dynamic in the calling code, not built
    statically by your class structure. There's no way to anticipate what
    various sequences you will want to evaluate.

    - Let's call the MF class "MultiEvaluator". There are several ways to
    evaluate among several alternatives:
    . short-circuit, take first match
    . best-fit, evaluate all and take best score (assuming the testit
    routines return a double or int, as opposed to a bool)

    For short-circuiting, say you have a case that will match A, you want
    to avoid any processing related to B,C,etc. as possible at test/do
    runtime. You *might* be able to do extra work at list construction
    time. Consider these two alternative designs:

    class MultiEvaluator(object):
    def __init__(self, *classes):
    self.testClasses = classes[:]

    def findit(self, *args):
    for C in self.testClasses:
    testobj = C()
    if testobj.testit(args[0]):
    testobj.doit()

    MultiEvaluator(A,B).findit("relates to A")

    vs.

    class MultiEvaluator(object):
    def __init__(self, *classes):
    self.testClasses = [ C() for C in classes ]

    def findit(self, *args):
    for testobj in self.testClasses:
    if testobj.testit(args[0]):
    testobj.doit()

    MultiEvaluator(A,B).findit("relates to B")

    In the first case, no B class is ever constructed, so if test object
    construction is expensive, you might go this route. In the second, A()
    and B() are built ahead of time, so the run-time processing is the
    fastest - you might choose this if the construction time can be done up
    front. The second option may cause problems for multi-threadedness or
    re-entrancy with a shared MultiEvaluator, though.

    This style of constructing the MultiEvaluator also makes more explicit
    (which I hear is better than implicit) what classes you are testing
    when creating your MultiEvaluator.

    - To make your testit() and doit() code more flexible and more
    powerful, I'd pass (*args) to each, as in:

    class MultiEvaluator(object):
    def __init__(self, *classes):
    self.testClasses = classes[:]

    def findit(self, *args):
    for C in self.testClasses:
    testobj = C()
    if testobj.testit(args):
    testobj.doit(args)

    - In the interests of flogging OO-ness, you could make MultiEvaluator
    into a function object, by changing "findit" to "__call__". Then your
    invocation of it would change from:

    getObj = MultiEvaluator(A,B)
    getObj.findit("relates to B")

    to:

    getObj = MultiEvaluator(A,B)
    getObj("relates to B")

    Although some might claim this is *less* explicit. The purpose of this
    is that you could then pass getObj to functional routines like map
    (although you could also pass getObj.findit).



    Those are my comments off the top of my head. Let us know what you
    come up with.

    -- Paul
  • Chinook at Jun 28, 2005 at 5:19 pm
    On Tue, 28 Jun 2005 10:22:59 -0400, Paul McGuire wrote
    (in article <1119968579.049502.68280 at g43g2000cwa.googlegroups.com>):
    Lee,

    Interesting idea, but I think the technique of "inherit from MF to
    automatically add class to the test chain" is a gimmick that wont
    scale.

    Here are some things to consider:

    - I'm not keen on the coupling of forcing your A,B,etc. classes to
    inherit from MF. Especially in a duck-typing language like Python, it
    adds no value, the subclasses receive no default behavior from their
    superclass, and I'm not keen on using the inheritance hierarchy to
    register test classes. What is the order of classes returned from
    __subclasses__()? Will you always want this order? Will you always
    want all subclasses? If this is part of a library that others will
    use, you may not be able to anticipate what subclasses someone else may
    stick on to your MF class.
    Even though this is an exercise, it is a learning exercise and your points
    are taken as pertinent considerations in "real-world" adaptation.

    So basically I'm coming from a if:elif:...else: test sequence where the order
    of the tests is critical (could be multiple hits and the first should be
    taken). My first trial was just to move the "if" sequence to a factory
    method. My second trial was to initially create an ordered list of classes
    to be tested as in:
    class A(object):
    ... def foo(self):
    ... print "I'm A.foo"
    ...
    class B(object):
    ... def foo(self):
    ... print "I'm B.foo"
    ...
    co = [A(), B()]
    co[1].foo()
    I'm B.foo
    >>>

    My third trial is what you are responding to. So in the "real-world" I could
    only suggest how someone else might add a test, but just as in the top-down
    "if" sequence I could impose no discipline. Even adding a weighting/priority
    to test cases (and going through all) is a halfway measure (though possibly a
    more explicit one). I think that the consideration of how a test case might
    be added in the future is very important - having dug my way through many
    other programs.

    BTW: Is duck-typing a variation on duct-taping?
    - The list of items should be dynamic in the calling code, not built
    statically by your class structure. There's no way to anticipate what
    various sequences you will want to evaluate.
    I was also playing with another exercise involving dynamic test cases where I
    thought the ordered list (second trial) would be a potential approach?
    - Let's call the MF class "MultiEvaluator". There are several ways to
    evaluate among several alternatives:
    . short-circuit, take first match
    what I was shooting for in this exercise
    . best-fit, evaluate all and take best score (assuming the testit
    routines return a double or int, as opposed to a bool)
    like my weighted/priority thought?
    For short-circuiting, say you have a case that will match A, you want
    to avoid any processing related to B,C,etc. as possible at test/do
    runtime. You *might* be able to do extra work at list construction
    time. Consider these two alternative designs:

    class MultiEvaluator(object):
    def __init__(self, *classes):
    self.testClasses = classes[:]

    def findit(self, *args):
    for C in self.testClasses:
    testobj = C()
    if testobj.testit(args[0]):
    testobj.doit()

    MultiEvaluator(A,B).findit("relates to A")
    my only drawback on such would be ME(A,B,...Z).findit(test_data)
    Explicit but cumbersome maybe, though no where near as cumbersome as a
    lengthy "if" sequence.
    vs.

    class MultiEvaluator(object):
    def __init__(self, *classes):
    self.testClasses = [ C() for C in classes ]

    def findit(self, *args):
    for testobj in self.testClasses:
    if testobj.testit(args[0]):
    testobj.doit()

    MultiEvaluator(A,B).findit("relates to B")

    In the first case, no B class is ever constructed, so if test object
    construction is expensive, you might go this route. In the second, A()
    and B() are built ahead of time, so the run-time processing is the
    fastest - you might choose this if the construction time can be done up
    front. The second option may cause problems for multi-threadedness or
    re-entrancy with a shared MultiEvaluator, though.

    This style of constructing the MultiEvaluator also makes more explicit
    (which I hear is better than implicit) what classes you are testing
    when creating your MultiEvaluator.

    - To make your testit() and doit() code more flexible and more
    powerful, I'd pass (*args) to each, as in:
    The testit() methods do in the full-fledged exercise. The doit() methods
    return code objects (but I'm rethinking that).
    class MultiEvaluator(object):
    def __init__(self, *classes):
    self.testClasses = classes[:]

    def findit(self, *args):
    for C in self.testClasses:
    testobj = C()
    if testobj.testit(args):
    testobj.doit(args)
    As in my ordered list approach (and what I thought my "cleverly" generated
    list would also do before giving it more thought), the idea in this exercise
    is to have one list (created once) that all levels of recursion would use.

    Your forcing me to use my head :~)
    - In the interests of flogging OO-ness, you could make MultiEvaluator
    into a function object, by changing "findit" to "__call__". Then your
    invocation of it would change from:

    getObj = MultiEvaluator(A,B)
    getObj.findit("relates to B")

    to:

    getObj = MultiEvaluator(A,B)
    getObj("relates to B")

    Although some might claim this is *less* explicit. The purpose of this
    is that you could then pass getObj to functional routines like map
    (although you could also pass getObj.findit).
    Good point, but my objective is an OO learning exercise. My mind isn't as
    flexible as it was back in the 60s :~) so it takes more effort to get a
    handle on something new (to me).

    Those are my comments off the top of my head. Let us know what you
    come up with.

    -- Paul
    Thank you very much for taking the time to consider and respond,

    Lee C
  • Chinook at Jun 29, 2005 at 1:02 am
    Never mind.
    BTW: Is duck-typing a variation on duct-taping?
    http://www.rubygarden.org/ruby?DuckTyping

    http://en.wikipedia.org/wiki/Duck_typing


    Lee C
  • Chinook at Jun 29, 2005 at 2:36 am
    Paul,

    Going back over various material led to another question regarding your
    comments.
    - I'm not keen on the coupling of forcing your A,B,etc. classes to
    inherit from MF. Especially in a duck-typing language like Python, it
    adds no value, the subclasses receive no default behavior from their
    superclass, and I'm not keen on using the inheritance hierarchy to
    register test classes.
    The latter (__subclasses__() bit) I picked up on as a convenience (courtesy
    of a suggestion by STeVe) and I understand your point about more explicit
    ordering. However, the former seems to take issue with examples like:

    http://jamesthornton.com/eckel/TIPython/html/Sect08.htm

    or indirectly as a show stopper (using inheritance) as in:

    http://www.unc.edu/~mconway/mt_static/archives/odds_and_ends/

    which is more in line with your comments.

    Anything more to this than individual preferences? Might it not be more
    explicit at least? Anyone?

    Thanks,

    Lee C
  • Kamilche at Jun 29, 2005 at 3:23 am
    '''
    You might find this interesting. Note that the object creation in
    main() below could easily be read in from a text file instead,
    thus meeting your requirement of not knowing an item's class
    until runtime.

    Sample output:

    {'password': 'Your Password Here', 'type': 'A', 'logonid': 'Your
    Logonid Here'}
    # did A #
    {'ssn': 555555555, 'type': 'B'}
    # did B #
    {'type': 'BASE', 'address': '501 south street'}
    # did BASE #
    None
    '''

    def Create(type = 'BASE', **kwargs):
    if type not in _CLASSES:
    return None # Or return a default object
    obj = _CLASSES[type](type = type, **kwargs)
    return obj

    class BASE(object):
    def __init__(self, **kwargs):
    self.__dict__.update(kwargs)
    def __str__(self):
    return str(self.__dict__)
    def doit(self):
    print "# did BASE #"

    class A(BASE):
    def doit(self):
    print '# did A #'

    class B(BASE):
    def doit(self):
    print '# did B #'

    _CLASSES = {'BASE': BASE, 'A': A, 'B': B}

    def main():
    obj1 = Create(type = 'A', logonid = 'Your Logonid Here', password =
    'Your Password Here')
    print obj1
    obj1.doit()
    obj2 = Create(type = 'B', ssn = 555555555)
    print obj2
    obj2.doit()
    obj3 = Create(address = '501 south street')
    print obj3
    obj3.doit()
    obj4 = Create(type = 'Missing')
    print obj4

    main()
  • Chinook at Jun 29, 2005 at 4:30 am
    On Tue, 28 Jun 2005 23:23:43 -0400, Kamilche wrote
    (in article <1120015423.318185.95600 at g14g2000cwa.googlegroups.com>):
    '''
    You might find this interesting. Note that the object creation in
    main() below could easily be read in from a text file instead,
    thus meeting your requirement of not knowing an item's class
    until runtime.

    Sample output:

    {'password': 'Your Password Here', 'type': 'A', 'logonid': 'Your
    Logonid Here'}
    # did A #
    {'ssn': 555555555, 'type': 'B'}
    # did B #
    {'type': 'BASE', 'address': '501 south street'}
    # did BASE #
    None
    '''

    def Create(type = 'BASE', **kwargs):
    if type not in _CLASSES:
    return None # Or return a default object
    obj = _CLASSES[type](type = type, **kwargs)
    return obj

    class BASE(object):
    def __init__(self, **kwargs):
    self.__dict__.update(kwargs)
    def __str__(self):
    return str(self.__dict__)
    def doit(self):
    print "# did BASE #"

    class A(BASE):
    def doit(self):
    print '# did A #'

    class B(BASE):
    def doit(self):
    print '# did B #'

    _CLASSES = {'BASE': BASE, 'A': A, 'B': B}

    def main():
    obj1 = Create(type = 'A', logonid = 'Your Logonid Here', password =
    'Your Password Here')
    print obj1
    obj1.doit()
    obj2 = Create(type = 'B', ssn = 555555555)
    print obj2
    obj2.doit()
    obj3 = Create(address = '501 south street')
    print obj3
    obj3.doit()
    obj4 = Create(type = 'Missing')
    print obj4

    main()
    Kamilche,

    Yes it is interesting and explicit, thank you.

    What I was not clear enough about though, is that at runtime the class object
    creation depends on the information being processed. That is, the context
    and type of node in the recursed tree. That's why in my trial the potential
    classes all included a "testit" method and the order of testing is important.
    Beyond that the "doit" methods all have some varying duplicated expressions,
    so I was constructing their functionality with code objects. However, in
    going back over researched material after Paul's comments I noticed another
    technique that might be better in creating functionality and have to study it
    further.

    Thanks for the sample,

    Lee C
  • Paul McGuire at Jun 29, 2005 at 4:18 am
    Lee -

    Bruce Eckel's observation:

    "the above scaffolding of Obstacle, Player and GameElementFactory
    (which was translated from the Java version of this example) is
    unnecessary - it's only required for languages that have static
    type checking. As long as the concrete Python classes follow the form
    of the required classes, we don't need any base classes..."

    is consistent with my "duck-typing" comment that all that is needed of
    A,B,etc. is that they provide the necessary testit and doit methods in
    the proper form. He also goes on to say that, even if the base classes
    were empty, they still provide a useful handle for all of the derived
    classes, to indicate they are all common subtypes of "Shape" or
    whatever.

    I think you were referring to the "Poking Python with a Stick" entry in
    the second link. The inheritance of all taunts from Taunt allowed the
    author to put some overriding common-to-all-taunts behavior into the
    superclass, even if it was just a "sorry, not implemented" exception
    into the base Taunt class's tauntTheKnights() method. The idea was to
    provide a runtime exception if the needed method had not been
    overridden in the subclass. But it also provides a place to put any
    other common-to-all-taunts behavior, perhaps a common constructor, or
    other common helper methods. I think this is a good use of
    inheritance, when the base class actually adds some value to the
    architecture, even if it is just Bruce Eckel's empty placeholder base
    class. Note also that this author was doing patterns experimentation
    in both Python and Java. I envision him writing the factory's
    getInstance() method in Java, and having to declare its return value
    type. In this case Java really drives you to having all possible
    return values derive from a common base class, so that you can define
    the method as:

    Taunt getInstance(string tauntTypeTag) { ...

    which is a bit easier to deal with than just declaring that getInstance
    returns an object, and then having to cast it - in fact, if there were
    no common base type, it would be problematic to know just what to cast
    it to.

    But Python does not require this sort of type rigidity. In your code,
    the only requirement is that each class A,B,etc. have testit and doit
    methods - they have to walk and talk like ducks, they don't need to
    *be* ducks. My point in an earlier post was, I think many current
    design patterns were born out of the C++ and Java worlds, and may be
    overly restrictive for a comparable implementation in Python.

    One step you might take in the MultiEvaluator constructor is to
    validate the provided classes on input, so that you don't have to
    exhaustively test all A thru Z classes before finding out that you
    misspelled Z's doit method as "dooit". This goes one better than the
    abstract subclass's "you forgot to override me" method implementation.

    In sum, both of the links you sent used examples that had inheritance
    hierarchies where the base class provided some contribution and
    commonality among the derived classes. TauntArthur "is-a" Taunt,
    TauntGalahad "is-a" Taunt. It really does look like the Factory
    pattern should return objects that share a common base class. But in
    Python, that common base class can also be just "something that walks
    like a duck."

    -- Paul
  • Chinook at Jun 29, 2005 at 5:01 am
    On Wed, 29 Jun 2005 00:18:24 -0400, Paul McGuire wrote
    (in article <1120018704.586468.68720 at f14g2000cwb.googlegroups.com>):
    Lee -

    Bruce Eckel's observation:

    "the above scaffolding of Obstacle, Player and GameElementFactory
    (which was translated from the Java version of this example) is
    unnecessary - it's only required for languages that have static
    type checking. As long as the concrete Python classes follow the form
    of the required classes, we don't need any base classes..."

    is consistent with my "duck-typing" comment that all that is needed of
    A,B,etc. is that they provide the necessary testit and doit methods in
    the proper form. He also goes on to say that, even if the base classes
    were empty, they still provide a useful handle for all of the derived
    classes, to indicate they are all common subtypes of "Shape" or
    whatever.

    I think you were referring to the "Poking Python with a Stick" entry in
    the second link. The inheritance of all taunts from Taunt allowed the
    author to put some overriding common-to-all-taunts behavior into the
    superclass, even if it was just a "sorry, not implemented" exception
    into the base Taunt class's tauntTheKnights() method. The idea was to
    provide a runtime exception if the needed method had not been
    overridden in the subclass. But it also provides a place to put any
    other common-to-all-taunts behavior, perhaps a common constructor, or
    other common helper methods. I think this is a good use of
    inheritance, when the base class actually adds some value to the
    architecture, even if it is just Bruce Eckel's empty placeholder base
    class. Note also that this author was doing patterns experimentation
    in both Python and Java. I envision him writing the factory's
    getInstance() method in Java, and having to declare its return value
    type. In this case Java really drives you to having all possible
    return values derive from a common base class, so that you can define
    the method as:

    Taunt getInstance(string tauntTypeTag) { ...

    which is a bit easier to deal with than just declaring that getInstance
    returns an object, and then having to cast it - in fact, if there were
    no common base type, it would be problematic to know just what to cast
    it to.

    But Python does not require this sort of type rigidity. In your code,
    the only requirement is that each class A,B,etc. have testit and doit
    methods - they have to walk and talk like ducks, they don't need to
    *be* ducks. My point in an earlier post was, I think many current
    design patterns were born out of the C++ and Java worlds, and may be
    overly restrictive for a comparable implementation in Python.

    One step you might take in the MultiEvaluator constructor is to
    validate the provided classes on input, so that you don't have to
    exhaustively test all A thru Z classes before finding out that you
    misspelled Z's doit method as "dooit". This goes one better than the
    abstract subclass's "you forgot to override me" method implementation.

    In sum, both of the links you sent used examples that had inheritance
    hierarchies where the base class provided some contribution and
    commonality among the derived classes. TauntArthur "is-a" Taunt,
    TauntGalahad "is-a" Taunt. It really does look like the Factory
    pattern should return objects that share a common base class. But in
    Python, that common base class can also be just "something that walks
    like a duck."

    -- Paul
    Thank you for the clarification Paul. I missed the influence of C++ and Java
    origins because my past experience was more in the assembler realm with a
    little C and Pascal, and now I'm trying to get up to speed with Python, ObjC
    and the OO world. You've helped me look at what I'm reading in a better
    light.

    Thanks again,

    Lee C

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
grouppython-list @
categoriespython
postedJun 28, '05 at 6:14a
activeJun 29, '05 at 5:01a
posts14
users4
websitepython.org

People

Translate

site design / logo © 2022 Grokbase