Another newbie question

Alex Martelli aleax at mail.comcast.net
Sun Dec 11 03:11:20 CET 2005


Mike Meyer <mwm at mired.org> wrote:
   ...
> Take our much-abused coordinate example, and assume you've exposed the
> x and y coordinates as attributes.
> 
> Now we have a changing requirement - we want to get to make the polar
> coordinates available. To keep the API consistent, they should be
> another pair of attributes, r and theta. Thanks to Pythons nice
> properties, we can implement these with a pair of getters, and compute
> them on the fly.
> 
> If x and y can't be manipulated individually, you're done. If they
> can, you have more work to do. If nothing else, you have to decide
> that you're going to provide an incomplete interface, in that users
> will be able to manipulate the object with some attributes but not
> others for no obvious good reason. To avoid that, you'll have to add
> code to run the coordinate transformations in reverse, which wouldn't
> otherwise be needed. Properties make this possible, which is a great
> thing.

Properties make this _easier_ (but you could do it before properties
were added to Python, via __setattr__ -- just less conveniently and
directly) -- just as easy as setX, setY, setRho, and setTheta would (in
fact, we're likely to have some of those methods under our properties,
so the difference is all in ease of USE, for the client code, not ease
of IMPLEMENTATION, compared to setter-methods).

If we keep the internal representation in cartesian coordinates
(attributes x and y), and decide that it would interfere with the
class's usefulness to have rho and theta read-only (i.e., that it IS
useful for the user of the class to be able to manipulate them
directly), we do indeed need to "add code" -- the setter methods setRho
and setTheta.  But let's put that in perspective. If we instead wanted
to make the CoordinatePair class immutable, we'd STILL have to offer an
alternative constructor or factory-function -- if it's at all useful to
manipulate rho and theta in a mutable class, it must be at least as
useful to be able to construct an immutable version from rho and theta,
after all.  So, we ARE going to have, say, a classmethod (note: all the
code in this post is untested)...:

class CoordinatePair(object):
    def fromPolar(cls, rho, theta):
        assert rho>=0
        return cls(rho*math.cos(theta), rho*math.sin(theta))
    fromPolar = classmethod(fromPolar)
    # etc etc, the rest of this class

well, then, how much more code are we adding, to implement setRho and
setTheta when we decide to make our class mutable?  Here...:

    def setRho(self, rho):
        c = self.fromPolar(rho, self.getTheta())
        self.x, self.y = c.x, c.y
    def setTheta(self, theta):
        c = self.fromPolar(self.getRho(), theta)
        self.x, self.y = c.x, c.y

That's the maximum possible "difficulty" (...if THIS was a measure of
real "difficulty" in programming, I doubt our jobs would be as well paid
as they are...;-) -- it's going to be even less if we need anyway to
have a method to copy a CoordinatePair instance from another, such as

    def copyFrom(self, other):
        self.x, self.y = other.x, other.y

since then the above setters also become no-brainer oneliners a la:

    def setRho(self, rho):
        self.copyFrom(self.fromPolar(rho, self.getTheta()))

and you might choose to further simplify this method's body to

        self.copyFrom(self.fromPolar(rho, self.theta))

since self.theta is going to be a property whose accessor half is the
above-used self.getTheta (mostly a matter of style choice here).


Really, I don't think this makes a good poster child for your "attribute
mutators make life more difficult" campaign...;-)


Alex



More information about the Python-list mailing list