views:

558

answers:

3

How can I iterate over a list of all classes loaded in memory? I'm thinking of doing it for a backup, looking for all classes inheriting from db.Model (Google App Engine).

Thanks, Neal Walters

+2  A: 

Classes are defined in modules. Modules are created by an import statement.

Modules are simply dictionaries. If you want, you can use the dir(x) function on a module named x

Or you can use x.__dict__ on a module named x.

S.Lott
Thanks - see my answer with code.
NealWalters
+5  A: 

In "normal" Python, you can reach all objects via the gc.getobjects() function of the gc standard library module; it's then very easy to loop on them, checking which one are classes (rather than instances or anything else -- I do believe you mean instances of classes, but you can very easily get the classes themselves too if that's really what you want), etc.

Unfortunately, the gc module in App Engine does NOT implement getobjects -- which makes it extremely difficult to reach ALL classes. For example, a class created by calling:

def makeaclass():
  class sic(object): pass
  return sic

and hidden into a list somewhere, IS going to be very difficult to reach.

But fortunately, since you say in your question's text that you only care about subclasses of db.Model, that's even easier than gc would allow:

for amodel in db.Model.__subclasses__():
   ...

Just make sure you explicitly ignore such classes you don't care about, such as Expando;-).

Note that this DOES give you only and exactly the CLASSES, not the instances -- there is no similarly easy shortcut if those are what you're really after!

Alex Martelli
Thanks - see my answer with code.
NealWalters
A: 

Based on S.Lott's response: This works if I omit the "if issubclass" except then I get classes I don't want.

  import dbModels 
  self.response.out.write("<br/><br/>Class Names:</br/>")
  for item in dbModels.__dict__:
      if issubclass(item, db.Model):
         self.response.out.write("<br/>" + item)

The above gives error:

TypeError: issubclass() arg 1 must be a class

So it wants a classname as a parm, not an object name apparently.

Based on Alex's answer, this worked great:

  self.response.out.write("<br/><br/>Class Names Inheriting from db.Model:</br/>")
  for item in db.Model.__subclasses__():
       self.response.out.write("<br/>" + item.__name__)

Thanks to both!

Neal

NealWalters
`dbModels` no doubt has SOME things that are not classes; filter them out (see standard library module `inspect`) OR put a try/except around your `if issubclass` statement. **And**, do accept the answer you've found most helpful (using the checkbox-shaped icon under the number of upvotes for that answer): your 0% accept rate proves you just don't get this crucial aspect of SO etiquette and will eventually convince people to stop answering you!-)
Alex Martelli
I never even noticed that checkbox before. Many things in Stackoverflow are still not obvious to beginners. I thought clicking the up-arrow was the only nice thing to do.
NealWalters