Velocity Reviews > Objects with different data views

# Objects with different data views

Fredrik Lundh
Guest
Posts: n/a

 10-07-2005
Steven D'Aprano wrote:

> It is important that there are no privileged attributes, e.g. in the
> above example, I can set any of x, y, z, r, theta or phi and all the
> others will automatically reflect the changes.

</F>

Steven D'Aprano
Guest
Posts: n/a

 10-07-2005
I'm not sure how to do this, or where to start looking for the right
information, so any advice would be appreciated.

I want to implement a class with two (or more) different ways of looking
at its attributes.

One example of this might be complex numbers, which can be written in
Cartesian form (x+yi) or polar form (r cis theta).

(Yes, I know Python already has complex numbers. That was just an example.)

Another might be 3D vectors, which can be written in Cartesian form
[x, y, z], polar form [r, theta, z] or spherical polar [r, theta, phi].

It is important that there are no privileged attributes, e.g. in the
above example, I can set any of x, y, z, r, theta or phi and all the
others will automatically reflect the changes. A concrete, if simple,
example will make it clear.

Suppose I have a transformation (a,b) <-> (x,y) where:

x = a+b
y = a+2*b

I create an instance spam, and set a and b:

spam.a = 1
spam.b = 2

Now I should be able to read x and y:

print spam.x, spam.y
# prints 3 5

If I set attribute y:

spam.y = 0

a and b automatically change to match:

print spam.a, spam.b
# prints 6, -3

Anyone have any good ideas for how I should implement this?

Thanks,

--
Steven.

Paul Rubin
Guest
Posts: n/a

 10-07-2005
Steven D'Aprano <(E-Mail Removed)> writes:
> Anyone have any good ideas for how I should implement this?

These days you can use properties. Before, you'd have had to do it
manually with __setattr__ / __getattr__ methods. Here's how I'd do it
with properties, if I have the math right. You're using a and b as
the canonical values of the variables, computing x and y from them,
and adjusting them when x and y change.

class Parrot(object):
x = property(getx, setx)
y = property(gety, sety)

def getx(self):
return self.a + self.b
def setx(self, x):
y = self.y # calls gety
self.a, self.b = 2*x - y, y-x

def gety(self):
return self.a + 2*self.b
def sety(self, y):
x = self.x # calls getx
self.a, self.b = 2*x - y, y-x

D.Hering
Guest
Posts: n/a

 10-07-2005
Paul Rubin wrote:
> Steven D'Aprano <(E-Mail Removed)> writes:
>
> class Parrot(object):
> x = property(getx, setx)
> y = property(gety, sety)
>
> def getx(self):
> return self.a + self.b
> def setx(self, x):
> y = self.y # calls gety
> self.a, self.b = 2*x - y, y-x
>
> def gety(self):
> return self.a + 2*self.b
> def sety(self, y):
> x = self.x # calls getx
> self.a, self.b = 2*x - y, y-x

class Parrot(object):

def getx(self):
return self.a + self.b
def setx(self, x):
y = self.y # calls gety
self.a, self.b = 2*x - y, y-x

def gety(self):
return self.a + 2*self.b
def sety(self, y):
x = self.x # calls getx
self.a, self.b = 2*x - y, y-x

x = property(getx, setx)
y = property(gety, sety)

Paul Rubin
Guest
Posts: n/a

 10-07-2005
Yeah, that's what I meant. Thanks.

George Sakkis
Guest
Posts: n/a

 10-08-2005
"Steven D'Aprano" <(E-Mail Removed)> wrote:

> I'm not sure how to do this, or where to start looking for the right
> information, so any advice would be appreciated.
>
> I want to implement a class with two (or more) different ways of looking
> at its attributes.
>
> One example of this might be complex numbers, which can be written in
> Cartesian form (x+yi) or polar form (r cis theta).
>
> (Yes, I know Python already has complex numbers. That was just an example.)
>
> Another might be 3D vectors, which can be written in Cartesian form
> [x, y, z], polar form [r, theta, z] or spherical polar [r, theta, phi].
>
> It is important that there are no privileged attributes, e.g. in the
> above example, I can set any of x, y, z, r, theta or phi and all the
> others will automatically reflect the changes. A concrete, if simple,
> example will make it clear.
>
> Suppose I have a transformation (a,b) <-> (x,y) where:
>
> x = a+b
> y = a+2*b
>
> I create an instance spam, and set a and b:
>
> spam.a = 1
> spam.b = 2
>
> Now I should be able to read x and y:
>
> print spam.x, spam.y
> # prints 3 5
>
> If I set attribute y:
>
> spam.y = 0
>
> a and b automatically change to match:
>
> print spam.a, spam.b
> # prints 6, -3
>
>
> Anyone have any good ideas for how I should implement this?

As others have replied, properties is the way to go. There have been a few recipes in the Cookbook
that avoid cluttering the class namespace with temporary get/set/del methods, e.g.
http://aspn.activestate.com/ASPN/Coo.../Recipe/410698.

HTH,
George