I am learning OOP python using the Markana tutorial and I’m having some trouble with Lab 16.8. (Among some other troubles) I can’t get the __iter__ method correct. My method looks like this:
def __iter__(self):
for e in self.l_investments:
yield e
Here is my code (and the result of running it): http://hastebin.com/wayuwakode.py
Here is the result that should appear:
>>> 'GOOG' in p
True
I get:
>>> 'GOOG' in p
False
p is an instance of the class Portfolio(). ‘GOOG’ is the .name property of an instance of the Investment() object. p contains a list and a dictionary of Investment() instances.
I can change my __iter__ method to yield the names:
def __iter__(self):
for e in self.l_investments:
yield e.name
This fixes it so that 'GOOG' in p == True, but it breaks another requirement:
Failed example:
for stock in p:
print stock
Expected:
1000 shares of APPL worth 252730.00
5000 shares of CSCO worth 118700.00
500 shares of GOOG worth 245670.00
2000 shares of MSFT worth 50880.00
Got:
APPL
CSCO
GOOG
MSFT
How do I change the __iter__ method (or any other part of the code) so that both of these requirements are met?
I more interested in learning how OOP works than solving this particular problem. Any help would be much appreciated!
To add more detail to BrenBarn’s answer — yes, you want to override
__contains__. Thex in objectmembership test only uses__iter__if__contains__isn’t defined.It seems like you’ll want to make
__contains__work for both Investment instances and Investment name strings, since I’d assume you want both'GOOG' in pandinvestment_object_with_GOOG_name in pto returnTrue. If that’s the case, the code should look something like this:Note that the Investment objects need to implement sensible comparison for this to work. If they don’t (which it looks like they don’t — object comparison uses IDs and not attribute contents), either give them a comparison operator, or replace the second half of the above with this version to just do the comparison on the name:
Of course, if you want the membership test to only work for name strings, just remove the second half altogether.
Also, after looking at your code — is there any reason why you keep a list and a dictionary of investments in Portfolio? Either should be sufficient as an internal representation. I used the dictionary for my code above, but it would be easy to re-implement with a list — I think you should just pick one, unless you really need both for performance or other reasons that I haven’t figured out from the code.