1 view

Skip to first unread message

Sep 3, 2008, 9:57:50 AM9/3/08

to pytho...@python.org

Hello everyone,

I try to set two properties, "value" and "square" in the following code,

and arrange it in such way that setting one property also sets another

one and vice versa. But the code seems to get Python into infinite loop:

>>> import math

>>> class Squared2(object):

def __init__(self, val):

self._internalval=val

self.square=pow(self._internalval,2)

def fgetvalue(self):

return self._internalval

def fsetvalue(self, val):

self._internalval=val

self.square=pow(self._internalval,2)

value = property(fgetvalue, fsetvalue)

def fgetsquare(self):

return self.square

def fsetsquare(self,s):

self.square = s

self.value = math.sqrt(self.square)

square = property(fgetsquare, fsetsquare)

>>> a=Squared2(5)

Traceback (most recent call last):

File "<pyshell#11>", line 1, in <module>

a=Squared2(5)

File "<pyshell#10>", line 5, in __init__

self.square=pow(self._internalval,2)

File "<pyshell#10>", line 19, in fsetsquare

self.square = s

File "<pyshell#10>", line 19, in fsetsquare

self.square = s

File "<pyshell#10>", line 19, in fsetsquare

self.square = s

File "<pyshell#10>", line 19, in fsetsquare

self.square = s

File "<pyshell#10>", line 19, in fsetsquare

self.square = s

File "<pyshell#10>", line 19, in fsetsquare

...

Is there a way to achieve this goal of two mutually setting properties?

Sep 3, 2008, 10:31:17 AM9/3/08

to

On Wed, 03 Sep 2008 15:57:50 +0200, mk wrote:

> I try to set two properties, "value" and "square" in the following code,

> and arrange it in such way that setting one property also sets another

> one and vice versa. But the code seems to get Python into infinite loop:

> Is there a way to achieve this goal of two mutually setting properties?

My attempt:

---

import math

class Square(object):

def __init__(self, val):

self._square = pow(val, 2)

self._value = math.sqrt(self.square)

def getsquare(self):

return self._square

def setsquare(self, square):

self._square = square

self._value = math.sqrt(self._square)

square = property(getsquare, setsquare)

def getvalue(self):

return self._value

def setvalue(self, value):

self._value = value

self._square = math.pow(value, 2)

value = property(getvalue, setvalue)

a = Square(5)

print a.square

print a.value

a.value = 10

print a.square

print a.value

a.square = 64

print a.square

print a.value

---

and the result:

$ python sqval.py

25

5.0

100.0

10

64

8.0

$

--

Regards,

Wojtek Walczak,

http://tosh.pl/gminick/

Sep 3, 2008, 10:34:12 AM9/3/08

to

On Wed, 3 Sep 2008 14:31:17 +0000 (UTC), Wojtek Walczak wrote:

> class Square(object):

> def __init__(self, val):

> self._square = pow(val, 2)

> self._value = math.sqrt(self.square)

^^^^^^^^^^^^^^^^^^^^^^

or just:

self._value = val

:-)

Sep 3, 2008, 10:42:11 AM9/3/08

to

mk schrieb:

Better to make the getter for square return the square of value, and the

setter of square compute the root & set that. Like this:

class Squared2(object):

def __init__(self, value):

self.value = value

@apply

def squared():

def fset(self, squared):

self.value = math.sqrt(squared)

def fget(self):

return self.value ** 2

return property(**locals())

Diez

Sep 3, 2008, 10:44:10 AM9/3/08

to pytho...@python.org

Your square property is not correctly defined, it recurselively call itself,

it should be (I also avoided the extra lookup) :

def fgetsquare(self):

return self._square

def fsetsquare(self,s):

self._square = s

self.value = math.sqrt(s)

then the fsetvalue will be also be called recursively as it use the square

property, you should also write it :

def fsetvalue(self, val):

self._internalval=val

self._square=pow(val,2)

*but*, if you want to add more logic in the setters, you could want to add two

