最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python?類中定義多個(gè)構(gòu)造器方法重載與泛方法

 更新時(shí)間:2023年03月22日 10:46:54   作者:披著狼皮的羊_  
這篇文章主要為大家介紹了Python?類中定義多個(gè)構(gòu)造器方法重載與泛方法示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

引言

在 Python 開發(fā)中,參數(shù)校驗(yàn)這件事一直讓我很苦惱;校驗(yàn)嘛,就得寫很多與業(yè)務(wù)不相關(guān)的 if/else,特別麻煩;不校驗(yàn)嘛,又擔(dān)心會(huì)有哪些意料之外的 bug,而且在很多情況下報(bào)的錯(cuò)誤也和具體問題有些偏差,難以定位問題。

歸功于 Python 動(dòng)態(tài)語言的特性,這個(gè)問題好像沒有很好的解決方式。通過歷代 Python 版本的發(fā)布你也可以看到,官方一直都在完善類型注解(比如最近的 Python 3.11 新增的 Self 類型),似乎想通過某種方式解決此類問題。

不管怎樣,就目前來看,泛方法(generic method)或許能很大程度上解決這個(gè)問題。

什么是“泛方法”?

由多個(gè)方法組成的方法,這些方法為不同的類型實(shí)現(xiàn)相同的操作。

舉個(gè)栗子 ??

現(xiàn)在有個(gè)需求,需要你通過以下幾種方式創(chuàng)建一個(gè)自定義的日期類(CustomDate):

  • 時(shí)間戳
  • 年、月、日(包含三個(gè)整數(shù)的元組)
  • ISO 格式的字符串
  • Datetime

一般實(shí)現(xiàn)

from datetime import date, datetime
class CustomDate:
    def __init__(self, arg):
        if isinstance(arg, (int, float)):
            self.__date = date.fromtimestamp(arg)
        elif isinstance(arg, tuple) and len(arg) == 3 and all(map(lambda x: isinstance(x, int), arg):
            self.__date = date(*arg)
        elif isinstance(arg, str):
            self.__date = date.fromisoformat(arg)
        elif isinstance(arg, datetime):
            self.__date = datetime.date()
        else:
            raise TypeError("could not create instance from " + type(arg).__name__)
    @property
    def date():
        return self.__date

注:這里暫不討論傳入的日期/時(shí)間戳合不合法,僅僅只對(duì)類型做大致判斷。

有沒有更好的方式?

我們可以將不同的構(gòu)建方式拆分為多個(gè)方法,并利用 functools 中的 singledispatchmethod 裝飾器來根據(jù)傳入的參數(shù)類型決定調(diào)用哪個(gè)方法。

from datetime import date, datetime
from functools import singledispatchmethod
class CustomDate:
    @singledispatchmethod
    def __init__(self, arg):
        raise TypeError("could not create instance from " + type(arg).__name__)
    @__init__.register(int)
    @__init__.register(float)
    def __from_timestamp(self, arg):
        self.__date = date.fromtimestamp(arg)
    @__init__.register(tuple)
    def __from_tuple(self, arg):
        if len(arg) == 3 and all(map(lambda x: isinstance(x, int), arg)):
            self.__date = date(*arg)
        else:
            raise ValueError("could not create instance from a malformed tuple")
    @__init__.register(str)
    def __from_isoformat(self, arg):
        self.__date = date.fromisoformat(arg)
    @__init__.register(datetime)
    def __from_datetime(self, arg):
        self.__date = arg.date()
    @property
    def date(self):
        return self.__date

這樣一來,我們便能將每種參數(shù)類型的初始化獨(dú)立成一個(gè)個(gè)的方法了。

缺點(diǎn)

#1 單分派

在調(diào)用期間應(yīng)該使用哪個(gè)方法實(shí)現(xiàn)由分派算法決定。如果該算法只基于單個(gè)參數(shù)的類型來決定使用哪個(gè)方法實(shí)現(xiàn),則稱其為單分派。

singledispatchmethod 就是就是單分派的。也就是說,只有第一個(gè)參數(shù)會(huì)作為考量。這在實(shí)際業(yè)務(wù)中是遠(yuǎn)遠(yuǎn)不足的。

#2 不支持 typing

然而,如上,對(duì)元組中元素類型判斷還是需要我們用 if/else 實(shí)現(xiàn)。也就是說,我們不能使用 typing.Tuple[int, int, int]。

作為一種折中的方案,或許我們可以定義一個(gè) ThreeIntTuple 類來對(duì)其進(jìn)行限定,將這些判斷從 CustomDate 類中隔離開來。

這里僅提供一個(gè)思路讓大家參考,我就不實(shí)現(xiàn)了(因?yàn)槲覀冇懈玫姆绞?xD)。

