FAQ
Hello everybody,

I am building a code for surface meshes (triangulations for instance).
I need to implement Body objects (bodies can be points, segments,
triangles and so on), then a Mesh will be a collection of bodies,
together with their neighbourhood relations.
I also need OrientedBody objects, which consist in a body
together with a plus or minus sign to describe its orientation.
So, basically an OrientedBody is just a Body with an
integer label stuck on it.

I implemented it in a very crude manner:
------------------------------------------
class Body:
[...]
class OrientedBody:
def __init__ (self,b,orient=1):
# b is an already existing body
assert isinstance(b,Body)
self.base = b
self.orientation = orient
-------------------------------------------

My question is: can it be done using inheritance ?
I recall that I need three distinct objects:
the basic (non-oriented) body, the same body with positive
orientation and the same body with negative orientation.

Thank you. Cristian Barbarosie
http://cmaf.fc.ul.pt/~barbaros

Search Discussions

  • Bruno Desthuilliers at Apr 23, 2008 at 9:48 am

    barbaros a ?crit :
    Hello everybody,

    I am building a code for surface meshes (triangulations for instance).
    I need to implement Body objects (bodies can be points, segments,
    triangles and so on), then a Mesh will be a collection of bodies,
    together with their neighbourhood relations.
    I also need OrientedBody objects, which consist in a body
    together with a plus or minus sign to describe its orientation.
    So, basically an OrientedBody is just a Body with an
    integer label stuck on it.

    I implemented it in a very crude manner:
    ------------------------------------------
    class Body:
    Unless you need compatibility with pre-2.2 Python versions, use a
    new-style class instead:

    class Body(object):
    [...]
    class OrientedBody:
    def __init__ (self,b,orient=1):
    # b is an already existing body
    assert isinstance(b,Body)
    self.base = b
    self.orientation = orient
    -------------------------------------------

    My question is: can it be done using inheritance ?
    Technically, yes:

    class OrientedBody(Body):
    def __init__(self, orient=1):
    Body.__init__(self)
    self.orient = 1

    Now if it's the right thing to do is another question... Another
    possible design could be to have an orient attribute on the Body class
    itself, with 0 => non-oriented (default), 1 => 'plus', -1 => 'minus' (or
    any other convention, depending on how you use this attribute).
  • Barbaros at Apr 23, 2008 at 3:44 pm

    On Apr 23, 10:48 am, Bruno Desthuilliers <bruno. 42.desthuilli... at websiteburo.invalid> wrote:

    My question is: can it be done using inheritance ?
    Technically, yes:

    class OrientedBody(Body):
    def __init__(self, orient=1):
    Body.__init__(self)
    self.orient = 1

    Now if it's the right thing to do is another question...
    If I understand correctly, in the above implementation I cannot
    define firstly a (non-oriented) body, and then build, on top of it,
    two bodies with opposite orientations. The point is, I want
    both oriented bodies to share the same base Body object.
    Another
    possible design could be to have an orient attribute on the Body class
    itself, with 0 => non-oriented (default), 1 => 'plus', -1 => 'minus' (or
    any other convention, depending on how you use this attribute).
    The above comments apply here, too.

    In what concerns other suggestion, about Python language,
    I shall do my best to understand them and apply them.

    Thank you. Cristian Barbarosie
    http://cmaf.fc.ul.pt/~barbaros
  • Paul McGuire at Apr 23, 2008 at 4:41 pm

    On Apr 23, 10:44?am, barbaros wrote:
    If I understand correctly, in the above implementation I cannot
    define firstly a (non-oriented) body, and then build, on top of it,
    two bodies with opposite orientations. The point is, I want
    both oriented bodies to share the same base Body object.
    What you are describing is composition+delegation, not inheritance,
    and it would be the same answer in Java, C++, or OO-langue-du-jour.
    Python makes delegation to the contained object easier than the others
    (except maybe for OOldj) - no need to implement all the methods of the
    contained object in the container, that just delegate the call to the
    contained; use __getattr__ to get attributes of the contained object
    that are not defined on the container (methods are attributes, too) as
    shown below. No inheritance in this example at all.

    -- Paul


    class BodyWithoutOrientation(object):
    def __init__(self,color):
    self.color = color
    def show_orientation(self):
    print "I don't lean one way or the other"

    class OrientedBody(object):
    def __init__(self,base,orientation):
    self.base_body = base
    self.orientation = orientation
    def show_orientation(self):
    print "I lean to the " + \
    {
    OrientedBody.RIGHT : "right",
    OrientedBody.LEFT : "left",
    }[self.orientation],
    print "and my color is " + self.color
    # delegate any other attr lookups to the base_body object
    def __getattr__(self,attr):
    return getattr(self.base_body,attr)
    OrientedBody.RIGHT = object()
    OrientedBody.LEFT = object()

    class LeftRightBody(object):
    def __init__(self,b):
    self.common_base = b
    self.left = OrientedBody(b,OrientedBody.LEFT)
    self.right = OrientedBody(b,OrientedBody.RIGHT)
    def show_orientation(self):
    print "I do both of these:"
    print "- ",
    self.left.show_orientation()
    print "- ",
    self.right.show_orientation()

    base = BodyWithoutOrientation("purple")
    lr = LeftRightBody(base)

    base.show_orientation()
    lr.show_orientation()

    Prints:
    I don't lean one way or the other
    I do both of these:
    - I lean to the left and my color is purple
    - I lean to the right and my color is purple
  • Bruno Desthuilliers at Apr 24, 2008 at 11:28 am

    barbaros a ?crit :
    On Apr 23, 10:48 am, Bruno Desthuilliers <bruno.
    42.desthuilli... at websiteburo.invalid> wrote:
    My question is: can it be done using inheritance ?
    Technically, yes:

    class OrientedBody(Body):
    def __init__(self, orient=1):
    Body.__init__(self)
    self.orient = 1

    Now if it's the right thing to do is another question...
    If I understand correctly, in the above implementation I cannot
    define firstly a (non-oriented) body, and then build, on top of it,
    two bodies with opposite orientations. The point is, I want
    both oriented bodies to share the same base Body object.
    Then it's not a job for inheritence, but for composition/delegation -
    Sorry but I didn't get your specs quite right :-/

    Now the good news is that Python makes composition/delegation close to
    a no-brainer:

    class Body(object):
    # definitions here

    class OrientedBody(object):
    # notice that we *dont* inherit from Body
    def __init__(self, body, orient):
    self._body = body
    self.orient = orient

    def __getattr__(self, name):
    try:
    return getattr(self._body, name)
    except AttributeError:
    raise AttributeError(
    "OrientedBody object has no attribute %s" % name
    )


    def __setattr__(self, name, val):
    # this one is a bit more tricky, since you have
    # to know which names are (or should be) bound to
    # which object. I use a Q&D approach here - which will break
    # on computed attributes (properties etc) in the Body class -
    # but you can also define a class attribute in either Body
    # or OrientedBody to explicitly declare what name goes where
    if name in self._body.__dict__:
    setattr(self._body, name, val)
    else:
    object.__setattr__(self, name, value)
  • Barbaros at Apr 24, 2008 at 1:45 pm
    Thanks to Paul McGuire and Bruno Desthuilliers for their comprehensive
    answers. This is exactly what I was looking for, except I did not know
    the correct name (composition/delegation). Now all I have to do is to
    study the supplied code, understand it and adapt it to my problem.

    Thank you very much. Cristian Barbarosie
    http://cmaf.ptmat.fc.ul.pt/~barbaros
  • Andrew Lee at Apr 23, 2008 at 10:49 am

    barbaros wrote:
    Hello everybody,

    I am building a code for surface meshes (triangulations for instance).
    I need to implement Body objects (bodies can be points, segments,
    triangles and so on), then a Mesh will be a collection of bodies,
    together with their neighbourhood relations.
    I also need OrientedBody objects, which consist in a body
    together with a plus or minus sign to describe its orientation.
    So, basically an OrientedBody is just a Body with an
    integer label stuck on it.

    I implemented it in a very crude manner:
    ------------------------------------------
    class Body:
    [...]
    class OrientedBody:
    def __init__ (self,b,orient=1):
    # b is an already existing body
    assert isinstance(b,Body)
    self.base = b
    self.orientation = orient
    -------------------------------------------
    class Body(object) :
    ...

    class OrientedBody (Body):
    def __init__(self, orientation = 1) :
    Body.__init__(self)
    self.orientation = orientation



    as noted


    But, also.

    as a rule of thumb .. if you are using "isinstance" in a class to
    determine what class a parameter is ... you have broken the OO contract.
    Remember, every class ought to have a well defined internal state and
    a well defined interface to its state.

    If I write --

    class foo (object):
    def __init__ :
    pass

    def some_func (self, val) :
    if isinstance (val, "bar") :
    ....

    Then I am either doing something very wrong or very clever (either can
    get me in trouble)

    In Python it is preferred that I write two functions some_func_a and
    some_func_b

    e.g.

    def some_func_a (self, val = None, class = bar) :
    assert(isinstance (class, "bar"), True)
    ....

    def some_func_b (self, val = None, class = baz) :
    assert (isinstance (class, "baz"), True)

    C++ and Java try to enforce the OO contract by making data and methods
    private, protected or public. Which helps -- but leads to some
    confusion (what is protected inheritance in C++????) Python exposes all
    of its classes internals to everyone -- but that doesn't mean you should
    touch them!!

    As Larry Wall once wrote, "There is a difference between, 'do not enter
    my living room because I asked you not to' and 'do not enter my living
    room because I have a shotgun'"

    Python adopts the 'do not touch my private parts because I asked you not
    to' idiom. (In C++, only friends can touch your privates ... ;-)

    So -- be mindful that checking the class of well defined parameters at
    anytime is breaking the contract -- you may need to do it -- but it is
    more likely that you aren't adhering to good OOD.

    Does that make any sense?

    Seriously -- I have not had any coffee yet and I am still new at Python.


    -- Andrew



    My question is: can it be done using inheritance ?
    I recall that I need three distinct objects:
    the basic (non-oriented) body, the same body with positive
    orientation and the same body with negative orientation.

    Thank you. Cristian Barbarosie
    http://cmaf.fc.ul.pt/~barbaros
  • Bruno Desthuilliers at Apr 23, 2008 at 12:45 pm
    Andrew Lee a ?crit :
    (snip)
    as a rule of thumb .. if you are using "isinstance" in a class to
    determine what class a parameter is ... you have broken the OO contract. Nope.
    Remember, every class ought to have a well defined internal state and a
    well defined interface to its state.
    I don't see how the part about the internal state relates to the problem
    here.

    If I write --

    class foo (object):
    def __init__ :
    pass

    def some_func (self, val) :
    if isinstance (val, "bar") :
    ....

    Then I am either doing something very wrong
    If you do so in a desperate attempt to emulate static typing in Python,
    then yes, you're doing something very wrong. Else:
    or very clever
    Not necessarily. Given Python's dynamic typing, there's no builtin
    OneObviousWay(tm) way to dispatch on different functions based on
    argument's type - something often done in statically typed OOPLs using
    method overridding (ie: different methods with same name but different
    signatures). Doing a manual dispatch based on argument's type, while not
    good OO style, is sometimes the simplest working solution, and a good
    enough one for the problem at hand. Having different methods for
    different arg types has the drawback that you don't have one single
    generic function/method that you can use as a callback.

    Having a real multidispatch (or rule-based dispatch etc) system either
    builtin or in the stdlib would indeed be much cleaner. Until then, there
    are a couple third-part packages solving this problem, but it can be
    overkill for simple problems (and add unneeded/unwanted dependencies).

    my 2 cents.

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
grouppython-list @
categoriespython
postedApr 23, '08 at 8:54a
activeApr 24, '08 at 1:45p
posts8
users4
websitepython.org

People

Translate

site design / logo © 2022 Grokbase