Classes as objects

Alex Martelli aleaxit at yahoo.com
Fri Apr 27 05:17:19 EDT 2001


"Daniel Klein" <DanielK at jBASE.com> wrote in message
news:2m%F6.3$o7.36 at typhoon.aracnet.com...
> Haven't posted for a while but I this time I am requesting some
assistence.
>
> I'm putting on a presentation on the benefits of Python over Java and one
of
> the points I would like to make is how everything is an object, even
> Classes. Can anyone out there in PythonVille provide a simple (practical)
> example of how classes can be used as objects?

Here's an example of a pattern I believe is very important:


class Hand:
    "models a single bridge hand with basic evaluation abilities"
    # a few fundamental point-sequences: HCPs, 4 Aces, controls, cards count
    dictSeqEval={'hcp':(4,3,2,1), 'a4':(3,2,1,0.5), 'control':(2,1),
        'ace':(1,), 'king':(0,1), 'queen':(0,0,1), 'jack':(0,0,0,1),
[snip]

This is a pretty elementary model of a (contract-bridge) hand: its
hand-evaluation abilities (like most players':-) are limited to "point
counts" of various descriptions -- no losing-trick-count variations,
Kaplan points, and so on.

More generally, this would be an "elementary object in the application
domain" -- intended to be used as a base class, providing some useful
abilities but definitely needing to be extended for advanced or
specialized uses.  OK do far?

Right, then:

class Deal:
    "models a bridge deal, able to shuffle, evaluate, and show itself"
    handClass = Hand
    def __init__(self, handClass=None):
        if handClass is not None: self.handClass = handClass
[snip]
    def sort(self):
        "sort the shuffled deal object into its 4 hand objects"
        for j in range(4):
            self.hand[j]=self.handClass(self.deck[j*13:j*13+13])

etc, etc.  This models a bridge deal, a structured set of four
hands into which the 52-cards deck is divided.  More generally,
this would be a "structured collection in the application
domain", with its own functionality but crucially relying
on the functionality of the "elementary application-domain
objects" it holds.  But *WHAT* class should the "application
domain objects" _BE_...?

Using Hand, unconditionally, as the class for the application
domain objects, would reduce the usefulness of the structured
collection (Deal) drastically.  When in some other module I
extend Hand to SmartHand, adding other evaluation abilities
and so on, Deal would become pretty useless if it was just
able to generate (e.g. in its .sort() method), and hold, Hand
objects.  Even if I _did_ commit to inherit from Hand, I
would at least have to extend Deal into SmartDeal and hunt
for all mentions of the Hand class to turn them into SmartHand.

There are many solutions, depending on language, such as
(in Eiffel or C++, for example) making Deal parameterized
(template) on the Hand type, having Deal use a factory or
other advanced creational patterns (and only hold its
hand objects with a reference to an interface), ...

Having classes as first-level objects wipes the problem
away.  I can "upgrade" the whole Deal class at runtime
with a single
    pyBridge.Deal.handClass = SmartHand
assignment, or generate specific Deal objects that use
a different hand-class than the deal-class's default:
    aDeal = Deal(SmartHand)

The class object can be its own factory in simple
cases, and in a sense the self.handClass attribute
also plays the role of a "template type parameter".


More generally, any time you define a framework that exposes
several classes, many of which "use each other" (by default)
in terms of instances generating/holding/manipulating other
instances, and where classes are also subject to likely
inheritance and extension by client-code, classes as first
class objects make your life really simple.  It's not that
these forces _cannot_ be resolved e.g. in Java, mind you --
it IS possible (and advisable) to make vast use of interfaces
and creational patterns to let the framework be smoothly
extensible and reusable.  But there are convenience tradeoffs
aplenty, and sometimes simplicity issues -- by the time you
find yourself architecting factories that build factories,
and worrying whether those factories should also have their
own designed abstract interfaces, you MAY start to think
of the many advantages of a job in a halibut processing
plant.  First-class class objects lower complexity quite
substantially in many framework-design tasks.


Alex






More information about the Python-list mailing list