类方法重载装饰器@singledispatchmethod

-- TOC --

前面有文章详细解释@singledispatch装饰器,也有文章详细解释用于类方法的@classmethod和@staticmethod,本文补充另一个用于类方法重载的装饰器:@singledispatchmethod。

从Python3.8开始提供@singledispatchmethod。

@singledispatch可以重载函数接口的第1个参数,@singledispatchmethod同样是重载第1个参数,确切地说,是重载第1个非cls或self参数

代码祭天:

from functools import singledispatchmethod


class clock():

    def __new__(cls):
        raise NotImplementedError('please use classmethod to instantiation')

    @staticmethod
    def init(self, hour, minute, second):
        self.hour = hour
        self.minute = minute
        self.second = second

    @singledispatchmethod
    @classmethod
    def create(cls, hour, minute, second):
        print('int create')
        if not (0 < hour < 23
                and 0 < minute < 60
                and 0 < second < 60):
            return
        obj = object.__new__(cls)
        clock.init(obj, hour, minute, second)
        return obj

    @create.register(str)
    @classmethod
    def _(cls, hour, minute, second):
        print('str create')
        if not (0 < int(hour) < 23
                and 0 < int(minute) < 60
                and 0 < int(second) < 60):
            return
        obj = object.__new__(cls)
        clock.init(obj, int(hour), int(minute), int(second))
        return obj

    @create.register(tuple)
    @classmethod
    def _(cls, tt):
        print('tuple create')
        if not (0 < tt[0] < 23
                and 0 < tt[1] < 60
                and 0 < tt[2] < 60):
            return
        obj = object.__new__(cls)
        clock.init(obj, tt[0], tt[1], tt[2])
        return obj

    @singledispatchmethod
    def show(self, tag):
        print('str-->'+tag, str(self.hour)+':'
                        +str(self.minute)+':'
                        +str(self.second))

    @show.register(int)
    def _(self, tag):
        print('int-->'+str(tag), str(self.hour)+':'
                        +str(self.minute)+':'
                        +str(self.second))


c1 = clock.create(1,2,3)
c1.show('beijing')

c2 = clock.create('3',4,5)
c2.show(24)

c3 = clock.create((5,6,6))
c3.show('a')

try:
    c4 = clock()
except Exception as e:
    print(repr(e))

这段测试代码,将@classmethod,@staticmethod,以及本文的重点@singledispatchmethod都用上了。而且没有定义__init__,并且在__new__内直接raise,需仔细品味。

这样设计,实际上是不允许通过class名称这种常规的方式来创建对象,强迫代码使用者使用create这个被@singledispatchmetho修饰过的classmethod来创建对象。

运行结果符合预期:

$ python3 sdm.py
int create
str-->beijing 1:2:3
str create
int-->24 3:4:5
tuple create
str-->a 5:6:6
NotImplementedError('please use classmethod to instantiation')

有了@singledispatchmethod,再配合上@classmethod,我们就可以重载class的factory method,提升代码的可读性和优雅值!

本文链接:https://cs.pynote.net/sf/python/202209091/

-- EOF --

-- MORE --