extra methods :

def _setsquare(self, v) :

# some extra logic here

self._square = s

def fsetsquare(self,s):

self._setsquare(s)

self._setvalue = math.sqrt(s)

def _setvalue(self, val):

# some extra logic here

self._internalval=val

def fsetvalue(self, val):

self._setvalue(val)

self._setsquare=pow(val,2)

Note that if one property can really be computed from another, this kind of

thing could be considered as bad design (except if the computation is heavy).

--

_____________

Maric Michaud

Sep 3, 2008, 10:50:43 AM9/3/08

to

mk a écrit :

> Hello everyone,

>

> I try to set two properties, "value" and "square" in the following code,

> and arrange it in such way that setting one property also sets another

> one and vice versa. But the code seems to get Python into infinite loop:

>

> >>> import math

> >>> class Squared2(object):

>

> def __init__(self, val):

> self._internalval=val

> self.square=pow(self._internalval,2)

> Hello everyone,

>

> I try to set two properties, "value" and "square" in the following code,

> and arrange it in such way that setting one property also sets another

> one and vice versa. But the code seems to get Python into infinite loop:

>

> >>> import math

> >>> class Squared2(object):

>

> def __init__(self, val):

> self._internalval=val

> self.square=pow(self._internalval,2)

the 'internal' prefix is already implied by the '_'. And your __init__

code is a useless duplication of fsetvalue, so just use the property and

get rid of copy-pasted code.

> def fgetvalue(self):

> return self._internalval

the '_' prefix already means 'internal'. The convention here would be to

name the attribute '_value' (to make clear it's the implementation

support for the 'value' property). Also, your property getter and setter

should also be marked as implementation using the '_' prefix - they are

implementation detail, not part of your class API.

> def fsetvalue(self, val):

> self._internalval=val

> self.square=pow(self._internalval,2)

>

> value = property(fgetvalue, fsetvalue)

>

> def fgetsquare(self):

> return self.square

> def fsetsquare(self,s):

> self.square = s

Hem... Notice something here ?

> self.value = math.sqrt(self.square)

>

> square = property(fgetsquare, fsetsquare)

Your fsetsquare implementation is broken - it calls itself recursively.

You have to use different names for the property and the 'implementation

attribute' for the property. But even if you fix this, you'll have

another infinite recursion between the two setters.

The simplest solution : don't call one property from the other, do

direct attribute access within the setters:

import math

class Squared2(object):

def __init__(self, value):

self.value=value

def _fgetvalue(self):

return self._value

def _fsetvalue(self, value):

self._value=value

self._square=pow(value,2)

value = property(_fgetvalue, _fsetvalue)

def _fgetsquare(self):

return self._square

def _fsetsquare(self,square):

self._square = square

self._value = math.sqrt(square)

square = property(_fgetsquare, _fsetsquare)

Sep 3, 2008, 10:52:06 AM9/3/08

to pytho...@python.org

Le Wednesday 03 September 2008 16:44:10 Maric Michaud, vous avez écrit :

> def _setsquare(self, v) :

> # some extra logic here

> self._square = s

>

> def fsetsquare(self,s):

> self._setsquare(s)

> self._setvalue = math.sqrt(s)

>

> def _setvalue(self, val):

> # some extra logic here

> self._internalval=val

>

> def fsetvalue(self, val):

> self._setvalue(val)

> self._setsquare=pow(val,2)

> def _setsquare(self, v) :

> # some extra logic here

> self._square = s

>

> def fsetsquare(self,s):

> self._setsquare(s)

> self._setvalue = math.sqrt(s)

>

> def _setvalue(self, val):

> # some extra logic here

> self._internalval=val

>

> def fsetvalue(self, val):

> self._setvalue(val)

> self._setsquare=pow(val,2)

Oh sorry for this last version the setters should be :

def fsetsquare(self,s):

self._setsquare(s)

self._setvalue = math.sqrt(self.square)

def fsetvalue(self, val):

