"indexed properties"...

David C. Ullrich dullrich at sprynet.com
Wed May 14 17:15:41 EDT 2008


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: "indexedproperty" works more or less
like "property" except it gives what in Object Pascal
would be an "indexed property". See the 
__name__="__main__" section below for a demo

"""

class WriteOnlyIP(Exception):
  def __str__(self): 
    return """

indexed property is write-only

"""

class ReadOnlyIP(Exception):
  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__(self, index):
    if self.getitem:
      return self.getitem(self.obj, index)
    else:
      raise WriteOnlyIP

  def __setitem__(self, index, value):
    if self.setitem:
      self.setitem(self.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



More information about the Python-list mailing list