[newbie] Looking for a good introduction to object orientedprogramming with Python

T

Terry Reedy

Perhaps I have. Or perhaps I'm just (over-)reacting to the abuse of
Patterns:

http://c2.com/cgi/wiki?DesignPatternsConsideredHarmful

or that they are a crutch for underpowered languages:

I still remember reading an article something like "Implementing the
Composite Pattern in C++". The example for the discussion was Pictures
that could contain sub-Pictures as well as Graphic elements. I
eventually realized that a) this is trivial in Python, b) the article
was really about how to lie to a C++ compiler, so it would accept
recursive heterogenous structures, and c) I preferred Python.
I think that as languages get more powerful, "Design Patterns" just
become language features, and people stop talking about them. Nobody
talks about Function Pattern, but everyone uses it. In Python, we don't
talk about the Iterator Pattern. We just use iterators.

In pre 2.2 Python, there was talk about the pattern (but not with
Capitals) and how to lie to the interpreter with a fake __getitem__ method.
I'm pretty sure that people could talk about good coding design before
the Gof4. As you say, they didn't invent the patterns. So people
obviously wrote code, and talked about algorithms, without the Gof4
terminology.

'Divide and conquer' is an old, descriptive name for an algorithm action
pattern. It is only incidentally about static structures.

'Dynamic programming' is a rather opaque name for a) an action patter
for using the optimality principle* (when applicable) and b) not
disposing of data one still needs.

* the best path from A to B that passes through C is the best path from
A to C plus the best path from C to B.

Lisp is based on a simple data pattern (or is it a principle):
collection (of dicrete items) = one item + remainder, used to both
construct and deconstruct. Python iterator embody the the same
principle. next(iterator) = iterator: return one item and mutate
yourself to represent the rest -- or raise StopIteration.
 
A

alex23

I haven't read the Gang of Four book itself, but I've spent plenty of
time being perplexed by over-engineered, jargon-filled code, articles,
posts and discussions by people who use Design Patterns as an end to
themselves rather than a means to an end. (Singleton is notoriously bad
in that way.)

The Go4 book isn't perfect, and I don't agree with all of their
patterns. But they themselves made it very clear that _you're not
supposed to_. It's meant to provide a mechanism for discussion and
debate. It's _just another tool for development_; it's not a silver
bullet, and anyone who claims otherwise is just a desperate marketing
shill. _Not_ using a pattern should be as much a part of any
conversation as using it.

