Python中的自定义类:方法是否必须通过实例调用?

2 投票
2 回答
763 浏览
提问于 2025-04-16 03:12

我正在处理一个应用程序的数据,这个程序在时间处理上有一些特别的地方。其中一个比较简单的地方是,它使用“年度中的天数”来表示日期,比如1月1日是1,2月1日是32,依此类推,而不是用月份加日期的方式。所以我想自己做一个日期类,继承默认的日期时间类,并添加一些自定义的方法。我把这个类叫做daytime。除了能输出我这种奇怪格式的方法外,我还需要一些方法,能够把这种奇怪的格式输入到daytime中。就像可以从datetime调用的方法.fromordinal()一样,我想要一个可以从daytime调用的方法.fromdayofyear()。到目前为止,我已经写了:

import datetime

class daytime(datetime.datetime):
    @property
    def dayofyear(self):
        return (self.date - datetime.date(self.year,1,1)).days + 1
    def fromdayofyear(year,dayofyear):
        return datetime(year,1,1)+datetime.timedelta(dayofyear-1)

问题是,由于fromdayofyear是一个类,它需要一个daytime的实例才能执行任何方法。

>>> from utils import daytime
>>> day = daytime.fromdayofyear(2010,32)          #should give a datetime, Feburary first
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unbound method from_datetime() must be called with DayTime instance as first argument (got str instance instead)
>>>

我可以很容易地写一系列函数来完成这个,但那样就失去了创建自定义类的意义。我意识到我可能不应该在这里使用类。有人能给我指个方向吗?

编辑:

这是我最终决定的:

import datetime

class daytime(datetime.datetime):
    @property
    def dayofyear(self):
        return (self.date - datetime.date(self.year,1,1)).days + 1
    @classmethod
    def fromdayofyear(cls,year,dayofyear):
        dt = cls(year,1,1)+datetime.timedelta(dayofyear-1)
        return cls(dt.year,dt.month,dt.day)

2 个回答

8

你想要使用@classmethod这个装饰器。这样的话,你的方法就会把类本身作为第一个参数,而不是对象实例。通常我们把这个参数叫做cls:

@classmethod
def from_file(cls, f):
    return cls(f.read())
2

原作者选择的解决方案存在严重问题(self.date 需要被调用,而不仅仅是提到;而且 fromdayofyear 方法实际上返回的是一个 datetime.datetime 实例,而不是 daytime,尽管看起来是想这样做的,使用了 cls)。

下面是我认为可以按预期工作的版本:

class daytime(datetime.datetime):

    @property
    def dayofyear(self):
        return (self.date() - datetime.date(self.year, 1, 1)).days + 1

    @classmethod
    def fromdayofyear(cls, year, dayofyear):
        dt = datetime.datetime(year, 1, 1) + datetime.timedelta(dayofyear-1)
        return cls(dt.year, dt.month, dt.day)

撰写回答