473,726 Members | 2,262 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

"indexed properties"...

Having a hard time phrasing this in the form
of a question...

The other day I saw a thread where someone asked
about overrideable properties and nobody offered
the advice that properties are Bad. So maybe we've
got over that. I suppose properties could have
Bad consequences if a user doesn't know they exist
and think that a certain property of an object is
just an ordinary attribute. But that applies to
almost any aspect of any language.

If a person comes from, say, Object Pascal (Delphi)
then properties are hard to live without. The
other day I decided I wanted what OP calls an
"indexed property" or "array property". Couldn't
figure out how to make a _property_ behave that way.
So I read a little bit about descriptors, and a
few minutes later I had an indexedproperty thing
that works just like property, except it gives
an indexed property! This is just too cool.

Why? For example, a Matrix should have a row[n]
property allowing things like

m.row[0] = m.row[1] + m.row[2]

Ok, you could do _that_ by just making row
an ordinary list of Row objects. But then
you'd have to say

m.row[0] = Row([1,2,3])

where I want to be able to say

m.row[0] = [1,2,3]

and have the Row created automatically.

_Also_ with these indexed properties my Matrix
can have m.row[j] and m.col[k] that look exactly
the same to a client - we don't want to store a
list of rows internally and also store the same
data in a list of columns. Too cool.

Hmm, none of that's a valid excuse for a post here.
Um, right, here we go: Anyone see problems or
possible improvements with the implementation
of indexedproperty below?

"""indexed. py: "indexedpropert y" works more or less
like "property" except it gives what in Object Pascal
would be an "indexed property". See the
__name__="__mai n__" section below for a demo

"""

class WriteOnlyIP(Exc eption):
def __str__(self):
return """

indexed property is write-only

"""

class ReadOnlyIP(Exce ption):
def __str__(self):
return """

indexed property is read-only

"""

class indexedproperty (object):
def __init__(self, getitem=None, setitem=None):
self.getitem = getitem
self.setitem = setitem

def __get__(self, obj, owner):
self.obj = obj
return self

def __getitem__(sel f, index):
if self.getitem:
return self.getitem(se lf.obj, index)
else:
raise WriteOnlyIP

def __setitem__(sel f, index, value):
if self.setitem:
self.setitem(se lf.obj, index, value)
else:
raise ReadOnlyIP
if __name__ == "__main__":

class AClass(object):
def __init__(self):
self.cells = [[0,0], [0,0]]

def SetCell(self, (row, col), value):
self.cells[row][col] = value

def GetCell(self, (row, col)):
return self.cells[row][col]

cell = indexedproperty (GetCell, SetCell)

C = AClass()
for row in range(2):
for col in range(2):
C.cell[row, col] = "row: %s, col: %s" % (row, col)

for row in range(2):
for col in range(2):
print C.cell[row, col]

C.cell[0,0], C.cell[1,1] = C.cell[1,1], C.cell[0,0]

print "After C.cell[0,0], C.cell[1,1] = C.cell[1,1], C.cell[0,0]:"

for row in range(2):
for col in range(2):
print C.cell[row, col]

--
David C. Ullrich
Jun 27 '08 #1
17 2782
En Wed, 14 May 2008 18:15:41 -0300, David C. Ullrich
<du******@spryn et.comescribió:
Having a hard time phrasing this in the form
of a question...

The other day I saw a thread where someone asked
about overrideable properties and nobody offered
the advice that properties are Bad. So maybe we've
got over that. I suppose properties could have
Bad consequences if a user doesn't know they exist
and think that a certain property of an object is
just an ordinary attribute. But that applies to
almost any aspect of any language.

If a person comes from, say, Object Pascal (Delphi)
then properties are hard to live without. The
other day I decided I wanted what OP calls an
"indexed property" or "array property". Couldn't
figure out how to make a _property_ behave that way.
So I read a little bit about descriptors, and a
few minutes later I had an indexedproperty thing
that works just like property, except it gives
an indexed property! This is just too cool.

Why? For example, a Matrix should have a row[n]
property allowing things like

m.row[0] = m.row[1] + m.row[2]

Ok, you could do _that_ by just making row
an ordinary list of Row objects. But then
you'd have to say

m.row[0] = Row([1,2,3])

where I want to be able to say

m.row[0] = [1,2,3]

and have the Row created automatically.

_Also_ with these indexed properties my Matrix
can have m.row[j] and m.col[k] that look exactly
the same to a client - we don't want to store a
list of rows internally and also store the same
data in a list of columns. Too cool.

Hmm, none of that's a valid excuse for a post here.
Um, right, here we go: Anyone see problems or
possible improvements with the implementation
of indexedproperty below?

"""indexed. py: "indexedpropert y" works more or less
like "property" except it gives what in Object Pascal
would be an "indexed property". See the
__name__="__mai n__" section below for a demo

"""

class WriteOnlyIP(Exc eption):
def __str__(self):
return """

indexed property is write-only

"""

class ReadOnlyIP(Exce ption):
def __str__(self):
return """

indexed property is read-only

"""

class indexedproperty (object):
def __init__(self, getitem=None, setitem=None):
self.getitem = getitem
self.setitem = setitem

def __get__(self, obj, owner):
self.obj = obj
return self

def __getitem__(sel f, index):
if self.getitem:
return self.getitem(se lf.obj, index)
else:
raise WriteOnlyIP

def __setitem__(sel f, index, value):
if self.setitem:
self.setitem(se lf.obj, index, value)
else:
raise ReadOnlyIP
if __name__ == "__main__":

class AClass(object):
def __init__(self):
self.cells = [[0,0], [0,0]]

def SetCell(self, (row, col), value):
self.cells[row][col] = value

def GetCell(self, (row, col)):
return self.cells[row][col]

cell = indexedproperty (GetCell, SetCell)

