You can't do what you originally wanted to do (ie, have two different __iter__ methods) because it doesn't make any sense. But you can fake it using the mapping protocol (see below).
However before going into that, if you really want to cast to a dict, have a look at this answer for some better options.
My suggestion is to either:
- Do what was suggested in the other answer and utilize
namedtuple, which gives you the _asdict() method "for free". - Implement the class utilizing the mapping protocol (as explained in the previous link above). If you do that, you can circumvent the
__iter__ method entirely when casting to dict.
You might do that like this; however this is a little bit odd:
class Point3: _fields = tuple("xyz") def __init__(self, x, y, z): self.x = x self.y = y self.z = z def __iter__(self): for f in self._fields: yield getattr(self, f) def keys(self): return self._fields def __getitem__(self, i): if i in self._fields: return getattr(self, i) raise KeyError("{!r} is not a valid field".format(i))
With the above, the dict is created using the keys() and __getitem__() rather than __iter__:
>>> dict(Point3(1, 2, 3)) {'x': 1, 'y': 2, 'z': 3}
Using the mapping protocol can also come in handy because you can "cast"- that is, unpack your object in the form of keyword arguments- to any other type that accepts the same field names as keyword arguments, e.g.:
point= XYZer(**point3_instance)
For other people (not the OP) who are able to benefit from the latest version of Python 3 (3.7): I highly recommend using the dataclasses module:
from dataclasses import dataclass, asdict, astuple @dataclass class Point: x: float y: float z: float
Use it like so:
>>> p = Point(1,2,3) >>> asdict(p) {'x': 1, 'y': 2, 'z': 3} >>> astuple(p) (1, 2, 3)
.to_tuple()and.to_dict()that convert to tuple and dict in whatever ways you want?tupleand used.to_dict()for creating dictionaries.__iter__).Pointfromdict(ornamedtuple) and usetuple(p.items())wherever necessary.