By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
440,627 Members | 1,211 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 440,627 IT Pros & Developers. It's quick & easy.

Python Design Patterns - composition vs. inheritance

P: n/a
In learning about design patterns, I've seen discussion about using
inheritance when an object's relationship to another object is 'is-a'
and composition when the relationship is 'has-a'.

Since this is all new and I'm still learning, I was hoping someone can
give me some pointers on best practices on applying these ideas. If my
logic is incorrect on anything, please don't hesitate to tell me where
I'm wrong - I'm completely open to any help offered.

As a very simplified example, if I had two classes, Pet and Owner, it
seems that I would not have Pet inherit from Owner, since a pet 'has
an' owner, but not 'is an' owner. If this is correct, does my code
below reflect this? I passed the owner object into the pet object's
constructor - is this the right way to do it?

Also, I've seen talk that ideally you shouldn't have too many "dots"
in your method calls, instead using delegates to the methods and
attributes. Can anyone elaborate on this? Ideally, should I be writing
getattr() methods so I can do pet.address instead of
pet.owner.address? Should I be doing the same with owner's methods
like I did with get_foo()?

Thanks in advance to anyone who can share their experience with me -
it's very appreciated.

class Owner(object):
def __init__(self):
self.address = '123 Fake Street'

def get_foo(self):
return 'bar'

class Pet(object):
def __init__(self, owner):
self.owner = owner

def __getattr__(self, name):
if name == 'address':
return self.owner.address
else:
raise AttributeError, name

def get_foo(self):
return self.owner.get_foo()

owner = Owner()
pet = Pet(owner)
Nov 15 '07 #1
Share this Question
Share on Google+
7 Replies


P: n/a
As a very simplified example, if I had two classes, Pet and Owner, it
seems that I would not have Pet inherit from Owner, since a pet 'has
an' owner, but not 'is an' owner. If this is correct, does my code
below reflect this? I passed the owner object into the pet object's
constructor - is this the right way to do it?
Yes. Of course there are other ways, establishing the connection later,
and of course making the Owner know her pets. But your unidirectional,
ctor-passed implementation is sensible.
Also, I've seen talk that ideally you shouldn't have too many "dots"
in your method calls, instead using delegates to the methods and
attributes. Can anyone elaborate on this? Ideally, should I be writing
getattr() methods so I can do pet.address instead of
pet.owner.address? Should I be doing the same with owner's methods
like I did with get_foo()?
No, that's certainly not a good idea. And I'm under the impression you
misunderstood something there in the original lecture/explanation.

The reason is simple: by adding these methods, you essentially extend
Pet's knowledge as a class to what only its owner has to know. Which
makes no sense. Why should pets know about addresses? Or cars? Or
anything else that belongs to the owner only.

Of course there are just reasons to create such delegation methods - if
for example the property/method is of general interest to the Pet, but
implemented by means of the owner. But I've got difficulties even to
imagine such thing, at least in your actual example.

Diez
Nov 15 '07 #2

P: n/a
On Nov 15, 3:37 pm, "Diez B. Roggisch" <de...@nospam.web.dewrote:
Also, I've seen talk that ideally you shouldn't have too many "dots"
in your method calls, instead using delegates to the methods and
attributes. Can anyone elaborate on this? Ideally, should I be writing
getattr() methods so I can do pet.address instead of
pet.owner.address? Should I be doing the same with owner's methods
like I did with get_foo()?

No, that's certainly not a good idea. And I'm under the impression you
misunderstood something there in the original lecture/explanation.
Having read lots of "perspectives" on OO style, it wouldn't surprise
me if the OP understood the point perfectly.

I.e., there probably are people out there who suggest that when you
have something like this:

mypet.owner.get_attributes()

you should reverse-refactor it into something like this:

mypet.get_owner_attributes()
I would agree that the former is preferable, especially in cases like
this one where the classes aren't really closely related.
Carl Banks
Nov 15 '07 #3

P: n/a
On Nov 15, 2007 2:37 PM, Diez B. Roggisch <de***@nospam.web.dewrote:
>
As a very simplified example, if I had two classes, Pet and Owner, it
seems that I would not have Pet inherit from Owner, since a pet 'has
an' owner, but not 'is an' owner. If this is correct, does my code
below reflect this? I passed the owner object into the pet object's
constructor - is this the right way to do it?

Yes. Of course there are other ways, establishing the connection later,
and of course making the Owner know her pets. But your unidirectional,
ctor-passed implementation is sensible.
Also, I've seen talk that ideally you shouldn't have too many "dots"
in your method calls, instead using delegates to the methods and
attributes. Can anyone elaborate on this? Ideally, should I be writing
getattr() methods so I can do pet.address instead of
pet.owner.address? Should I be doing the same with owner's methods
like I did with get_foo()?

