Effective Python item 30
ちょっととっかかりづらかったので、leaky ではない普通のバケツの問題に書き換えました。
◯ property を使うメリット
既存の関数, メソッドを書き換えることなく、属性を変更することができます。
◯ 問題
以下のコードを現在量 quota ではなく...
def sample_code(): # 水を貯められるバケツ Bucket オブジェクト bucket = Bucket() # 水を汲む fill 関数 fill(bucket, 100) # 水を抜く deduct 関数 deduct(bucket, 30) # __repr__ print(bucket) # Bucket(quota=70) # fill(bucket, 100) deduct(bucket, 20) print(bucket) # Bucket(quota=150) class Bucket(object): def __init__(self, quota=0): self.quota = quota def __repr__(self): return 'Bucket(quota=%d)' % self.quota def fill(bucket, amount): bucket.quota += amount def deduct(bucket, amount): bucket.quota -= amount if __name__ == '__main__': sample_code()
総支出量 self.quota_consumed、総取得量 self.quota_accumulated で管理するように、2つの quota メソッドを実装してください。
ただし、既存のメソッド、fill, deduct を変更してはいけません。
def sample_code(): bucket = Bucket() fill(bucket, 100) deduct(bucket, 30) print(bucket) fill(bucket, 100) deduct(bucket, 20) print(bucket) class Bucket(object): def __init__(self, quota_accumulated=0, quota_consumed=0): self.max_quota = max_quota self.quota_consumed = quota_consumed def __repr__(self): return ('Bucket(quota_accumulated=%d, quota_consumed=%d)' % (self.max_quota, self.quota_consumed)) @property def quota(self): ... @quota.setter def quota(self, new_quota): ... def fill(bucket, amount): bucket.quota += amount def deduct(bucket, amount): bucket.quota -= amount if __name__ == '__main__': sample_code()
◯ 解答例
こんな感じに。fill, deduct を書き換えることなく、総支出量 self.quota_consumed、総取得量 self.quota_accumulated で管理するようになりました。
def sample_code(): bucket = Bucket() fill(bucket, 100) deduct(bucket, 30) print(bucket) fill(bucket, 100) deduct(bucket, 20) print(bucket) class Bucket(object): def __init__(self, quota_accumulated=0, quota_consumed=0): self.quota_accumulated = quota_accumulated self.quota_consumed = quota_consumed def __repr__(self): return ('Bucket(quota_accumulated=%d, quota_consumed=%d)' % (self.quota_accumulated, self.quota_consumed)) @property def quota(self): return self.quota_accumulated - self.quota_consumed @quota.setter def quota(self, new_quota): delta = new_quota - self.quota if new_quota < 0: raise ValueError # fill if delta > 0: self.quota_accumulated += delta # deduct else: self.quota_consumed -= delta def fill(bucket, amount): bucket.quota += amount def deduct(bucket, amount): bucket.quota -= amount if __name__ == '__main__': sample_code()