Objects with different data views

S

Steven D'Aprano

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,
 
P

Paul Rubin

Steven D'Aprano said:
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

D.Hering

Paul said:
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)
 
G

George Sakkis

Steven D'Aprano said:
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/Cookbook/Python/Recipe/410698.

HTH,
George
 

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

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,014
Latest member
BiancaFix3

Latest Threads

Top