473,404 Members | 2,187 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,404 software developers and data experts.

Python Design Patterns - composition vs. inheritance

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
7 3052
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
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
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
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
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
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
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 thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

36
by: Andrea Griffini | last post by:
I did it. I proposed python as the main language for our next CAD/CAM software because I think that it has all the potential needed for it. I'm not sure yet if the decision will get through, but...
63
by: Davor | last post by:
Is it possible to write purely procedural code in Python, or the OO constructs in both language and supporting libraries have got so embedded that it's impossible to avoid them? Also, is anyone...
8
by: Gert Van den Eynde | last post by:
Hi all, I have a question on interface design: I have a set of objects that are interlinked in the real world: object of class A needs for example for the operator() an object of class B. On...
12
by: Steve Jorgensen | last post by:
The classing Visual Basic and VBA support for polymorphism, let's face it, is a bit on the weak side, and built-in support for inheritance is non-existent. This little essay is about some patterns...
1
by: Josh28 | last post by:
Hi We are a group of two chaps just out of undergrad, we created a software to automate the use of Design Patterns. We have put it up at Source Forge--http://dpatoolkit.sourceforge.net/ The...
6
by: Orgun | last post by:
Hi, I sent this message to the moderated c++ group too but it is waiting for moderator approval and I wanted to send here too. I am new to Design Patterns. I want to write a simple...
23
by: neoedmund | last post by:
There's a program, it's result is "unexpected aaa", i want it to be "expected aaa". how to make it work? class C1(object): def v(self, o): return "expected "+o class C2(object):
18
by: GD | last post by:
Please remove ability to multiple inheritance in Python 3000. Multiple inheritance is bad for design, rarely used and contains many problems for usual users. Every program can be designed only...
10
by: Aaron Gray | last post by:
Wikipedia says Python has Multiple Inheritance, is this true ? http://en.wikipedia.org/wiki/Multiple_inheritance Thanks, Aaron
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.