C = AClass()
for row in range(2):
for col in range(2):
C.cell[row, col] = "row: %s, col: %s" % (row, col)

for row in range(2):
for col in range(2):
print C.cell[row, col]

C.cell[0,0], C.cell[1,1] = C.cell[1,1], C.cell[0,0]

print "After C.cell[0,0], C.cell[1,1] = C.cell[1,1], C.cell[0,0]:"

for row in range(2):
for col in range(2):
print C.cell[row, col]


--
Gabriel Genellina

Jun 27 '08 #2
En Wed, 14 May 2008 18:15:41 -0300, David C. Ullrich <du******@spryn et.comescribió:
Having a hard time phrasing this in the form
of a question...

The other day I saw a thread where someone asked
about overrideable properties and nobody offered
the advice that properties are Bad. So maybe we've
got over that. I suppose properties could have
Bad consequences if a user doesn't know they exist
and think that a certain property of an object is
just an ordinary attribute. But that applies to
almost any aspect of any language.
Which "bad consequences" are you thinking of? Apart from the user not being aware of the complexity of certain operations, or a getter/setter very time-consuming (in that case I'd use public getXXX/setXXX functions instead, to emphasize that "something" is happening, not just an attribute lookup)
If a person comes from, say, Object Pascal (Delphi)
then properties are hard to live without. The
You should read the article "Python is not Java" if you haven't done it yet.
http://dirtsimple.org/2004/12/python-is-not-java.html
other day I decided I wanted what OP calls an
"indexed property" or "array property". Couldn't
figure out how to make a _property_ behave that way.
So I read a little bit about descriptors, and a
few minutes later I had an indexedproperty thing
that works just like property, except it gives
an indexed property! This is just too cool.

Why? For example, a Matrix should have a row[n]
property allowing things like

m.row[0] = m.row[1] + m.row[2]

Ok, you could do _that_ by just making row
an ordinary list of Row objects. But then
you'd have to say

m.row[0] = Row([1,2,3])

where I want to be able to say

m.row[0] = [1,2,3]

and have the Row created automatically.
One could make *row* an object with a custom __getitem__/__setitem__ in this case. But I prefer to have as little magic as possible on my objects: if it says m.row[0] = [1,2,3] I expect m.row[0] to actually *be* that list (whenever possible), and not any other object initialized from the [1,2,3] arguments. (Maybe this is some overreaction against C++ "magic" constructors and such horrible things...)
_Also_ with these indexed properties my Matrix
can have m.row[j] and m.col[k] that look exactly
the same to a client - we don't want to store a
list of rows internally and also store the same
data in a list of columns. Too cool.
The same can be achieved having m.row and m.col be custom objects like I said above.
Hmm, none of that's a valid excuse for a post here.
Um, right, here we go: Anyone see problems or
possible improvements with the implementation
of indexedproperty below?
Note that the property object (or your indexedproperty ) is a *class* attribute. That is, shared among all instances.
class indexedproperty (object):
def __init__(self, getitem=None, setitem=None):
self.getitem = getitem
self.setitem = setitem

def __get__(self, obj, owner):
self.obj = obj
return self
Here is the problem. You can't store "obj" in "self" because it is shared among all instances. Your examples don't show any problem because all property accesses are immediately followed by a getitem access using the same object. Try this:

x = AClass()
y = AClass()
x.cell[0,0] = 1
print x.cell[1,1] # output: 0
y.cell[x.cell[0,0], x.cell[0,0]] = 2
print y.cell[1,1] # should be 2, still 0
print x.cell[1,1] # should still be 0, but changed, now 2

A workaround would be to return another object in __get__ instead of self, which remembers the "obj" instance, or a closure, or...
But I don't really see the point, it's a lot easier to use another object for .cell (it's more clear, doesn't break encapsulation, divides responsabilitie s...)

class Matrix2x2(objec t):
def __init__(self):
self.cells = [[0,0], [0,0]]

def __setitem__(sel f, (row, col), value):
self.cells[row][col] = value

def __getitem__(sel f, (row, col)):
return self.cells[row][col]

class AClass(object):
def __init__(self):
self.cell = Matrix2x2()
--
Gabriel Genellina

Jun 27 '08 #3
On Thu, 15 May 2008 10:59:41 -0300, "Gabriel Genellina"
<ga*******@yaho o.com.arwrote:
>En Wed, 14 May 2008 18:15:41 -0300, David C. Ullrich <du******@spryn et.comescribió:
>Having a hard time phrasing this in the form
of a question...

The other day I saw a thread where someone asked
about overrideable properties and nobody offered
the advice that properties are Bad. So maybe we've
got over that. I suppose properties could have
Bad consequences if a user doesn't know they exist
and think that a certain property of an object is
just an ordinary attribute. But that applies to
almost any aspect of any language.

Which "bad consequences" are you thinking of?
Didn't have anything specific in mind - there I was
just playing devil's advocate. I've seen a lot of people
here say things like "properties should only be used
when refactoring" without any explanation that I could
see of why properties were bad things. I was referring
to whatever problems they had in mind.
>Apart from the user not being aware of the complexity of certain operations, or a getter/setter very time-consuming (in that case I'd use public getXXX/setXXX functions instead, to emphasize that "something" is happening, not just an attribute lookup)
>If a person comes from, say, Object Pascal (Delphi)
then properties are hard to live without. The

You should read the article "Python is not Java" if you haven't done it yet.
http://dirtsimple.org/2004/12/python-is-not-java.html
I suspect you misunderstood my point there. I actually read that
article years ago. Been using Python for years. I'd never confuse
it with OP, I promise (luckily I don't know any Java and don't
intend to). I really didn't express what I meant very well - what
I should have said was more like "If you're accustomed to properties
from a language like OP they seem like a very useful addition to
Python".

Looking at the article it seems like two points are relevant.
(i) I'm well aware that chains of attribute accesses don't
get compiled away in Python the way they do in OP.

(ii) Regarding the bit about how getters and setters are
evil, and it's also bad to wrap things in properties when
simple attributes would do. Yes. Thanks for pointing
that out, but I wouldn't do that - using a property where
a simple attribute would do would be stupid. But they
_can_ be much nicer than having to use explicit getters
and setters, in cases where a simple attribute won't do.

I got started on this thinking about making myself a
nicer interface (nicer-seeming to me) to the wxPython
grid object. Being able to say

grid[row, col] = value

seems much nicer and more natural than

grid.SetCellVal ue(row, col, value)

(yes, _that_ one is just __get(set)item_ _,
no property needed), just as

window.pos = (x,y)

seems more natural than

window.SetPos(x ,y);

in these cases the work involved in changing the cell
value or the window position is going to make the
extra overhead of the property interface irrelevant.
>other day I decided I wanted what OP calls an
"indexed property" or "array property". Couldn't
figure out how to make a _property_ behave that way.
So I read a little bit about descriptors, and a
few minutes later I had an indexedproperty thing
that works just like property, except it gives
an indexed property! This is just too cool.

Why? For example, a Matrix should have a row[n]
property allowing things like

m.row[0] = m.row[1] + m.row[2]

Ok, you could do _that_ by just making row
an ordinary list of Row objects. But then
you'd have to say

m.row[0] = Row([1,2,3])

where I want to be able to say

m.row[0] = [1,2,3]

and have the Row created automatically.

One could make *row* an object with a custom __getitem__/__setitem__ in this case.
But then [see below]
>But I prefer to have as little magic as possible on my objects: if it says m.row[0] = [1,2,3] I
expect m.row[0] to actually *be* that list (whenever possible), and not any other object initialized
from the [1,2,3] arguments. (Maybe this is some overreaction against C++ "magic" constructors and such horrible things...)
Whatever - the idea here is that m.row[0] is going to walk and quack
exactly like that list would, but also do other things that the liist
can't do, like you can add two of them.

(When you say anobject.aprope rty = 2 you also expect aproperty to
be 2? But if aproperty is a property that's not necessarily so - this
seems like as much an argument against properties in general as
against my version. Or perversion, if you like.)
>_Also_ with these indexed properties my Matrix
can have m.row[j] and m.col[k] that look exactly
the same to a client - we don't want to store a
list of rows internally and also store the same
data in a list of columns. Too cool.

The same can be achieved having m.row and m.col be custom objects like I said above.
>Hmm, none of that's a valid excuse for a post here.
Um, right, here we go: Anyone see problems or
possible improvements with the implementation
of indexedproperty below?

Note that the property object (or your indexedproperty ) is a *class* attribute. That is, shared among all instances.
>class indexedproperty (object):
def __init__(self, getitem=None, setitem=None):
self.getitem = getitem
self.setitem = setitem

def __get__(self, obj, owner):
self.obj = obj
return self

Here is the problem. You can't store "obj" in "self" because it is shared among all instances. Your examples don't show any problem because all property accesses are immediately followed by a getitem access using the same object. Try this:

x = AClass()
y = AClass()
x.cell[0,0] = 1
print x.cell[1,1] # output: 0
y.cell[x.cell[0,0], x.cell[0,0]] = 2
print y.cell[1,1] # should be 2, still 0
print x.cell[1,1] # should still be 0, but changed, now 2
Eewps. I did realize that the "indexedpropert y" object was going to be
shared, but I thought this sort of problem would be taken care of by
the fact that self.obj was reset each time __get__ was called. I
guess not.

_A_ workaround would be to simply not have indexedproperti es
be class attributes, instead saying self.whatever =
indexedproprty( whatever) in __init__.
>A workaround would be to return another object in __get__ instead of self, which remembers the "obj" instance, or a closure, or...
But I don't really see the point, it's a lot easier to use another object for .cell (it's more clear, doesn't break encapsulation, divides responsabilitie s...)

class Matrix2x2(objec t):
def __init__(self):
self.cells = [[0,0], [0,0]]

def __setitem__(sel f, (row, col), value):
self.cells[row][col] = value

def __getitem__(sel f, (row, col)):
return self.cells[row][col]

class AClass(object):
def __init__(self):
self.cell = Matrix2x2()
Well, something like this is where I was before coming up with
the indexedproperty thing. Unless I'm missing something, which
has happened before, what you write above can't work, because
self.cell has to know what Matrix2x2 created it so it knows
what AClass instance to modify when it's modified. (No, we
can't just leave the state information in self.cells; think of the
case of a Matrix with a row[] property and also a col[]
property - they have to be modifying the data stored in
the owning matrix.)

So it would have to be more something like (untested,
I don't have Python on this machine right now)

class Matrix2x2(objec t):
def __init__(self, owner):
self.owner = owner

def __setitem__(sel f, (row, col), value):
self.owner.data[row][col] = value

def __getitem__(sel f, (row, col)):
return self.owner.data[row][col]

class AClass(object):
def __init__(self):
self.cell = Matrix2x2(self)
self.data = [[0, 0], [0, 0]]

(again, it doesn't have to be like that in this case,
but it does in the case where various "properties "
like cells are giving different sorts of access to the
same data, which data then has to be stored in AClass.)

And then that's the point to the indexedproperty ;
the code passing data back and forth doesn't need
to be rewritten with each property, it's all done
inside the implementation of the indexedproperty
class. I realized that I could just use object attributes
instead, but it seems to me that indexedproperty
encapsulates the data-passing protcol once and for
all instead of requiring it to be redone each time.

Thanks for the comments, especially for pointing out
the bug. Before doing this I reproduced a Python
implementation of "property". Gonna have to look
that up instead of figuring it out to make sure I got
it right, then look at it to see why property
doesn't have the same problem...
David C. Ullrich
Jun 27 '08 #4
(warning: it's a rather long message)

En Fri, 16 May 2008 12:58:46 -0300, David C. Ullrich
<du******@spryn et.comescribió:
On Thu, 15 May 2008 10:59:41 -0300, "Gabriel Genellina"
<ga*******@yaho o.com.arwrote:
>En Wed, 14 May 2008 18:15:41 -0300, David C. Ullrich
<du******@spry net.comescribió :
>>The other day I saw a thread where someone asked
about overrideable properties and nobody offered
the advice that properties are Bad. So maybe we've
got over that. I suppose properties could have
Bad consequences if a user doesn't know they exist
and think that a certain property of an object is
just an ordinary attribute. But that applies to
almost any aspect of any language.

Which "bad consequences" are you thinking of?

Didn't have anything specific in mind - there I was
just playing devil's advocate. I've seen a lot of people
here say things like "properties should only be used
when refactoring" without any explanation that I could
see of why properties were bad things. I was referring
to whatever problems they had in mind.
I suppose those people were talking about this usage:

def getfoo(self): return self._foo
def setfoo(self, value): self._foo = value
foo = property(getfoo , setfoo)

Just use a plain foo attribute instead. Almost nobody will notice the
difference, and it's faster, easier to maintain, easier to test, less
magic... But if you *do* have more to do besides handling the _foo
attribute, using a property is OK, at least for me. And from your other
comments, I can see it's fine for you too.
>>If a person comes from, say, Object Pascal (Delphi)
then properties are hard to live without. The

You should read the article "Python is not Java" if you haven't done it
yet.
http://dirtsimple.org/2004/12/python-is-not-java.html

I suspect you misunderstood my point there. I actually read that
article years ago. Been using Python for years. I'd never confuse
it with OP, I promise (luckily I don't know any Java and don't
intend to). I really didn't express what I meant very well - what
I should have said was more like "If you're accustomed to properties
from a language like OP they seem like a very useful addition to
Python".
Oh, sure. I missed them a lot until they became available in Python. And I
even wrote a fake property mixin class for Python 2.1 (horrible and slow!).
Now I understand better what you're saying.
window.pos = (x,y)

seems more natural than

window.SetPos(x ,y);

in these cases the work involved in changing the cell
value or the window position is going to make the
extra overhead of the property interface irrelevant.
Sure, that looks like a good candidate for using a property.
>But I prefer to have as little magic as possible on my objects: if it
says m.row[0] = [1,2,3] I
expect m.row[0] to actually *be* that list (whenever possible), and not
any other object initialized
from the [1,2,3] arguments. (Maybe this is some overreaction against
C++ "magic" constructors and such horrible things...)

Whatever - the idea here is that m.row[0] is going to walk and quack
exactly like that list would, but also do other things that the liist
can't do, like you can add two of them.

(When you say anobject.aprope rty = 2 you also expect aproperty to
be 2? But if aproperty is a property that's not necessarily so - this
seems like as much an argument against properties in general as
against my version. Or perversion, if you like.)
No, I don't necesarily expect it, but I try to maintain that behavior as
long as I can; I try to keep things simple and intuitive. This is a rather
used idiom:

items = foo.items = []
for x in someiterator:
if somecondition:
...
items.append(x)
...

That works fine if foo.items is items - but if items were a property that
holds its own internal list, the code above would be broken. In that case,
replacing a simple attribute with a property would *not* be equivalent;
and I try to follow the "principle of least astonishment" and avoid such
situations as long as possible.

(I think that in OP the equivalent of m.row[0] = [1,2,3] isn't very usual
- mostly because there isn't a list literal, I presume)
_A_ workaround would be to simply not have indexedproperti es
be class attributes, instead saying self.whatever =
indexedproprty( whatever) in __init__.
Unfortunately that doesn't work. Properties get their "magic" when
searched in the class namespace - a property set as an instance attribute
doesn't behave as a property at all, it's just an attribute as any other.
>class Matrix2x2(objec t):
def __init__(self):
self.cells = [[0,0], [0,0]]

def __setitem__(sel f, (row, col), value):
self.cells[row][col] = value

def __getitem__(sel f, (row, col)):
return self.cells[row][col]

class AClass(object):
def __init__(self):
self.cell = Matrix2x2()

Well, something like this is where I was before coming up with
the indexedproperty thing. Unless I'm missing something, which
has happened before, what you write above can't work, because
self.cell has to know what Matrix2x2 created it so it knows
what AClass instance to modify when it's modified. (No, we
can't just leave the state information in self.cells; think of the
case of a Matrix with a row[] property and also a col[]
property - they have to be modifying the data stored in
the owning matrix.)
The above class works fine in the simple cases I tested it - including the
bug involving two AClass instances. Adding "row" and "col" views is rather
simple:

class AClass(object):
def __init__(self):
self.cell = Matrix2x2()
self.row = ViewAsRow(self. cell)
self.col = ViewAsCol(self. cell)

class ViewAsRow(objec t):
def __init__(self, matrix):
self.cells = matrix.cells

def __getitem__(sel f, index):
return self.cells[index][:]

def __setitem__(sel f, index, row):
self.cells[index][:] = row

class ViewAsCol(objec t):
def __init__(self, matrix):
self.cells = matrix.cells

def __getitem__(sel f, index):
return [row[index] for row in self.cells]

def __setitem__(sel f, index, col):
for row, value in zip(self.cells, col):
row[index] = value

There is no need for the ViewAsCol nor ViewAsRow classes to know they're
being used inside an AClass instance. (A better design would avoid to use
matrix.cells - but I was constrained by the original Matrix2x2 design that
I didn't want to modify.)
(again, it doesn't have to be like that in this case,
but it does in the case where various "properties "
like cells are giving different sorts of access to the
same data, which data then has to be stored in AClass.)
But you may have many references to the *same* data and view it in
different ways - you don't have to walk thru the intermediate AClass
"container" because AClass doesn't "store" data; the data is "stored" in
the list itself, AClass instances only contain the name "cell" bound to
the Matrix2x2 object.

In OP terms, all objects in Python act like those inheriting from TObject,
not like basic types (numbers, char, string...). An important difference
is that Python takes care of automatic object deletion when they're no
longer used, but in OP you have to manage the object's lifetime yourself.
So in OP it is important *who* owns some object; and sharing a TList
instance -by example- isn't so frequent because when the list is freed all
its references become invalid (so one needs some kind of notification... )
In Python, on the other side, many objects may have a reference to the
same other one, like the Matrix above - it won't disappear until nobody
else references it. This sharing behavior may be a Good Thing or a Bad
Thing, depending on the circumstances. By example, the ViewAsRow class
above *could* return an actual list from the Matrix2x2 instance, but I
choose not to, to emphasize that it's a *view* of the underlying data
(else, modifications to the returned list would alter the data itself).
And then that's the point to the indexedproperty ;
the code passing data back and forth doesn't need
to be rewritten with each property, it's all done
inside the implementation of the indexedproperty
class. I realized that I could just use object attributes
instead, but it seems to me that indexedproperty
encapsulates the data-passing protcol once and for
all instead of requiring it to be redone each time.
I don't understand what you call "data-passing protocol"; as far as I can
tell, there is no data-passing, only names refering to the same and unique
object instance.

--
Gabriel Genellina

Jun 27 '08 #5
On Sat, 17 May 2008 00:27:31 -0300, "Gabriel Genellina"
<ga*******@yaho o.com.arwrote:
>(warning: it's a rather long message)

En Fri, 16 May 2008 12:58:46 -0300, David C. Ullrich
<du******@spry net.comescribió :
>On Thu, 15 May 2008 10:59:41 -0300, "Gabriel Genellina"
<ga*******@yah oo.com.arwrote:
>>En Wed, 14 May 2008 18:15:41 -0300, David C. Ullrich
<du******@spr ynet.comescribi ó:

The other day I saw a thread where someone asked
about overrideable properties and nobody offered
the advice that properties are Bad. So maybe we've
got over that. I suppose properties could have
Bad consequences if a user doesn't know they exist
and think that a certain property of an object is
just an ordinary attribute. But that applies to
almost any aspect of any language.

Which "bad consequences" are you thinking of?

Didn't have anything specific in mind - there I was
just playing devil's advocate. I've seen a lot of people
here say things like "properties should only be used
when refactoring" without any explanation that I could
see of why properties were bad things. I was referring
to whatever problems they had in mind.

I suppose those people were talking about this usage:

def getfoo(self): return self._foo
def setfoo(self, value): self._foo = value
foo = property(getfoo , setfoo)
Yeah. _If_ that's what I had in mind then telling me Python
is not Java would have been a great service.

If I recall correctly (maybe not, haven't done any OP in
a long time) this is one of many things that OP gets righter
than Java: you can have the "read" or "write" for a property
refer to a method _or_ to an actual field; in the second
case access compiles to the same thing as in direct field
access.
>Just use a plain foo attribute instead. Almost nobody will notice the
difference, and it's faster, easier to maintain, easier to test, less
magic... But if you *do* have more to do besides handling the _foo
attribute, using a property is OK, at least for me. And from your other
comments, I can see it's fine for you too.
>>>If a person comes from, say, Object Pascal (Delphi)
then properties are hard to live without. The

You should read the article "Python is not Java" if you haven't done it
yet.
http://dirtsimple.org/2004/12/python-is-not-java.html

I suspect you misunderstood my point there. I actually read that
article years ago. Been using Python for years. I'd never confuse
it with OP, I promise (luckily I don't know any Java and don't
intend to). I really didn't express what I meant very well - what
I should have said was more like "If you're accustomed to properties
from a language like OP they seem like a very useful addition to
Python".

Oh, sure. I missed them a lot until they became available in Python. And I
even wrote a fake property mixin class for Python 2.1 (horrible and slow!).
Now I understand better what you're saying.
> window.pos = (x,y)

seems more natural than

window.SetPos(x ,y);

in these cases the work involved in changing the cell
value or the window position is going to make the
extra overhead of the property interface irrelevant.

Sure, that looks like a good candidate for using a property.
>>But I prefer to have as little magic as possible on my objects: if it
says m.row[0] = [1,2,3] I
expect m.row[0] to actually *be* that list (whenever possible), and not
any other object initialized
from the [1,2,3] arguments. (Maybe this is some overreaction against
C++ "magic" constructors and such horrible things...)

Whatever - the idea here is that m.row[0] is going to walk and quack
exactly like that list would, but also do other things that the liist
can't do, like you can add two of them.

(When you say anobject.aprope rty = 2 you also expect aproperty to
be 2? But if aproperty is a property that's not necessarily so - this
seems like as much an argument against properties in general as
against my version. Or perversion, if you like.)

No, I don't necesarily expect it, but I try to maintain that behavior as
long as I can; I try to keep things simple and intuitive. This is a rather
used idiom:

items = foo.items = []
for x in someiterator:
if somecondition:
...
items.append(x)
...

That works fine if foo.items is items - but if items were a property that
holds its own internal list, the code above would be broken. In that case,
replacing a simple attribute with a property would *not* be equivalent;
and I try to follow the "principle of least astonishment" and avoid such
situations as long as possible.
Right. Except that for the implementation I have in mind this
moring that code will work just fine. foo.items is going to be
a property of foo, so foo.items = [] will ...

Um. I just realized I have no idea what happens if
p = property(getp, setp) and later you say

(*) avariable = x.p = avalue

I'd hope that this first calls x.setp(avalue) and then
executes avariable = s.getp(). One second please,
while we fire up the other machine...

No, it doesn't do that.

Again, this doesn't have anything to do with lists,
it seems an unfortunate astonishment regarding
properties in general. If p is an attribute then the
effect of (*) is the same as x.p=value; avariable = x.p
but if p is a property that's not so.

In the implementation I have in mind I don't see
how there's going to be any astonishment other
than astonishments that can arise with properties
in general.

Ok, that was your point - even if p is a property
you'd prefer that x.p = value store value and
possibly do other things as well, instead of
storing something other than value.

(I _have_ been astonished at how unastonishing
my Rows are, for example I was surprised to see
that

def __add__(self, other):
return Row([x + y for x, y in zip(self, other)])

worked as hoped if self is a Row and other is a
Row _or_ a list.)

Anyway, my m.rows[j] can't be a list, because
I want to be able to say things like
m.rows[0] += c*m.rows[2]. Allowing
m.rows[j] = [1,2,3] seems convenient, while
requiring m.rows[j] = Row([1,2,3]) fixes
this problem. Hmm.
>(I think that in OP the equivalent of m.row[0] = [1,2,3] isn't very usual
- mostly because there isn't a list literal, I presume)
>_A_ workaround would be to simply not have indexedproperti es
be class attributes, instead saying self.whatever =
indexedproprty (whatever) in __init__.

Unfortunatel y that doesn't work.
As I found when I tried it. Then I read the docs again a little
more closely...
>Properties get their "magic" when
searched in the class namespace - a property set as an instance attribute
doesn't behave as a property at all, it's just an attribute as any other.
>>class Matrix2x2(objec t):
def __init__(self):
self.cells = [[0,0], [0,0]]

def __setitem__(sel f, (row, col), value):
self.cells[row][col] = value

def __getitem__(sel f, (row, col)):
return self.cells[row][col]

class AClass(object):
def __init__(self):
self.cell = Matrix2x2()

Well, something like this is where I was before coming up with
the indexedproperty thing. Unless I'm missing something, which
has happened before, what you write above can't work, because
self.cell has to know what Matrix2x2 created it so it knows
what AClass instance to modify when it's modified. (No, we
can't just leave the state information in self.cells; think of the
case of a Matrix with a row[] property and also a col[]
property - they have to be modifying the data stored in
the owning matrix.)

The above class works fine in the simple cases I tested it - including the
bug involving two AClass instances. Adding "row" and "col" views is rather
simple:

class AClass(object):
def __init__(self):
self.cell = Matrix2x2()
self.row = ViewAsRow(self. cell)
self.col = ViewAsCol(self. cell)

class ViewAsRow(objec t):
def __init__(self, matrix):
self.cells = matrix.cells

def __getitem__(sel f, index):
return self.cells[index][:]

def __setitem__(sel f, index, row):
self.cells[index][:] = row

class ViewAsCol(objec t):
def __init__(self, matrix):
self.cells = matrix.cells

def __getitem__(sel f, index):
return [row[index] for row in self.cells]

def __setitem__(sel f, index, col):
for row, value in zip(self.cells, col):
row[index] = value

There is no need for the ViewAsCol nor ViewAsRow classes to know they're
being used inside an AClass instance.
Well, no. But they do need to preserve that reference to that
Matrix2x2 object.
>(A better design would avoid to use
matrix.cells - but I was constrained by the original Matrix2x2 design that
I didn't want to modify.)
>(again, it doesn't have to be like that in this case,
but it does in the case where various "properties "
like cells are giving different sorts of access to the
same data, which data then has to be stored in AClass.)

But you may have many references to the *same* data and view it in
different ways - you don't have to walk thru the intermediate AClass
"container" because AClass doesn't "store" data; the data is "stored" in
the list itself, AClass instances only contain the name "cell" bound to
the Matrix2x2 object.
Well of course. My point was just that it had to be somewhat
more complicated than the original code you gave if we wanted
to have two views of the same data.
>In OP terms, all objects in Python act like those inheriting from TObject,
not like basic types (numbers, char, string...). An important difference
is that Python takes care of automatic object deletion when they're no
longer used, but in OP you have to manage the object's lifetime yourself.
So in OP it is important *who* owns some object; and sharing a TList
instance -by example- isn't so frequent because when the list is freed all
its references become invalid (so one needs some kind of notification... )
In Python, on the other side, many objects may have a reference to the
same other one, like the Matrix above - it won't disappear until nobody
else references it. This sharing behavior may be a Good Thing or a Bad
Thing, depending on the circumstances. By example, the ViewAsRow class
above *could* return an actual list from the Matrix2x2 instance, but I
choose not to, to emphasize that it's a *view* of the underlying data
(else, modifications to the returned list would alter the data itself).
>And then that's the point to the indexedproperty ;
the code passing data back and forth doesn't need
to be rewritten with each property, it's all done
inside the implementation of the indexedproperty
class. I realized that I could just use object attributes
instead, but it seems to me that indexedproperty
encapsulates the data-passing protcol once and for
all instead of requiring it to be redone each time.

I don't understand what you call "data-passing protocol"; as far as I can
tell, there is no data-passing, only names refering to the same and unique
object instance.
I didn't say what I meant very well. Your ViewAsRow does require
a reference to data held elsewhere; that reference has to be passed
in the constructor and used in __get/setitem__.

I think what I should do is set something up like your thing
above (except that in fact there's no reason for AClass,
it's actually Matrix I care about, AClass just crept into the
discussion because it was in the trivial example in the original),
modified so it stores a list of Row objects instead of a list of
lists.

Then concoct an indexedattribut e class (ignoring descriptors)
that lets me say

class Matrix2x2(objec t)
def __init__(self, data):
...
self.rows = indexedattribut e(self.getrow, self.setrow)
self.cols = indexedattribut e(self.getcol, self.setcol)

def getrow(self, index)
...

and then compare the two. I suspect that the second
Matrx2x2 is going to be simpler because of things
handled automatically by the indexedattribut e class
(counting the code in that class as part of the
"complexity " doesn't count, since I only write that
class once and get to use it for my matrices and
also my wxGrids...)

Don't hold your breath, I have other things to do
in the next few days. Thanks again for pointing
out the bug in the original. (It might never have
come up - I don't see why I'd use a cell in one
matrix as an index to another matrix. But regardless
it makes the original totally unacceptable, and
if it _did_ come up when I was using it it would
have taken me some time to figure out what the
problem was...)
David C. Ullrich
Jun 27 '08 #6
In article <hj************ *************** *****@4ax.com>,
du******@spryne t.com says...
window.pos = (x,y)

seems more natural than

window.SetPos(x ,y);
Yes, and to assign a row in a matrix I'd also like to use either tuples
or lists on the right side.
def __add__(self, other):
return Row([x + y for x, y in zip(self, other)])

worked as hoped if self is a Row and other is a
Row _or_ a list.)

Anyway, my m.rows[j] can't be a list, because
I want to be able to say things like
m.rows[0] += c*m.rows[2]. Allowing
m.rows[j] = [1,2,3] seems convenient, while
requiring m.rows[j] = Row([1,2,3]) fixes
this problem. Hmm.
I'm not sure how far you'd go along with Gabriel's idea of decoupling
views from data but I think there isn't even a need for using a matrix
as the underlying data type. Why not use a flat list and compute matrix
positions according to a row or column adressing scheme on the fly?

P.

Jun 27 '08 #7
On Sun, 18 May 2008 08:50:23 +0200, pataphor <pa******@gmail .com>
wrote:
>In article <hj************ *************** *****@4ax.com>,
du******@spryn et.com says...
> window.pos = (x,y)

seems more natural than

window.SetPos(x ,y);

Yes, and to assign a row in a matrix I'd also like to use either tuples
or lists on the right side.
Heh - in the current (flawed) implementation you can
say m.row[0] = 'Hello'; m.row[1]= 'World!' .Not that I see why
you'd want to, but that happened in the test code just to
check that things were as general as I wanted - sure enough
m.row[0] + m.row[1] comes out to ['HW', 'eo', 'lr', ''ld', 'o!'].
> def __add__(self, other):
return Row([x + y for x, y in zip(self, other)])

worked as hoped if self is a Row and other is a
Row _or_ a list.)

Anyway, my m.rows[j] can't be a list, because
I want to be able to say things like
m.rows[0] += c*m.rows[2]. Allowing
m.rows[j] = [1,2,3] seems convenient, while
requiring m.rows[j] = Row([1,2,3]) fixes
this problem. Hmm.

I'm not sure how far you'd go along with Gabriel's idea of decoupling
views from data but I think there isn't even a need for using a matrix
as the underlying data type. Why not use a flat list and compute matrix
positions according to a row or column adressing scheme on the fly?
Is there some reason that would be better? It would make a lot
of the code more complicated. Ok, it would require only one
bit of added code, I suppose, but I don't see the plus side.

Hmm. It might actually _reduce_ the total amount of code,
since the code to access columns has to exist anyway and
rows could use the same code as columns with different
"start" and "skip". And come to think of it rows and
columns could be obtained just with a slice of the data.
So column access might even be more efficient. But I
expect that row access will happen a lot more often
than column access.
>P.
David C. Ullrich
Jun 27 '08 #8
In article <dt************ *************** *****@4ax.com>,
du******@spryne t.com says...
Is there some reason that would be better? It would make a lot
of the code more complicated. Ok, it would require only one
bit of added code, I suppose, but I don't see the plus side.
The plus side is you give up an untenable position :-) And to address an
item in a matrix costs two lookups, row and column, while an array needs
only one.

P.
Jun 27 '08 #9
On Mon, 19 May 2008 06:29:18 -0500
David C. Ullrich <du******@spryn et.comwrote:
Maybe you could be more specific? Various "positions" I've
taken in all this may well be untenable, but I can't think
of any that have anything to do with whether the data should
be a single list instead of a list of lists.
What's 'untenable' (hey, I tried to get away with a smiley, remember)
is that a matrix is a list of rows. Suppose you do the transpose trick
with the zip(*M) routine, now it's a list of columns. Both views are
equal, there is no getting around the fact that you're holding an
unnatural predisposition towards seeing the matrix as a list of rows,
which it is most definitely not ...

I was holding the brakes for this argument because I realize it's
intuitive and also because Gabriel seems to want a list stay a list if
he assigns something a list. But that's untenable too. Suppose you
assign a column to a list? The list is torn to shreds and placed over
multiple rows.
(The only way I can parse this to make it relevant is to
assume that the position you're referring to is that a
list of lists is better than a single list. If so: First, I
haven't said that it was. Second, saying "B is untenable"
is not much of an answer when someone asks why you
say A is better than B.)
Yes, it was not much of an answer but I was afraid of ending up in
this quagmire. I now see that it is unavoidable anyway if I want to
explain myself. Why couldn't you just see it the same way as me and
leave it at that without waking up all the creatures of hell :-)
And to address an
item in a matrix costs two lookups, row and column, while an array
needs only one.

The phrase "premature optimization" springs to mind.
Well, I really liked your slicing idea ...
This is _Python_ we're talking about. Supposing you're right that
doing two lookups _in Python_ is faster than doing one lookup
plus the calculuation col + row*width _in Python_, it can't
make enough difference to matter. In the sort of application I
have in mind things already happen "instantaneousl y".
The computation is almost certainly faster. Lookups are expensive.
However I concede the point because we're not supposed to worry about
such stuff. But it *is* a simpler format.
The point is not to improve on NumPy. Trying to improve on
NumPy in pure Python code would be silly - if I wanted
optimized large matrices I'd _use_ NumPy. The point is just
to give a simple "intuitive" way to manipulate rows and
columns in small matrices.
Yes, me too. This is all about intuition.
So I'm not looking ahead to the future, things are not
scalable? The thing is not _supposed_ to scale up to
large matricies. If a person were dealing with large
matricies then almost all of it would need to be
rewritten (and if a person were dealing with really
large matrices then trying to do the thing in pure
Python would be silly in the first place, and insisting
on being able to write things like "m.row[0] =
m.row[1] + m.row[2]" could very well be a totally
wrong approach to begin with - I'd figure out the
operations I expected to need to do and write functions
to do them.)
The reason why I am interested in this is that since I was writing
sudoku algorithms some time ago I have been looking for ways to interact
with data according to different views. I want the data to update even
when I have made changes to them according to another view. In my case
things are even more complex than they are with matrices because I
tend to view sudoku as subcases of binary cubes. Imagine a 3d 9*9*9
chessboard and try to place 81 non-threatening rooks in it. This is not
quite a solution to a sudoku but every sudoku is also a solution to this
problem.

One of the solution strategies I thought of was forgetting about the 3d
binary cube's content at all, and just update row, column and file
totals (I start with a 'filled' cube and wipe away fields that are
covered by the 'rooks') to drive the optimization. Somehow this seems
possible even though I do not use the cube itself anymore. It just
exists as a figment of my imagination but still it defines the context.

I hope you understand how this was driving me crazy and why I would be
more than happy to return to a safe and sound, actually 'existing' cube,
if only there was a way to access rows, columns and files (for example
sum their elements) as shared data. In the end I realized that
everything I was doing was an abstraction anyway and if that is the
case why not use the simplest possible representation for the data and
let any matrices, rows, columns, files, cubes and so on exist somewhere
higher up in the levels of abstraction of the code.
Really. In one of the intended applications the matrix
entries are going to be home-made Rationals. Just
adding two of those guys takes a long time. It's
still more than fast enough for the intended application,
but [oh, never mind.
Too late :-)
Sorry about the argumentative tone - I _would_ like
to know which "untenable position" you're referring to...
No, it's no problem. Thanks again for bringing this up. Once I overcame
my initial resistance to bringing up all this old (for me) issues I was
more than happy to share intuitions. I hope this somehow results in a
shared data type. Even just a matrix_with_a_v iew would be very nice.

P.
Jun 27 '08 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

0
1534
by: Michael Bourgon | last post by:
Here's something I found a few months ago, and it seems to come in handy pretty often, so I figured I'd share. Disclaimer: you are modifying a SYSTEM TABLE. This may not work in the next version of SQL Server. When you right click on a Database in the Enterprise Manager and choose Properties, in order to show the last backup time, it has to go through MSDB and find the last backup date for the database. Unless you're carefully...
2
8964
by: Petra | last post by:
Hi I have problem reading the userPassword - Property from an Entry with the person-Schema using Microsoft Dotnet. I use DirectoryServices library and LDAP in my class. The code I used is as following: DirectoryEntry de = new DirectoryEntry,gAllgemein.IBMLDAPServerPathBenutzer,"cn=root","ldap",AuthenticationTypes.None); String ergebnis = aktBenutzer.Properties.ToString();
1
1537
by: Phill. W | last post by:
I have a number of properties on a UserControl that are logically related to one another and do a specific job. What I'd /like/ to do is to have these properties available in the Forms Designer, "grouped" together under a single "sub-heading", in the same way as, for example, the standard Font, Location and Size properties. I've wandered around the Browsable and DesignerSerializationVisibility Attributes but the "nearest" I've got so...
0
1465
by: VB Newbie | last post by:
I am creating a user control containing a combobox using VB.NET(2003) I want to add 2 public properties "DataSource" and "Items" like the "System.Windows.Forms.ComboBox" here is my code, but it doesn't work. What's wrong with it? Public Property cboDataSource() As Object Get Return Me.cbo.DataSource 'cbo is my combobox End Get
5
6903
by: VB Newbie | last post by:
I am creating a user control containing a combobox using VB.NET(2003) I want to add 2 public properties "DataSource" and "Items" like the "System.Windows.Forms.ComboBox" here is my code, but it doesn't work. What's wrong with it? Public Property cboDataSource() As Object Get Return Me.cbo.DataSource 'cbo is my combobox End Get
1
4760
by: DiegoMx | last post by:
I'm having a problem with "a:visited" properties overriding "a:hover" ones - here's the relevant part of my CSS: a.barra { position:absolute; top:30px; font-family:century gothic; padding:10px; font-size:12pt; font-weight:bold; color:#4855A9;
3
1761
by: EYIII | last post by:
Is it possible to retrieve the "created by" identity and "modified by" identity for a file (e.g. word doc, .pdf, report, etc) using .NET?
1
1232
by: =?Utf-8?B?QXNhZg==?= | last post by:
Hi, I have just installed VS.NET 2008 Pro. According to Scott Blog at http://weblogs.asp.net/scottgu/archive/2007/07/25/vs-2008-web-designer-and-css-support.aspx I can't find how to add the "Manage Styles" and "CSS Properties" to Solution Explorer. * Also I have VS.NET 2005 already installed period the installation of
1
1396
by: Dom | last post by:
I had a program that worked fine, and made good use of Properties.Settings. I needed a second program that was similar to it, so I just canabalized it. I made very minor changes, perhaps the biggest was changing the namespace, since the old one no longer made sense. All of a sudden, I can't get to Properties.Settings. When I type "Properties" in my code, the intellisense window does not list it. Also, when I start a new class, the...
0
8752
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
9257
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
1
9179
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
9116
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
1
6702
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
4519
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
0
4784
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
3228
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
3
2157
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.