9

In a defined object some values are kept in a dict, and I want to iterate over the contents in that dict as when referring to a plain dict, thus with directly access using [], and loop using e.g. .items(). Code structure is:

class Klass: def __init__(self, values): self.values = values self.more = None def __getitem__(self, name): return self.values[name] def __iter__(self): pass # TBD[How to make this ?] d = {'alfa': 1, 'bravo': 2, 'charlie': 3} k = Klass(d) for key in k: print(key) # Expected to print keys from self.values for (key, value) in k.items(): print(key, value) # Expected to print key and value from self.values for key in k.keys(): print(key) # Expected to print key from self.values for value in k.values(): print(value) # Expected to print value from self.values 

How to write the __iter__ and, other required methods, so this kind of access is possible through an instance of Klass?

4
  • for item in self.values: yield item? Commented Mar 13, 2015 at 13:19
  • The intention with OOP is to hide specific implementation, so direct reference to instance attribute .values should be avoided.. Commented Mar 13, 2015 at 13:21
  • 1
    @EquipDev: within the implementation you are still going to have to rely on your own state. Torxed was proposing a implementation for __iter__, making it a generator function. Not needed here, not with iter(), however. Commented Mar 13, 2015 at 13:23
  • @MartijnPieters: Now I see; yes that adheres to OOP principles. Thanks for pointing that out. Commented Mar 13, 2015 at 13:28

3 Answers 3

19

You'll have to implement the .keys(), .values() and .items() methods yourself; together with __iter__ they can all delegate the actual work to the self.values() dictionary:

class Klass: def __init__(self, values): self._values = values self.more = None def __getitem__(self, name): return self._values[name] def __iter__(self): return iter(self._values) def keys(self): return self._values.keys() def items(self): return self._values.items() def values(self): return self._values.values() 

I renamed the attribute to avoid masking the .values() method.

The easiest way to delegate __iter__ to iteration over the dictionary (by key) is to use the iter() function to get an iterator for the dictionary object.

To be explicit: __iter__ plays no role in how .keys(), .values() and .items() are handled; the latter are just more methods.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for the help, and for renaming values to _values; it was a bad choice of name when having to implement the values method.
There's no need to implement .keys() etc. Just subclass from collections.abc.Mapping.
@Kevin: yup, that's the next step. The fact that collections.abc.Mapping then implements those methods doesn't diminishes the fact that those methods need to be implemented.
3
 class Klass(dict): def __init__(self, *arg, **kw): super(Klass, self).__init__(*arg, **kw) self.choosebettername = super(Klass, self).keys() def __iter__(self): return iter(self.choosebettername) def keys(self): return self.choosebettername def itervalues(self): return (self[key] for key in self) d = {'alfa': 1, 'bravo': 2, 'charlie': 3} k = Klass(d) for key in k: print(key) # Expected to print keys from self.values for (key, value) in k.items(): print(key, value) # Expected to print key and value from self.values for key in k.keys(): print(key) # Expected to print key from self.values print(k.values()) for value in k.values(): print(value) # Expected to print value from self.values 

Comments

0

Contrary to the dict behavior, one might simply let the default iteration method be the items' dictionary view:

class Klass: def __init__(self, values): self._values = values def __getitem__(self, name): return self._values[name] def __iter__(self): iter(self._values.items()) klass = Klass({'alfa': 1, 'bravo': 2, 'charlie': 3}) for key, value in klass: print(key, value) 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.