two new wrinkles to the general class!

syd syd.diamond at gmail.com
Wed Nov 3 21:57:18 EST 2004


Recap: For a general "container" type class, I wanted to grab another
instance of this class based upon attributes of the items contained
within.  Eg, for an illustrative library of nations, I want to be able
to do operations like
library.get_continent('Europe').get_size('medium').

A good sol'n: Use __getattr__ to intercept the "get_continent"
on-the-fly and split it into "get_" (the function I want) and
"continent" (the attribute I want to select for).  By using the
built-in getattr(), I can grab the value of this attribute in each
component object in my library.  Thus, each "get_foo" does not need to
be hard coded.

Some things I learned: subclass object -- ie, "class Library(object):"
-- for post python-2.2 for a variety of reasons including better
agreement with upcoming versions.  Also, __getattr__ intercepts *after*
looking in __dict__, and __getattribute__ (when you've subclassed
object) intercepts *before*.

First off, thanks to everyone for helping me to this point!  Looking
forward, I've got two other related issues:

>>1) Because I've got many "container" type classes, the best route
would obviously seem be to subclass each to a general "container".  Ie,

class Library_A(Container): ...
class Library_B(Container): ...

The problem: in the current setup, a library_a.get_continent('Europe')
would pass back an instance of Container and *not* Library_A.  The
obvious implication is that any attributes/method specific to Library_A
are gone.  (In the code at the bottom, we'd lose the "defineNation"
method).  My (bad?) remedy: when you create library_a, give it a
"blankSelf" attribute that it can deepcopy before you pass it back.
Within the __getattr__:

def get(value):
container=copy.deepcopy(self.blankSelf)
if self.isNotEmpty()==True:
for item in self.list:
if getattr(item,attribute)==value:
container.add(item)
return container

This hard-code / deepcopy does not seem ideal!

>>2) I've got a bunch of "get_foo" type things where "foo" is not an
attribute of the component class but rather a method.  In our
illustrative example, we could imagine a
"get_nameLongerThanFourLetters" where we add the component nation class
when "nation.is_nameLongerThanFourLetters()==True".

Above, we use getattr() to grab the attribute on-the-fly.  Can we grab
a method on-the-fly, too?  Ie, when we see "get_foo", use the "is_foo"
criteria from the class below.

I hope this makes sense.  In response to Andrea's comments, I'll state
the obvious: I'm fairly new to the intricacies of Python class
structures :).  I'm a student (non CS), and my year or so of Python
experience before this project has been "functional" (alternatively:
quick hacks).  But I love the language!  And I want to learn!  Thanks
again, everyone.

Appendix: Here's the code for the illustrative example...

#!/usr/bin/python
import copy
class Container(object):
def __init__(self,list=None,blankSelf=None):
self.list=list
self.blankSelf=blankSelf
def __getattr__(self,name):
def get(value):
container=copy.deepcopy(self.blankSelf)
if self.isNotEmpty()==True:
for item in self.list:
if getattr(item,attribute)==value:
container.add(item)
return container
def getMethodAndAttribute():
if name.startswith('get_'):
return 'get',name[4:]
else:
return '',''
method,attribute=getMethodAndAttribute()
if method=='get': return get
else: raise AttributeError,name
def add(self,item):
try: self.list.append(item)
except: self.list=[item]
def count(self):
if type(self.list)==type([]): return len(self.list)
else: return 0
def getNameList(self):
outList=[]
for nation in self.list:
outList.append(nation.name)
return outList
def isNotEmpty(self):
if self.count()>0: return True
else: return False
class Library(Container):
def __init__(self):
pass
def defineNation(self,name,continent,size):
nation=Library.Nation()
nation.name=name
nation.continent=continent
nation.size=size
self.add(nation)
class Nation:
def __init__(self,name=None,continent=None,size=None):
self.name=name # eg, Spain
self.continent=continent # eg, Europe
self.size=size # eg, medium

library=Library()
library.blankSelf=Library()
library.defineNation('Spain','Europe','medium')
library.defineNation('USA','NorthAmerica','large')
library.defineNation('Luxembourg','Europe','small')
library.defineNation('Portugal','Europe','medium')

print library.getNameList()
print library.get_continent('Europe').getNameList()




More information about the Python-list mailing list