2

I'm getting returned a list with objects that have multiple attributes like so:

results = q.fetch(5)
for p in results:
    print "%s %s, %d inches tall" % (p.first_name, p.last_name, p.height

Is it possible to iterate over these attributes so I can do something like for x in p. I want to check the value of each one, but I don't want to create a huge block of IF statements.

joslinm
  • 7,845
  • 6
  • 49
  • 72
  • 4
    It looks like a questionable design to me. It might be better to redesign your program so that you don't need to do this. – Mark Byers Jan 08 '11 at 00:46

4 Answers4

6

I warn against doing this. There are rare exceptions where it's warranted, but almost all the time it's better avoiding this sort of hackish solution. If you want to though, you could use vars() to get a dictionary of attributes and iterate through it. As @Nick points out below, App Engine uses properties instead of values to define its members so you have to use getattr() to get their values.

results = q.fetch(5)
for p in results:
    for attribute in vars(p).keys()
        print '%s = %s' % (attribute, str(getattr(p, attribute)))

Demonstration of what vars() does:

>>> class A:
...     def __init__(self, a, b):
...         self.a = a
...         self.b = b
... 
>>> a = A(1, 2)
>>> vars(a)
{'a': 1, 'b': 2}
>>> for attribute in vars(a).keys():
...     print '%s = %s' % (attribute, str(getattr(a, attribute)))
... 
a = 1
b = 2
moinudin
  • 134,091
  • 45
  • 190
  • 216
  • This won't work on App Engine, because entity members are properties (descriptors), not just values. – Nick Johnson Jan 12 '11 at 00:13
  • @Nick Thanks for pointing it out. I've barely used AE. I think this is still worth sticking around for the general python case (IIRC, you can't delete an accepted answer anyway). I've added a note on top though. – moinudin Jan 12 '11 at 00:20
  • @marcog Fair enough. A version that works in general would be to iterate over the keys of vars(), and call getattr(a, k) on each. It'll iterate over methods and other unwanted cruft in any object though, of course. – Nick Johnson Jan 12 '11 at 00:26
  • @marcog It ought to, yes. App Engine models are constructed using descriptors, so anything that works on descriptors will work on them. It's probably better practice anyway, since the current snippet bypasses the descriptor protocol, which is probably not the desired outcome. – Nick Johnson Jan 12 '11 at 04:58
  • @Nick Thanks, you just taught me a good practice. :) Updated my answer with this. – moinudin Jan 12 '11 at 09:55
3

You can subclass the original variable type, and define your own cunning iter(self) function, to get what you want. e.g. to change the way a dictionary iterates:-

>>> class mydict(dict):
...    def __iter__(self):
...      for i in self.items():
...          yield i
... 
>>> x = mydict( {'a' : 1, 'b':2 } )
>>> for i in x:
...   print i
... 
('a', 1)
('b', 2)
Alex Leach
  • 1,199
  • 2
  • 12
  • 26
  • I've given a more extensive example of making an object iterable at this page:- http://stackoverflow.com/questions/4642219/testing-hsl-colours-ideally-avoiding-red-adjacent-to-green-common-colour-blindn – Alex Leach Jan 10 '11 at 09:29
1

To get a list of properties on a model class, call Model.properties() (or instance.properties() - it's a class method). This returns a dictionary mapping property names to Property class instances; you can fetch the value of the properties by doing getattr(instance, name).

If you're using Expando, there's also instance.dynamic_properties(), which returns a list of dynamically defined properties on that object.

Nick Johnson
  • 100,655
  • 16
  • 128
  • 198
0

With the assumption that the object you get back from q.fetch(5) having a __dict__ attribute, you can simply use pprint to display your information.

>>> import pprint
>>> results = q.fetch(5)
>>> pprint.pprint(results.__dict__())

Or alternatively, if it has something that can be converted to a dictionary, a similar notation would work

>>> pprint.pprint(dict(results.dict_like_property))

I would suggest though, that this isn't a good approach to take, but it does hold for debugging code easily.

aodj
  • 2,163
  • 1
  • 12
  • 13