python魔法函数  sub     rsub  

前言

最近使用到Moment.js,发现可以加减月份。python 中好像没有这个实现,遂在 github 上找到一个库datedelta

moment 使用方法

var moment = require("moment");
console.log(moment().format("YYYY-MM"));
console.log(
  moment()
    .add(-1, "months")
    .format("YYYY-MM")
);

输出结果:

❯ node moment.js
2019-11
2019-10

抽离核心代码

import datetime


class datedelta:

    __slots__ = ['_years', '_months', '_days']

    def __init__(self, *, years=0, months=0, days=0):
        int_years = int(years)
        int_months = int(months)
        int_days = int(days)

        self._years = int_years
        self._months = int_months
        self._days = int_days

    def __rsub__(self, other):
        if isinstance(other, datetime.date):
            month = other.month
            year = other.year

            month -= self._months
            dyear, month0 = divmod(month - 1, 12)
            year += dyear
            month = month0 + 1
            result = other.replace(year, month, 1)

            return result


MONTH = datedelta(months=1)

if __name__ == '__main__':
    print(datetime.date(2016, 3, 1) - MONTH)
    # 2016-02-01

输出结果: 2016-02-01

解析

python 有很多魔法方法,比如加减乘除、取余取模、大于小于等于… 感兴趣的可以看官方文档

值得一提的是,python 不仅提供了这些魔法方法,还提供部分反向操作符(+, -, *, /, %, divmod(), pow(), **, «, », &, ^, |)。

如果 x-y,x 没有实现sub方法,那就要看 y 有没有实现rsub,如果 y 有实现这个方法,就可以会调用 y-x。

datetime.date的__sub__,只支持 timedelta 类型才能减。

所以当 datetime.date(2016, 3, 1)去减 datedelta(months=1)时,会反向调用 datedelta 的__rsub__,来减去一个月。

有时间下次整理下,python 的魔法方法

reference

© 2025 · Built with Gatsby