对齐 Python Class & 超-Class

Aligning Python Class & Super-Class

考虑以下 Python 代码片段,我们在其中定义了 PortfolioCompanyDeposit class。 Portfolio 对象只是充当公司和存款的联合体。我们可以 运行 投资组合的指标,例如 Profit。问题:

  1. 对于我在 CompanyDeposit class 中包含的每个新指标,我需要在 Portfolio class;尽管他们的行为始终相同:对所有投资求和。有没有办法改进 logic/construction of classes? 如果我们需要添加 100 个其他指标怎么办...

  2. Depositclass只有Profit的功能,没有Loss的功能(假定银行账户利息有保障) .有没有办法将 "undefined" 指标视为始终返回 0?或者是否有 cleaner/more 正确定义这些指标? 如果我们需要涵盖 100 种可能有或可能没有不同指标的不同投资类型怎么办...


class Company():
    def __init__(self, ItemsSold, ItemPrice, Expenses, Fines):
        self.ItemsSold = ItemsSold
        self.ItemPrice = ItemPrice
        self.Expenses  = Expenses
        self.Fines     = Fines

    def Profit(self):
        return self.ItemsSold * self.ItemPrice

    def Loss(self):
        return self.Expenses + self.Fines

    def ProfitAndLoss(self):
        return self.Profit() - self.Loss()

class Portfolio():
    def __init__(self, Investments):
        self.Investments = Investments

    def Profit(self):
        return sum([inv.Profit() for inv in self.Investments])

    def Loss(self):
        return sum([inv.Loss() for inv in self.Investments])

    def ProfitAndLoss(self):
        return sum([inv.ProfitAndLoss() for inv in self.Investments])

class Deposit():
    def __init__(self, Notional, InterestRate, TimeHorizon):
        self.Notional     = Notional
        self.InterestRate = InterestRate
        self.TimeHorizon  = TimeHorizon

    def Profit(self):
        return self.Notional * self.InterestRate * self.TimeHorizon        

myComp1 = Company(100,2,50,20)
myComp2 = Company(200,2,100,80)
myDepos = Deposit(100,0.02,3)
myPortf = Portfolio([myComp1,myComp2,myDepos])

print(myPortf.Profit())          # Works fine
print(myPortf.ProfitAndLoss())   # Throws an error

第二个问题很简单:您所要做的就是创建一个 Base class,其中每个指标都定义为返回 0 的方法。然后派生所有 Invest classes (Company, Deposit, etc) 来自 Base class,因此所有未定义的指标将调用 [=12= 中的相应方法] class.

第一个问题有点难,因为它需要 meta-programming。你的Portfolioclass也可以从Baseclass派生出来,然后在Baseclass的方法字典中查找(Base.__dict__) 检索所有指标名称。之后,对于所有这些指标,它会创建一个特定的 lambda 方法,该方法会为 Investments 列表中的每个项目调用此指标并对结果求和。这是一个框架代码:

class Base(object):
    def f1(self):
        return 0
    def f2(self):
        return 0

class InvestA(Base):
    def f2(self):
        return 2

class InvestB(Base):
    def f1(self):
        return 1

class Portfolio(Base):
    def __init__(self, invest):
        self.invest = invest
        for name in [n for n in Base.__dict__ if n[:2] != '__']:
           self.__dict__[name] = lambda name=name: self.sum(name)
    def sum(self, name):
        return sum([i.__class__.__dict__[name](i) for i in self.invest
                   if name in i.__class__.__dict__])

A = InvestA()
print("A.f1 = %s, A.f2 = %s" % (A.f1(), A.f2()))
B = InvestB()
print("B.f1 = %s, B.f2 = %s" % (B.f1(), B.f2()))
P = Portfolio([A,A,B])
print('P.f1 = A.f1 + A.f1 + B.f1 =', P.f1())
print('P.f2 = A.f2 + A.f2 + B.f2 =', P.f2())

产生以下输出:

A.f1 = 0, A.f2 = 2
B.f1 = 1, B.f2 = 0
P.f1 = A.f1 + A.f1 + B.f1 = 1
P.f2 = A.f2 + A.f2 + B.f2 = 4

如您所见,A.f1、B.f2、P.f1 和 P.f2 没有明确定义为方法,但由于继承和 meta-programming