473,763 Members | 3,712 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

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.addre ss? 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__(sel f, name):
if name == 'address':
return self.owner.addr ess
else:
raise AttributeError, name

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

owner = Owner()
pet = Pet(owner)
Nov 15 '07 #1
7 3067
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.addre ss? 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.w eb.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.addre ss? 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 "perspectiv es" 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.w eb.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.addre ss? 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_foodbow l, which is
implemented as self.owner.has_ foodbowl_for(se lf). If you've got pets
with more than one owner, it might be any(owner.has_f oodbowl_for(sel f)
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*******@gmai l.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.add ress" 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 responsibilitie s, 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.addre ss? 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.addres s" doesn't say it uses owner to make
the connection, unlike "pet.owner.addr ess").
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.net com.comwrote:
On Thu, 15 Nov 2007 12:28:28 -0800 (PST), "sn*******@gmai l.com"
<sn*******@gma il.comdeclaimed the following in comp.lang.pytho n:
>>
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(Veh icle):
#inherits (RoadVehicle IS-A Vehicle with Axles)

class Auto(RoadVehicl e)
# 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(RoadVehic le) 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.li stAxles():
print tire.specificat ion() }
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.writ e(),
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.addre ss?
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******@hotma il.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
6397
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 something I'll need in this case is some experience-based set of rules about how to use python in this context. For example... is defining readonly attributes in classes worth the hassle ? Does duck-typing scale well in complex
63
5175
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 aware of any scripting language that could be considered as "Python minus OO stuff"? (As you can see I'm completely new to Python and initially believed it's a nice&simple scripting language before seeing all this OO stuff that was added in over...
8
1854
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 what arguments do you decide whether to pass a reference to the object of class B to the member function like this operator()(classB& objB) or to have in class A a data member (a const pointer to a class B object or so) and have this set during...
12
7055
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 I've ended up using successfully for certain kinds of inheritance and polymorphism, and some that have not worked out so well. Let's start with obvious things that turn out not to work well: 1. Use interface classes and "Implements" for...
1
1887
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 software has been designed using the .NET framework and coded in C#. The patterns can be stored as plug-ins in XML, adding any number of attributes like Intent, Behavior and the like... Class
6
2079
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 DeviceManager which is only interested in CD/DVD devices. I want to get the list of CD/DVD devices and "be informed when a disc inserted into a device". I am developing this on Linux. So, I used HAL API and read some system (actually /proc) files to gather...
23
1511
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
1689
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 with single inheritance. I also published this request at http://bugs.python.org/issue2667
10
4392
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
9563
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, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
9386
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
10145
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
9998
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
1
9938
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 Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
9822
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 protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
8822
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, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
0
6642
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
5406
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?

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.