self._setvalue(val)

self._setsquare=pow(self.value, 2)

as we don't know what is done in _setXXX methods.

--

_____________

Maric Michaud

Sep 3, 2008, 11:40:43 AM9/3/08

to pytho...@python.org

Thanks to everyone for answers..

> *but*, if you want to add more logic in the setters, you could want to add two

> extra methods :

>

> def _setsquare(self, v) :

> # some extra logic here

> self._square = s

>

> def fsetsquare(self,s):

> self._setsquare(s)

> self._setvalue = math.sqrt(s)

>

> def _setvalue(self, val):

> # some extra logic here

> self._internalval=val

>

> def fsetvalue(self, val):

> self._setvalue(val)

> self._setsquare=pow(val,2)

>

Thanks for that, I'll keep that in mind.

> Note that if one property can really be computed from another, this kind of

> thing could be considered as bad design (except if the computation is heavy).

Hmm, why? Is the line of thinking smth like: because the variables

should be kept to minimum and they should be calculated at the moment

they are needed?

Sep 3, 2008, 12:11:25 PM9/3/08

to pytho...@python.org

Le Wednesday 03 September 2008 17:40:43 mk, vous avez écrit :

> > Note that if one property can really be computed from another, this kind

> > of thing could be considered as bad design (except if the computation is

> > heavy).

>

> Hmm, why? Is the line of thinking smth like: because the variables

> should be kept to minimum and they should be calculated at the moment

> they are needed?

> > Note that if one property can really be computed from another, this kind

> > of thing could be considered as bad design (except if the computation is

> > heavy).

>

> Hmm, why? Is the line of thinking smth like: because the variables

> should be kept to minimum and they should be calculated at the moment

> they are needed?

Because you have to make extra effort to keep the logical relation between

value and square. self._square is not really needed, and what is not needed

is just extra hassle.

Doesn't it clear that your code is more hard to maintain than the

alternative :

class Squared(object):

def __init__(self, val):

self._val=val

def fgetvalue(self):

return self._val

def fsetvalue(self, val):

self._val=val

value = property(fgetvalue, fsetvalue)

def fgetsquare(self):

return self.value ** 2

def fsetsquare(self,s):

self.value = math.sqrt(s)

square = property(fgetsquare, fsetsquare)

--

_____________

Maric Michaud

Sep 3, 2008, 1:38:13 PM9/3/08

to

Maric Michaud a écrit :

FWIW, if there's no computation on getting or setting value, you can

make it a plain attribute.

But while it's quite clear that in this example use case it would be

better to have only one property (weither square or value, depending on

which is the most often use), things are not always that simple in real

world code, and - as you mentionned - there may be times where you have

interdependant properties and really want to avoid recomputing the same

thing over and over. Now there's no one size fits all solution here -

it's an optimization problem, and as such depends on real use cases.

Sep 3, 2008, 7:20:42 PM9/3/08

to pytho...@python.org

Le Wednesday 03 September 2008 19:38:13 Bruno Desthuilliers, vous avez écrit :

> FWIW, if there's no computation on getting or setting value, you can

> make it a plain attribute.

> FWIW, if there's no computation on getting or setting value, you can

> make it a plain attribute.

Yes, this is the problem with these tiny examples, we don't know at which

point we must simplify them...

>

> But while it's quite clear that in this example use case it would be

> better to have only one property (weither square or value, depending on

> which is the most often use), things are not always that simple in real

> world code, and - as you mentionned - there may be times where you have

> interdependant properties and really want to avoid recomputing the same

> thing over and over. Now there's no one size fits all solution here -

> it's an optimization problem, and as such depends on real use cases.

Yes, my advice was exactly in that sense, it's an optimization problem,

duplicating such a data is a caching mechanism, and should be done knowingly,

in acceptance of all the complication it comes with.

--

_____________

Maric Michaud

Reply all

Reply to author

Forward

0 new messages

Search

Clear search

Close search

Google apps

Main menu