class Stack(list):
def push(self, item):
self.append(item)31 OOP Tricks
31.1 Avoiding Inheritance via Composition
class Stack:
def __init__(self, *, container=None):
if container is None:
container = list()
self._items = container
def push(self, item):
self._items.append(item)
def pop(self):
return self._items.pop()
def __len__(self):
return len(self._items)Ref: Beazley, David M. Python Distilled (p. 259). Pearson Education. Kindle Edition.
31.2 Avoiding Inheritance via Functions
class DataParser:
def parse(self, lines):
records = []
for line in lines:
row = line.split(',')
record = self.make_record(row)
records.append(row)
return records
def make_record(self, row):
raise NotImplementedError()
class PortfolioDataParser(DataParser):
def make_record(self, row):
return {
'name': row[0],
'shares': int(row[1]),
'price': float(row[2])
}parser = PortfolioDataParser()
data = parser.parse(open('portfolio.csv'))def parse_data(lines, make_record):
records = []
for line in lines:
row = line.split(',')
record = make_record(row)
records.append(row)
return records
def make_dict(row):
return {
'name': row[0],
'shares': int(row[1]),
'price': float(row[2])
}data = parse_data(open('portfolio.csv'), make_dict)31.3 Static Methods
Sometimes a class is merely used as a namespace for functions declared as static methods using @staticmethod. Unlike a normal method or class method, a static method does not take an extra self or cls argument. A static method is just a ordinary function that happens to be defined inside a class.
31.3.1 Simple
class Ops:
@staticmethod
def add(x, y):
return x + y
@staticmethod
def sub(x, y):
return x - ya = Ops.add(2, 3)
b = Ops.sub(4, 5)Ref: Beazley, David M. Python Distilled (p. 272). Pearson Education. Kindle Edition.
31.3.2 Advanced
class StandardPolicy:
@staticmethod
def deposit(account, amount):
account.balance += amount
@staticmethod
def withdraw(account, amount):
account.balance -= amount
@staticmethod
def inquiry(account):
return account.balance
class EvilPolicy(StandardPolicy):
@staticmethod
def deposit(account, amount):
account.balance += 0.95*amount
@staticmethod
def inquiry(account):
import random
if random.randint(0,4) == 1:
return 1.10 * account.balance
else:
return account.balanceclass Account:
def __init__(self, owner, balance, *, policy=StandardPolicy):
self.owner = owner
self.balance = balance
self.policy = policy
def __repr__(self):
return f'Account({self.policy}, {self.owner!r}, {self.balance!r})'
def deposit(self, amount):
self.policy.deposit(self, amount)
def withdraw(self, amount):
self.policy.withdraw(self, amount)
def inquiry(self):
return self.policy.inquiry(self)a = Account('Guido', 1000.0)
a.policy
a.deposit(500)
a.inquiry()1500.0
b = Account('Guido', 1000.0, policy=EvilPolicy)
b.deposit(500)
b.inquiry()1475.0