4

我正在为金融工具定价,每个金融工具对象都需要一个日计数器作为属性。有 4 种日计数器,它们的两种方法都有不同的实现,year_fraction并且day_count. 金融工具的这一天数计数器属性在定价时用于其他类,以了解如何适当地折现曲线等。但是,所有的天数计数方法都是静态的,无非是应用一些公式。

因此,尽管我在网上阅读的所有内容都告诉我不要使用静态方法而只使用模块级函数,但我看不到一种方法可以很好地绕过正确的 DayCounter 而不实现这样的东西

class DayCounter:
    __metaclass__ = abc.ABCMeta

    @abc.abstractstaticmethod
    def year_fraction(start_date, end_date):
        raise NotImplementedError("DayCounter subclass must define a year_fraction method to be valid.")

    @abc.abstractstaticmethod
    def day_count(start_date, end_date):
        raise NotImplementedError("DayCounter subclass must define a day_count method to be valid.")


class Actual360(DayCounter):

    @staticmethod
    def day_count(start_date, end_date):
        # some unique formula

    @staticmethod
    def year_fraction(start_date, end_date):
        # some unique formula


class Actual365(DayCounter):

    @staticmethod
    def day_count(start_date, end_date):
        # some unique formula

    @staticmethod
    def year_fraction(start_date, end_date):
        # some unique formula


class Thirty360(DayCounter):

    @staticmethod
    def day_count(start_date, end_date):
        # some unique formula

    @staticmethod
    def year_fraction(start_date, end_date):
        # some unique formula

class ActualActual(DayCounter):

    @staticmethod
    def day_count(start_date, end_date):
        # some unique formula

    @staticmethod
    def year_fraction(start_date, end_date):
        # some unique formula

因此,在某个特定工具的定价引擎中,将工具作为参数传递,我可以根据需要使用工具的日计数器属性。

我是否遗漏了 Python 中更惯用/风格上可接受的东西,或者这似乎适合用于仅静态方法的类?


示例

我有一个 FxPricingEngine 类,它有一个__init__传递 FxInstrument 和后续underlying_instrument属性的方法。然后,为了使用Value我的定价引擎的方法,我需要使用特定日期计数器对曲线进行折扣。我有一个YieldCurve带有discount我传递的方法的类,self.underlying_instrument.day_counter.year_fraction以便我可以应用正确的公式。实际上,这些类所要做的就是为独特的实现提供一些逻辑组织。

4

3 回答 3

4

事实上,面向对象在您的场景中没有任何意义:没有与您的类型实例关联的数据,因此某种类型的任何两个对象(例如Thirty360)将是相等的(即您只有单例)。

看起来您希望能够根据行为对客户端代码进行参数化 - 您的方法操作的数据不是在构造函数中给出,而是通过方法的参数给出。在这种情况下,普通的自由函数可能是一个更直接的解决方案。

例如,给定一些在您的计数器上运行的虚构客户端代码,例如:

def f(counter):
  counter.day_count(a, b)
  # ...
  counter.year_fraction(x, y)

...您也可以想象立即将两个函数作为参数而不是对象传递,例如有

def f(day_count, year_fraction):
    day_count(a, b)
    # ...
    year_fraction(x, y)

在调用方,您将传递普通函数,例如

f(thirty360_day_count, thirty360_year_fraction)

如果您愿意,您也可以为函数指定不同的名称,或者您可以在单独的模块中定义它们以获得命名空间。您还可以轻松地传递特殊功能,例如方式(例如,如果您只需要 day_count 正确但 year_fraction 可能是 noop)。

于 2016-04-13T12:35:00.760 回答
-1

坦率地说,以这种方式定义静态方法没有多大意义。在您的情况下,静态方法的唯一用途是为您的函数名称提供命名空间,即您可以调用您的方法,例如Actual365.day_count更清楚地说明 day_count 属于Actual365功能。

但是你可以通过定义一个名为actual365.

import actual365
actual365.day_count()

就面向对象而言,您的代码没有提供 OOP 设计提供的任何优势。您刚刚将函数包装在一个类中。

现在我注意到您所有的方法都使用 start_date 和 end_date,将它们用作实例变量怎么样?

class Actual365(object):

    def __init__(self, start_date, end_date):
        self.start_date, self.end_date = start_date, end_date

    def day_count(self):
        # your unique formula

    ...

此外AbstractClasses,在像 Python 这样的 Duck-Typed 语言中没有多大意义。只要某个对象提供一种行为,它就不需要从某个抽象类继承。

如果这对您不起作用,则仅使用函数可能是更好的方法。

于 2016-04-13T11:58:59.827 回答
-1

从来没听说过。在我看来,您的设计模式还可以。特别是如果您的代码有可能增长到每个类超过 2 个函数,并且如果一个类中的函数是连接的。

如果任何功能组合都是可能的,请使用功能传递方法。模块方法和您的方法非常相似。模块的优点或缺点(取决于)是您的代码被分成许多文件。您的方法允许您使用isinstance,但您可能不需要它。

直接传递函数

如果你只有一个函数,你可以直接传递这个函数而不是使用一个类。但是,一旦您拥有2 个或更多具有不同实现的函数,类对我来说似乎很好。只需添加一个文档字符串来解释用法。我假设一个类中的两个函数实现有一定的联系。

使用模块

您可以使用模块而不是类(例如模块 Actual365DayCounter 和模块 Actual360DayCounter)并使用类似if something: import Actual360DayCounter as daycounterand的东西else: import Actual365ayCounter as daycounter

或者您可以导入所有模块并将它们放入字典中(感谢@freakish 的评论),MODULES = { 'Actual360': Actual360, ... }然后简单地使用MODULES[my_var].

但我怀疑这会是一个更好的设计模式,因为您会将源代码拆分为许多小模块。

另外一个选项:

一种方法是只使用一个类:

class DayCounter:
    def __init__(self, daysOfTheYear = 360):
        self.days_of_the_year = daysOfTheYear

并使用self.days_of_the_year. 但这仅在days_of_the_year实际上是函数的参数时才有效。如果你必须在你的函数实现中使用很多if ... elif .. elif ...,这种方法会更糟

于 2016-04-13T12:21:54.620 回答