Iterable Objects
实现可迭代对象的方法有三种:第一种是类内实现 __iter__ 和 __next__ 方法, 第二种是使用 generator, 第三种是封装一个序列。__iter__ 和 __next__
from datetime import timedelta
class DateRangeIterable:
def __init__(self, start_date, end_date):
self.start_date = start_date
self.end_date = end_date
self._present_day = start_date
def __iter__(self):
return self
def __next__(self):
if self._present_day >= self.end_date:
raise StopIteration
today = self._present_day
self._present_day += timedelta(days=1)
return today使用 generator
from datetime import timedelta
class DateRangeContainerIterable:
def __init__(self, start_date, end_date):
self.start_date = start_date
self.end_date = end_date
def __iter__(self):
current_day = self.start_date
while current_day < self.end_date:
yield current_day
current_day += timedelta(days=1)封装一个序列
from datetime import timedelta
class DateRangeSequence:
"""An range created by wrapping a sequence."""
def __init__(self, start_date, end_date):
self.start_date = start_date
self.end_date = end_date
self._range = self._create_range()
def _create_range(self):
days = []
current_day = self.start_date
while current_day < self.end_date:
days.append(current_day)
current_day += timedelta(days=1)
return days
def __getitem__(self, day_no):
return self._range[day_no]
def __len__(self):
return len(self._range)
Container Objects
在 Python 中,实现了 __contains__ 方法的类就是容器类。当对该类使用 in 关键字的时候这个方法就会被调用。
element in container == container.__contains__(element)
示例代码:
class Criteria:
def __init__(self, height, weight):
self.height = height
self.weight = weight
def __contains__(self, person):
h, w = person
return 0 < h < self.height and 0 < w < self.weight
class Scope:
def __init__(self, height, weight):
self.criteria = Criteria(height, weight)
def __contains__(self, person):
return person in self.criteria
def mark_person(scope, person):
if person in scope:
scope[person] = 1
Dynamic attributes for objects
当我们做 . 调用的时候, Python 首先会对 object 的内部字典调用 __getattribute__ 方法,如果没有找到对应的 attribute,就会以 attribute 作为参数调用 __getattr__ 方法。
class DemoAttribute:
"""docstring for DemoAttribute"""
def __init__(self, attr):
self.attr = attr
def __getattr__(self, attr):
if attr.startswith("test"):
name = attr.replace("test", "")
return f"[test replaced]{name}"
raise AttributeError(f"{self.__class__.__name__}has no attribute{attr}")
下面是执行结果
>>> da = DemoAttribute("value")
>>> da.attr
'value'
>>> da.test_value
'[test replaced] _value'
>>> da.value
Traceback (most recent call last):
File "", line 1, in
File "testattr.py", line 19, in __getattr__
raise AttributeError(f"{self.__class__.__name__} has no attribute {attr}")
AttributeError: DemoAttribute has no attribute value
Callable objects
每当我们调用一个 Object 的时候,像这样 object(*args,**kwargs),其实 Python 是执行 object.__call__(*args, **kwargs).
from collections import defaultdict
class Count:
"""docstring for Count"""
def __init__(self):
self._count = defaultdict(int)
def __call__(self, value):
self._count[value] += 1
return self._count[value]
下面是执行结果
>>> c = Count()
>>> c(1)
1
>>> c(1)
2
>>> c(2)
1
>>> c(2)
2