替代方案:multimethod 庫

這個(gè)庫不是標(biāo)準(zhǔn)庫之一,需要通過 pip 安裝:

pip install multimethod

優(yōu)勢(shì)

multimethod 采用的是多分派算法,能更好地滿足更復(fù)雜的場(chǎng)景。此外,該庫對(duì) typing 中的類型也有不錯(cuò)的支持。

更更好的實(shí)踐方式

回到上面的問題,我們可以這么改進(jìn):

  • 使用 multimethod 方法來替代 singledispatchmethod;
  • 使用 Tuple[int, int, int] 來替代 tuple,不再需要手動(dòng)校驗(yàn)元組的長(zhǎng)度和元素類型了;
from datetime import date, datetime
from typing import Tuple, Union
from multimethod import multimethod
class CustomDate:
    @multimethod
    def __init__(self, arg):
        raise TypeError("could not create instance from " + type(arg).__name__)
    @__init__.register
    def __from_timestamp(self, arg: Union[int, float]):
        self.__date = date.fromtimestamp(arg)
    @__init__.register
    def __from_tuple(self, arg: Tuple[int, int, int]):
        self.__date = date(*arg)
    @__init__.register
    def __from_isoformat(self, arg: str):
        self.__date = date.fromisoformat(arg)
    @__init__.register
    def __from_datetime(self, arg: datetime):
        self.__date = arg.date()
    @property
    def date(self):
        return self.__date

究極好的實(shí)踐方式(真正的方法重載)

在此之前,先問大家一個(gè)簡(jiǎn)單的問題(這跟我們之后的內(nèi)容有很大的聯(lián)系):

class A:
    def a(self):
        print(1)
    def a(self):
        print(2)
A().a()

以上這段代碼會(huì)輸出什么?還是會(huì)拋出錯(cuò)誤?

輸出 2。

在 Python 中,如果定義了重名的方法,最后一個(gè)方法是會(huì)覆蓋掉之前的方法的。

但你或許不知,我們可以通過元類(metaclass)來改變這一行為:

class MetaA(type):
    class __prepare__(dict):
        def __init__(*args):
            pass
        def __setitem__(self, key, value):
            if self.get('a'):  # Line 7
                super().__setitem__('b', value)  # Line 8
            else:	
                super().__setitem__(key, value)
class A(metaclass=MetaA):
    def a(self):
        print(1)
    def a(self):
        print(2)
A().a()  # => 1
A().b()  # => 2  # Line 22

在第 7 和第 8 行,我們將重名的 a 方法改名為 b,并在第 22 行成功地調(diào)用它了。

multimethod 的維護(hù)者們很好地運(yùn)用了這一點(diǎn),對(duì)重名的方法進(jìn)行了處理,以達(dá)到一種“特殊的效果”。

回到正題,我們可以做出如下改進(jìn):

  • multimethod.multidata 設(shè)置為 CustomDate 類的元類;
  • 將所有方法命名為 __init__。
from datetime import date, datetime
from typing import Tuple, Union
from multimethod import multimeta
class CustomDate(metaclass=multimeta):
    def __init__(self, arg: Union[int, float]):
        self.__date = date.fromtimestamp(arg)
    def __init__(self, arg: Tuple[int, int, int]):
        self.__date = date(*arg)
    def __init__(self, arg: str):
        self.__date = date.fromisoformat(arg)
    def __init__(self, arg: datetime):
        self.__date = arg.date()
    def __init__(self, arg):
        raise TypeError("could not create instance from " + type(arg).__name__)
    @property
    def date(self):
        return self.__date

從效果上來看,這完全和靜態(tài)語言的方法重載一模一樣!

總結(jié)

使用泛方法能讓代碼更加簡(jiǎn)潔、靈活。希望上述內(nèi)容能對(duì)你有幫助。

參考資料

以上就是Python 類中定義多個(gè)構(gòu)造器方法重載與泛方法的詳細(xì)內(nèi)容,更多關(guān)于Python 類多個(gè)構(gòu)造器方法的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論

永吉县| 大埔县| 嘉兴市| 林甸县| 进贤县| 昌宁县| 城固县| 屏南县| 略阳县| 新密市| 西安市| 昌都县| 郓城县| 岢岚县| 和静县| 海安县| 鲁甸县| 东乌珠穆沁旗| 佛教| 崇义县| 昭苏县| 海伦市| 东兴市| 历史| 屏山县| 阿拉善左旗| 加查县| 华坪县| 平阴县| 合肥市| 绍兴市| 安泽县| 永寿县| 保山市| 沾化县| 义乌市| 侯马市| 文山县| 隆化县| 华容县| 芦山县|