If I hadn’t given an
__iter__
method to class
Month
,
the
for
loop would have called the
__getitem__
method of class
Month
and passed the illegal argument 0 to
__getitem__
.
""" This module is month.py """ import datetime import calendar class Month(object): "A Month object can be subscripted to return a datetime.date object of the Month." def __init__(self, month, year): if not isinstance(year, int): raise TypeError(f"year must be int, not {type(year)}") if not isinstance(month, int): raise TypeError(f"month must be int, not {type(month)}") if month < 1 or month > 12: raise ValueError(f"bad month {month}") self.year = year self.month = month self.last = calendar.monthrange(self.year, self.month)[1] #last day of month def __len__(self): return self.last; def __getitem__(self, day): if not isinstance(day, int): raise TypeError(f"day must be int, not {type(day)}") if day < 1 or day > self.last: raise ValueError(f"bad day {day} must be in range 1 to {self.last}") return datetime.date(self.year, self.month, day) def __iter__(self): return Month_iter(self.month, self.year, self.last) class Month_iter(object): def __init__(self, month, year, last): self.year = year self.month = month self.current = 1 self.last = last def __iter__(self): return self def __next__(self): if self.current > self.last: raise StopIteration d = datetime.date(self.year, self.month, self.current) self.current += 1 return d if __name__ == "__main__": import sys today = datetime.date.today() month = Month(today.month, today.year) d = month[today.day] print(d.strftime("%A, %B %-d, %Y")) sys.exit(0)
import sys import month november = month.Month(11, 2019) print(f"len(november) = {len(november)}") #calls november.__len__() d = november[19] #does the same thing as d = november.__getitem__(19) print(d.strftime("%A, %B %-d, %Y")) print() #Print the entire month. for d in november: print(d.strftime("%A, %B %-d, %Y")) sys.exit(0)
len(november) = 30 Tuesday, November 19, 2019 Friday, November 1, 2019 Saturday, November 2, 2019 Sunday, November 3, 2019 Monday, November 4, 2019 Tuesday, November 5, 2019 Wednesday, November 6, 2019 Thursday, November 7, 2019 Friday, November 8, 2019 Saturday, November 9, 2019 Sunday, November 10, 2019 Monday, November 11, 2019 Tuesday, November 12, 2019 Wednesday, November 13, 2019 Thursday, November 14, 2019 Friday, November 15, 2019 Saturday, November 16, 2019 Sunday, November 17, 2019 Monday, November 18, 2019 Tuesday, November 19, 2019 Wednesday, November 20, 2019 Thursday, November 21, 2019 Friday, November 22, 2019 Saturday, November 23, 2019 Sunday, November 24, 2019 Monday, November 25, 2019 Tuesday, November 26, 2019 Wednesday, November 27, 2019 Thursday, November 28, 2019 Friday, November 29, 2019 Saturday, November 30, 2019
An object of class
mystr.MyStr
contains an object of class
str
.
Therefore an object of class
mystr.MyStr_iterator
contains an object of class
str_iterator
.
""" This module is mystr.py """ class MyStr(object): def __init__(self, s = ""): if isinstance(s, str): self.s = s elif isinstance(s, MyStr): self.s = str(s) else: raise TypeError(f"s must be str or MyStr, not {type(s)}") def __str__(self): return self.s def __len__(self): return len(self.s) def __getitem__(self, key): le = len(self) if isinstance(key, int): if key < -le or key >= le: raise IndexError(f"index {key} must be in range {-le} to {le-1} inclusive") return MyStr(self.s[key]) elif isinstance(key, slice): if key.start != None and not isinstance(key.start, int): raise TypeError(f"start must be int, not {type(key.start)}") if key.stop != None and not isinstance(key.stop, int): raise TypeError(f"stop must be int, not {type(key.stop)}") if key.step != None and not isinstance(key.step, int): raise TypeError(f"step must be int, not {type(key.step)}") if key.step == 0: raise ValueError("step can't be 0") return MyStr(self.s[key.start:key.stop:key.step]) #or return MyStr(self.s[key]) else: raise TypeError(f"key must be int or slice, not {type(key)}") def __iter__(self): return MyStr_iterator(self.s) class MyStr_iterator(object): def __init__(self, s): self.s = s self.iter = iter(self.s) #self.iter is a str_iterator def __iter__(self): return self def __next__(self): return MyStr(next(self.iter)) #next(self.iter) is a str if __name__ == "__main__": import sys ms = MyStr("hello") print(ms) sys.exit(0)
Thanks to the
__getitem__
method,
the following
for
loop would have worked even if class
MyStr
had no
__iter__
method.
import mystr ms = mystr.MyStr("hello") print(f'ms = "{ms}"') print(f"len(ms) = {len(ms)}") empty = mystr.MyStr() print(f'empty = "{empty}"') print() print(ms[0]) print(ms[0:3]) print(ms[:3]) print(ms[-1::-1]) print() for c in ms: #c is a mystring.MyString print(c)
ms = "hello" len(ms) = 5 empty = "" h hel hel olleh h e l l o