No, that's certainly not a good idea. And I'm under the impression you
misunderstood something there in the original lecture/explanation.

The reason is simple: by adding these methods, you essentially extend
Pet's knowledge as a class to what only its owner has to know. Which
makes no sense. Why should pets know about addresses? Or cars? Or
anything else that belongs to the owner only.

Of course there are just reasons to create such delegation methods - if
for example the property/method is of general interest to the Pet, but
implemented by means of the owner. But I've got difficulties even to
imagine such thing, at least in your actual example.
An example might be something like pet.has_foodbowl, which is
implemented as self.owner.has_foodbowl_for(self). If you've got pets
with more than one owner, it might be any(owner.has_foodbowl_for(self)
for owner in self.owners) - certainly a candidate for an easy accessor
in the Pet class.

This is more an example of API convenience than it is any sort of
general OO or type theory concept. Note that any time you do this sort
of reverse binding you're codifying assumptions about your object
model (by which I mean domain objects, rather than your inheritance
hierarchy) into your code.

I don't worry to much about is-a or has-a or any sort of strict class
hierarchy or type system. I view inheritance, in Python, as a way of
inheriting implementation and I do it when I want some other classes
implementation and not otherwise. In other languages (not C++ family,
but ML family) I think much more in terms of types and type systems,
but in Python I stay pragmatic and flexible.
Nov 15 '07 #4

P: n/a
On 2007-11-15, sn*******@gmail.com <sn*******@gmail.comwrote:
inheritance when an object's relationship to another object is 'is-a'
and composition when the relationship is 'has-a'.

Since this is all new and I'm still learning, I was hoping someone can
give me some pointers on best practices on applying these ideas. If my
logic is incorrect on anything, please don't hesitate to tell me where
I'm wrong - I'm completely open to any help offered.
>
As a very simplified example, if I had two classes, Pet and Owner, it
seems that I would not have Pet inherit from Owner, since a pet 'has
an' owner, but not 'is an' owner. If this is correct, does my code
below reflect this? I passed the owner object into the pet object's
constructor - is this the right way to do it?
This is indeed one way. One of the things you enforce in this way that there is
no Pet object without an owner.
Also, I've seen talk that ideally you shouldn't have too many "dots"
in your method calls, instead using delegates to the methods and
attributes. Can anyone elaborate on this? Ideally, should I be writing
As with most design stuff, they are right and they are also wrong. It's a
trade-off.

They are right in the sense that if you change the structure of your links, you
will break potentionally a lot of code. Imagine you have to ask a data base for
the owner rather than having a direct link. All "pet.owner" references will
need to be changed then. If you hide the connection inside your Pet, there is
only one place that needs to be changed.

They are wrong in the sense that it is not always appropiate for a Pet object
to perform such a function. By hiding "self.owner.address" inside Pet, you are
designing a smart pet that knows how to find the address of its owner.
Unfortunately, smarter also means more complex, and at some point you will
defeat the advantage of OO, namely spreading responsibilities, and having
several simple objects that work together to realize your application.

So there is a trade-off. There is no universal rule, it highly depends on your
application, your future plans, and the lifetime of the app (to name a few).
getattr() methods so I can do pet.address instead of
pet.owner.address? Should I be doing the same with owner's methods
like I did with get_foo()?
I'd say no.
One of the 'rules' (guide lines) of Python is "Be explicit rather than
implicit" [1]. You may save a few dots, on the other hand, you obfuscate how
the link is realized (that is "pet.address" doesn't say it uses owner to make
the connection, unlike "pet.owner.address").
In the long run, the latter may be more important.
In general, I think you shouldn't need advanced trickery like __getattr__() for
your design. If you do, your design is most likely wrong.

[1]: The Zen of Python: http://www.python.org/dev/peps/pep-0020/
Sincerely,
Albert
Nov 16 '07 #5

P: n/a
On 2007-11-16, Dennis Lee Bieber <wl*****@ix.netcom.comwrote:
On Thu, 15 Nov 2007 12:28:28 -0800 (PST), "sn*******@gmail.com"
<sn*******@gmail.comdeclaimed the following in comp.lang.python:
>>
As a very simplified example, if I had two classes, Pet and Owner, it
seems that I would not have Pet inherit from Owner, since a pet 'has
an' owner, but not 'is an' owner. If this is correct, does my code
below reflect this? I passed the owner object into the pet object's
constructor - is this the right way to do it?
Well, other than the facet that I'd say "Owner" has-a "Pet", but
this example is a bit too disjoint for the association (IE, it goes both
ways)