(But then, I love the word "synergy" too. Just because something has
been driven into the ground through marketing misuse or overeager
misapplication doesn't make the basic concept itself worthless.)
I think that as languages get more powerful, "Design Patterns" just
become language features, and people stop talking about them. Nobody
talks about Function Pattern, but everyone uses it. In Python, we don't
talk about the Iterator Pattern. We just use iterators.

I'm not making the distinction between "iterator pattern" and
"iterators". Talking about one is talking about the other. That's
_all_ I see design patterns as: naming and defining commonly re-used
aspects of functionality. Not invention, recognition.
I'm pretty sure that people could talk about good coding design before
the Gof4. As you say, they didn't invent the patterns. So people
obviously wrote code, and talked about algorithms, without the Gof4
terminology.

So what did people call Singletons before the pattern was named? If I
was talking about "global uniques" and you were talking about "single
instantiation", would we even recognise we were discussing the same
thing?

The Go4 book was as much about the approach of naming and documenting
patterns as describing the patterns they saw. It was just an attempt
at formally approaching what we were previously doing anyway.
I don't think that "Memento Pattern" is any more clear than "save and
restore".

And I don't think that everyone making up their own terminology helps
with the _communicativeness_ of code.
And the ever-finer distinctions between variations on patterns. Without
looking them up, what are the difference between Default Visitor,
Extrinsic Visitor, Acyclic Visitor, Hierarchical Visitor, Null Object And
Visitor, and regular old Visitor patterns? -- and no, I did not make any
of them up.

Why wouldn't I look them up? The point is that they represent
experience with solving certain problems. _Someone_ felt the
distinction was necessary; by their documenting it I can read it and
decide whether the distinction is relevant to me. Maybe they
considered edge cases I didn't. But telling me _not_ to look at the
definition of a design pattern and just "intuit" it's meaning is,
again, missing the point of having a means of communicating experience
with specific problem domains.
 
S

Steven D'Aprano

So what did people call Singletons before the pattern was named? If I
was talking about "global uniques" and you were talking about "single
instantiation", would we even recognise we were discussing the same
thing?

But are we? If we're comparing code written in two languages, we don't
even know if "global" means the same -- it could be global to a single
module, or global to the entire program.

Singletons encompass many different behaviours under a single name. If I
delete the single instance, and recreate it, will it necessarily have the
same state? Calling it a singleton doesn't answer that question. We still
have to agree on what behaviour this particular singleton has.

NoneType raises an error if you try to create a second instance. bool
just returns one of the two singletons (doubletons?) again.

py> type(None)()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: cannot create 'NoneType' instances
py> type(False)() is False
True

And modules are singletons, even though there is no upper limit to the
number of distinct module objects you can get. So if I tell you that X is
a singleton, you don't even know something as fundamental as whether or
not X is the only instance of its type.

The Go4 book was as much about the approach of naming and documenting
patterns as describing the patterns they saw. It was just an attempt at
formally approaching what we were previously doing anyway.


And I don't think that everyone making up their own terminology helps
with the _communicativeness_ of code.

Are you saying that Go4 shouldn't have made up their own terminology?
"Save and restore" is plain English which predates "Memento Pattern". I
was writing code in the 1980s like:

save := something;
do_stuff_to(something);
something := save; {restore old value}

which is the Memento pattern in non-OOP Pascal.

Why wouldn't I look them up?

You claim that named Patterns simplify and clarify communication. If you
have to look the terms up, they aren't simplifying and clarifying
communication, they are obfuscating it.

The time I save in writing "Foo Visitor" is lost a dozen times over for
every one of my readers who has to look it up to find out what I mean.
And if somebody else uses "Foo Visitor" to mean something different to
what I mean, we now have a communication mismatch. The finer the
distinction between Foo and Bar Visitor, the more likely that people will
misunderstand or fail to see the distinction, and the less useful the
terminology gets.

There is a point of diminishing returns in terminology, where finer
distinctions lead to less clarity rather than more, and in my opinion
that point was already passed when Go4 wrote their book, and it's just
got worse since.
 
C

Chris Angelico

NoneType raises an error if you try to create a second instance. bool
just returns one of the two singletons (doubletons?) again.

py> type(None)()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: cannot create 'NoneType' instances
py> type(False)() is False
True

This is necessitated by the use of bool(x) as a means of boolifying
("casting to bool", if you like) x. I wouldn't want that to change,
and since type(False) is bool, what you see is bound to occur.

ChrisA
 
A

alex23

You claim that named Patterns simplify and clarify communication. If you
have to look the terms up, they aren't simplifying and clarifying
communication, they are obfuscating it.

By that argument, an encyclopaedia is useless because if you have to
look up the meaning of something by its name... Names are identifiers
for exactly that reason, to make look up easier. Names aren't meant to
encode every aspect of what they represent.

Or why distinguish between quick sort & merge sort? Let's just talk
about "sort", that's simpler.
The time I save in writing "Foo Visitor" is lost a dozen times over for
every one of my readers who has to look it up to find out what I mean.

What would you call it that would remove the need for _anyone_ to look
up/ask you what it meant?
And if somebody else uses "Foo Visitor" to mean something different to
what I mean, we now have a communication mismatch.

Do we just not use names at all? How do you communicate what you're
doing in this instance?
There is a point of diminishing returns in terminology, where finer
distinctions lead to less clarity rather than more, and in my opinion
that point was already passed when Go4 wrote their book, and it's just
got worse since.

Can you please point me to a standardised way for talking about
abstract patterns of behaviour across languages?
 
R

rusi

The point I'm obviously struggling to make is that words convey concepts
The word Person conveys a whole lifetime of experience of People and as
imperfect human beings many of us are unable to tease out 'bits of being
a person' that are relevant to the system we are developing. Inevitably
other seemingly irreversibly entwined bits keep popping up to cloud our
thinking. This is my experience, not an isolated case but one that has
popped up again and again.

I once sat for a presentation of a wannabe university teacher.
The subject she chose was object-orientation.

She spent some time on the usual dope about employee, manager etc.
Finally she reached the base-class: Person.

Or so we thought...

Then suddenly she started 'extending' the bases:
Person inherits from mammal inherits from vertebrate inherits from
animal

Now in principle one could perhaps find an app where this whole
inheritance hierarchy makes sense.
But I cannot think of one. (Maybe something from Orwell??)

In any case this is the incident that makes me side with your "NO
PERSON" dictum.
 
D

Dennis Lee Bieber

The point I'm obviously struggling to make is that words convey concepts
The word Person conveys a whole lifetime of experience of People and as
imperfect human beings many of us are unable to tease out 'bits of being
a person' that are relevant to the system we are developing. Inevitably
other seemingly irreversibly entwined bits keep popping up to cloud our
thinking. This is my experience, not an isolated case but one that has
popped up again and again.
You've never considered writing a genealogy program, have you? One
that never acknowledges "Person"?
 
S

Steven D'Aprano

I once sat for a presentation of a wannabe university teacher. The
subject she chose was object-orientation.

She spent some time on the usual dope about employee, manager etc.
Finally she reached the base-class: Person.

Or so we thought...

Then suddenly she started 'extending' the bases: Person inherits from
mammal inherits from vertebrate inherits from animal

Now in principle one could perhaps find an app where this whole
inheritance hierarchy makes sense.

Presumably female managers who breast-feed their children inherit that
method from Mammal.

And if you were modelling a futuristic space station with both human and
non-human beings (perhaps for a game?), then distinguishing between those
that inherit a breathe_oxygen() method from Animal versus those that
inherit absorb_magnetic_energy() from Acturian_Magnevore might be useful.

I wasn't at this talk, but I would be willing to bet that she wasn't
suggesting that any specific application needs to encompass the entire
inheritance hierarchy from Animal to Junior Manager Of Pencil Sharpeners,
only that the Inheritance design pattern was capable of doing so.

But I cannot think of one. (Maybe something from Orwell??)

In any case this is the incident that makes me side with your "NO
PERSON" dictum.

The problem with this dictum is that while it recognises that (e.g.) a
Customer is not necessarily a person (it can be another business unit or
a company), that's more the exception than the rule. A Student is always
a person. So is an Employee or Employer, a Surgeon or Patient, or the
subject of birth, death and marriage records.

(As they say: I'll believe that corporations are people when Texas
executes one.)

You can, of course, ban the name "Person" from your classes and
databases. But that's a mere cosmetic quirk -- you're still modelling
people as objects and/or database records, whether you use the word or
not.
 
C

Chris Angelico

(As they say: I'll believe that corporations are people when Texas
executes one.)

If proper excuse you can trump any,
You may wind up a Limited Company
You cannot conveniently blow it up!

-- WS Gilbert, "Utopia, Ltd"

But not every "is-a" relationship needs to be represented as class
inheritance. So what if all your Customers are Persons? Do you
_really_ need a Person base class? In a lot of systems, you don't. If
anything, you might have a generic base class for every entity that
has an Address (which would include corporations), but that's more
likely to want to be composition than inheritance (the customer Has-An
Address rather than the customer Is-An AddressibleEntity). Flat is
better than nested.

Of course, if you don't need an actual use-case, I could invent
several ridiculous base classes. Why not have one for Body, which
would be subclassed by Person and Corporation (after all, a
corporation is a body, that's where the name comes from), but not
Ghost. And then you could have a mixin called Intelligence which is
used by Corporation and Army (everyone knows what Business
Intelligence and Military Intelligence are), sometimes used by Person,
but never used by ClassDesign.

ChrisA
 
D

Dennis Lee Bieber

A Tree consists of Node(s) and Leaf(s), relationships are modelled by
following the Line(s) in the Tree diagram and that is it. Line may be a
class as in 'the patriarchal line' I'm not sure, it would come out in
the iterative wash.

We can infer whatever we want from this simple model. A Leaf is a child,
until it becomes a parent when it becomes a Node. To anthropomorphize a
bit more (I love that word) and introduce non species specific words and
concepts, a Node can be a father or mother (simple to implement by

If a "node" is a father or mother, and it takes one of each to
produce a "leaf", your "tree" has just collapsed.

In genealogy, a "tree" is merely the representation -- in one
direction -- of relationships from a single Person to either all
ancestors, or to all descendents.

"Father", "mother", "son", "daughter" (or to simplify, "parent",
"child") are merely roles taken on by a person in relationship to
another person. A Person can exist even if we do not know who the
parents were, nor if there are any children.
But what of all the ephemeral data that goes with a sentient existance
on this planet such as birth certificates, newspaper articles,
christenings, death certificates, photographs etc etc, what about
pegigree certificates, innoculation records and any other trivia,
information and flotsam that goes with a pedigree Dog or Horse or indeed
Parrot.
Those documents are the /evidence/ used to prove the linkages of the
Person.

Granted, the most popular genealogy program tends to be the least
capable -- it won't let one add a person without creating a "family"
first; and most all evidence is recorded as just a text memo.

In contrast, TMG, provides for "Sources" (the documents),
"Citations" (references to sources, used in the events in the person's
life), "Repositories" (where the source can be found). Events cover
things like "Birth", "Marriage", "Death", "Graduation", etc. [one can
create custom events too]. Events have a date, a location, and can have
multiple citations to the source the provides evidence that the event
took place and involved the person to which it is linked. In TMG, there
is no "family" as such -- only the linkages from relationship events (a
"birth" event does not link a child to its parents; that is done via a
pair of parent-child relationships [father-relationship,
mother-relationship] and TMG supports having multiples -- only the pair
marked a "primary" is used to produce "tree-like" reports, but the
system supports having birth-parents and adoptive-parents at the same
time in the data). It even supports having multiple "Birth" events too,
if one finds conflicting evidence and can not determine if some is
invalid.

I'm not going to go into depth, but the TMG (v8) database consists
of 29 tables, and the user interface centers on displaying a list of
events for a person. Oh, and the person can have more than one name too,
though only one can be listed as primary (shows at the top of the page)
-- the others appear as name events.

The absolute minimum to define a person in TMG is an ID number (the
internal primary key) and preferably a "primary" name (and the name
could be all blanks -- though having multiple people with no names, just
ID numbers, makes for difficulty when later adding relationships: does
this person connect to "(---unknown---)(---unknown---)" #2718 or to
"(---unknown---)(---unknown---)" #3145 <G>)
 
S

Simon Cropper

A Tree consists of Node(s) and Leaf(s), relationships are modelled by
following the Line(s) in the Tree diagram and that is it. Line may be a
class as in 'the patriarchal line' I'm not sure, it would come out in
the iterative wash.

We can infer whatever we want from this simple model. A Leaf is a child,
until it becomes a parent when it becomes a Node. To anthropomorphize a
bit more (I love that word) and introduce non species specific words and
concepts, a Node can be a father or mother (simple to implement by

If a "node" is a father or mother, and it takes one of each to
produce a "leaf", your "tree" has just collapsed.

In genealogy, a "tree" is merely the representation -- in one
direction -- of relationships from a single Person to either all
ancestors, or to all descendents.

"Father", "mother", "son", "daughter" (or to simplify, "parent",
"child") are merely roles taken on by a person in relationship to
another person. A Person can exist even if we do not know who the
parents were, nor if there are any children.
But what of all the ephemeral data that goes with a sentient existance
on this planet such as birth certificates, newspaper articles,
christenings, death certificates, photographs etc etc, what about
pegigree certificates, innoculation records and any other trivia,
information and flotsam that goes with a pedigree Dog or Horse or indeed
Parrot.
Those documents are the /evidence/ used to prove the linkages of the
Person.

Granted, the most popular genealogy program tends to be the least
capable -- it won't let one add a person without creating a "family"
first; and most all evidence is recorded as just a text memo.

In contrast, TMG, provides for "Sources" (the documents),
"Citations" (references to sources, used in the events in the person's
life), "Repositories" (where the source can be found). Events cover
things like "Birth", "Marriage", "Death", "Graduation", etc. [one can
create custom events too]. Events have a date, a location, and can have
multiple citations to the source the provides evidence that the event
took place and involved the person to which it is linked. In TMG, there
is no "family" as such -- only the linkages from relationship events (a
"birth" event does not link a child to its parents; that is done via a
pair of parent-child relationships [father-relationship,
mother-relationship] and TMG supports having multiples -- only the pair
marked a "primary" is used to produce "tree-like" reports, but the
system supports having birth-parents and adoptive-parents at the same
time in the data). It even supports having multiple "Birth" events too,
if one finds conflicting evidence and can not determine if some is
invalid.

I'm not going to go into depth, but the TMG (v8) database consists
of 29 tables, and the user interface centers on displaying a list of
events for a person. Oh, and the person can have more than one name too,
though only one can be listed as primary (shows at the top of the page)
-- the others appear as name events.

The absolute minimum to define a person in TMG is an ID number (the
internal primary key) and preferably a "primary" name (and the name
could be all blanks -- though having multiple people with no names, just
ID numbers, makes for difficulty when later adding relationships: does
this person connect to "(---unknown---)(---unknown---)" #2718 or to
"(---unknown---)(---unknown---)" #3145 <G>)

Since we have graduated to a completely different topic I have renamed
the thread.

If people are interested in a totally python-based open source FREE (as
in no $$) package that can do all the above try gramps...

http://gramps-project.org/

I have used this package for a few years now and it is fantastic. Check
out the features page to see what I mean.

http://gramps-project.org/features/

--
Cheers Simon

Simon Cropper - Open Content Creator

Free and Open Source Software Workflow Guides
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,480
Members
44,900
Latest member
Nell636132

Latest Threads

Top