文章

《编写整洁的Python代码》读书笔记(一)

属性的 setter 和 getter、可迭代对象

《编写整洁的Python代码》读书笔记(一)

属性

getter 和 setter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class User:
  def __init__(self):
    self._age = None

  # getter
  @property
  def age(self):
    return self._age

  # setter
  @age.setter
  def age(self,newValue):
    if newValue<0 or newValue>120:
      raise ValueError('age out of range')
    self._age = newValue

Tom = User()
Tom.age = 20
print(Tom.age)

Tom.age = 150

可迭代对象

可迭代对象的两种形式

  • 包含 __iter____next__ 方法的迭代,StopIteration 异常
  • 包含 __len____getitem__ 方法的序列

创建可迭代对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import datetime

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 += datetime.timedelta(days=1)

dr = DateRangeContainerIterable(
  datetime.date(2025,2,15),
  datetime.date(2025,3,15)
)

for day in dr:
  print(day)

创建序列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import datetime

class DateRangeContainerIterable:
  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 += datetime.timedelta(days=1)
    return days

  def __getitem__(self,day_no):
    return self._range[day_no]

  def __len__(self):
    return len(self._range)

dr = DateRangeContainerIterable(
  datetime.date(2025,2,15),
  datetime.date(2025,3,15)
)

for day in dr:
  print(day)

容器对象

容器对象需实现 __contains__ 方法,以支持 in 运算符

动态属性

实现魔术方法 __getattr__

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class DynamicAttributes:
  def __init__(self,attribute):
    self.attribute = attribute

  def __getattr__(self,attr):
    if attr.startswith('fallback_'):
      name = attr.replace('fallback_','')
      return f'[fallback resolved] {name}'
    raise AttributeError('f{self.__class__.__name__} has no attribute {attr}')

dyn = DynamicAttributes('value')
print(dyn.attribute) # value

print(dyn.fallback_test) # [fallback resolved] test

dyn.__dict__['fallback_new'] = 'new value'
print(dyn.fallback_new) # new value

print(getattr(dyn,'something','default')) # defalt
本文由作者按照 CC BY 4.0 进行授权