A common example is something like:

class Vehicle(object):
#which has attributes for speed, direction, cargo capacity,
passenger capacity

class RoadVehicle(Vehicle):
#inherits (RoadVehicle IS-A Vehicle with Axles)

class Auto(RoadVehicle)
# HAS-A Front-Axle, Rear-Axle
# and Axle HAS-A Left-Tire, Right-Tire (unless a Dual -- with
inner left, outer left, inner right, outer right, those those would
appear on Bus(RoadVehicle) and Truck(RoadVehicle) classes)

Look up "Law of Demeter" (I believe that is the name). The idea
is that a "user" of, say, Auto, should NOT need to know that it
has tires (may know it has axles, so it may have a
"listAxles()" method, which returns a list/tuple of the axles
that the Auto has. You could then use that list to access the
tires on each axle { for tire in aRoadVehicle.listAxles():
print tire.specification() }
The Law of Demeter constrains the attributes that the methods of
Auto may invoke. Given the above containment hierarchy, the Law
says that no method of Auto may depend on any attribute or method
of Tire. So if you needed to compute, in an Auto method,
something that depends on an attribute of Tire, you must make
that information available directly through the Axle interface.

The benefit is that this lowers the coupling between classes. The
Tire interface can change completely without affecting the Auto
class.
BUT... Just look at the Python library... sys.stdout.write(),
if following Law of Demeter would turn into:

myStdout = sys.getStdout()
myStdout.write()
The Law of Demeter doesn't apply to that example.

--
Neil Cerutti
Nov 16 '07 #6

P: n/a
sn*******@gmail.com a écrit :
In learning about design patterns, I've seen discussion about using
inheritance when an object's relationship to another object is 'is-a'
and composition when the relationship is 'has-a'.
wrt/ inheritance, it only makes sens with declarative static type
systems where polymorphic dispatch depends on subclassing (so
inheritance is used for both implementation and subtyping). In the
context of a dynamic type system, inheritance is only for implementation
reuse, ie given the following class definitions :

class Foo(object):
def bar(self):
return 42

class Baaz(object):
def bar(self):
return 84
Baaz actually 'is a' (proper subtype of) Foo (and vice-versa).
>
Since this is all new and I'm still learning, I was hoping someone can
give me some pointers on best practices on applying these ideas. If my
logic is incorrect on anything, please don't hesitate to tell me where
I'm wrong - I'm completely open to any help offered.

As a very simplified example, if I had two classes, Pet and Owner, it
seems that I would not have Pet inherit from Owner, since a pet 'has
an' owner, but not 'is an' owner.
Both (I mean 'has a' and 'is a') are not necessary exclusive.
If this is correct, does my code
below reflect this? I passed the owner object into the pet object's
constructor - is this the right way to do it?
Here again, it depends on the lifetime cycles of both objects. Look for
the difference between composition and aggregation. And it of course
depends on the problem you're trying to solve - there's no such thing as
an 'absolute' model.
Also, I've seen talk that ideally you shouldn't have too many "dots"
in your method calls, instead using delegates to the methods and
attributes. Can anyone elaborate on this?
"should", "should not", laws and golden rules... Indeed, it's usually
better to respect encapsulation.
Ideally, should I be writing
getattr() methods so I can do pet.address instead of
pet.owner.address?
What's the use of pet.address ? Is really 'adress' a responsability of
'Pet' ?
Should I be doing the same with owner's methods
like I did with get_foo()?
Python's methods actually are attributes, so you don't (technically)
need a distinct scheme for methods - __getattr__ will work as well.

__getattr__ is fine when you really have a generic delegation (look for
the Proxy pattern for an example). Else (ie, you decide that, for this
given problem, 'address' is really a responsability of Pet), you might
be better defining an explicit 'address' attribute in Pet - preferably
using a computed attribute (either a property object or a custom
descriptor).

Anyway, the simplest your design and implementation, the better.
My 2 cents...
Nov 16 '07 #7

P: n/a
On 2007-11-17, Odalrick <od******@hotmail.comwrote:
>But that breaks expectations: a user doesn't expect
set_width() to affect the height.

I can't speak for everyone but I certainly expect setting the
width of a Square to change it's height. In fact, that would
probably be the reason I used a Square rather than a Rectangle
in the first place.
Some of the dissonance is from assuming that rectangles can
mutate themselves. I've never seen one do that! ;) The rest of
the dissonance is caused by strong typing. A rectangle with equal
width and height is still a rectangle, in a strongly typed
language.

--
Neil cerutti
Nov 17 '07 #8

This discussion thread is closed

Replies have been disabled for this discussion.