亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Python類中怎么定義多個構造器方法重載與泛方法

發布時間:2023-03-22 11:24:24 來源:億速云 閱讀:104 作者:iii 欄目:開發技術

這篇文章主要介紹“Python類中怎么定義多個構造器方法重載與泛方法”,在日常操作中,相信很多人在Python類中怎么定義多個構造器方法重載與泛方法問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Python類中怎么定義多個構造器方法重載與泛方法”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

    什么是“泛方法”?

    由多個方法組成的方法,這些方法為不同的類型實現相同的操作。

    舉個栗子 

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

    • 時間戳

    • 年、月、日(包含三個整數的元組)

    • ISO 格式的字符串

    • Datetime

    一般實現

    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

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

    有沒有更好的方式?

    我們可以將不同的構建方式拆分為多個方法,并利用 functools 中的 singledispatchmethod 裝飾器來根據傳入的參數類型決定調用哪個方法。

    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

    這樣一來,我們便能將每種參數類型的初始化獨立成一個個的方法了。

    缺點

    #1 單分派

    在調用期間應該使用哪個方法實現由分派算法決定。如果該算法只基于單個參數的類型來決定使用哪個方法實現,則稱其為單分派。

    singledispatchmethod 就是就是單分派的。也就是說,只有第一個參數會作為考量。這在實際業務中是遠遠不足的。

    #2 不支持 typing

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

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

    這里僅提供一個思路讓大家參考,我就不實現了(因為我們有更好的方式 xD)。

    替代方案:multimethod 庫

    這個庫不是標準庫之一,需要通過 pip 安裝:

    pip install multimethod

    優勢

    multimethod 采用的是多分派算法,能更好地滿足更復雜的場景。此外,該庫對 typing 中的類型也有不錯的支持。

    更更好的實踐方式

    回到上面的問題,我們可以這么改進:

    • 使用 multimethod 方法來替代 singledispatchmethod

    • 使用 Tuple[int, int, int] 來替代 tuple,不再需要手動校驗元組的長度和元素類型了;

    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

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

    在此之前,先問大家一個簡單的問題(這跟我們之后的內容有很大的聯系):

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

    以上這段代碼會輸出什么?還是會拋出錯誤?

    輸出 2

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

    但你或許不知,我們可以通過元類(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 行成功地調用它了。

    multimethod 的維護者們很好地運用了這一點,對重名的方法進行了處理,以達到一種“特殊的效果”。

    回到正題,我們可以做出如下改進:

    • multimethod.multidata 設置為 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

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

    到此,關于“Python類中怎么定義多個構造器方法重載與泛方法”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    仁布县| 海晏县| 离岛区| 大冶市| 乳源| 望城县| 古蔺县| 盐津县| 贡觉县| 元谋县| 梅州市| 东阿县| 台中县| 延安市| 常德市| 鄱阳县| 台南县| 黄平县| 太谷县| 马龙县| 调兵山市| 财经| 阳城县| 麻城市| 民乐县| 井冈山市| 北流市| 右玉县| 崇义县| 荣昌县| 兰州市| 茌平县| 徐汇区| 昌邑市| 贵定县| 石渠县| 扶绥县| 沅江市| 富阳市| 唐山市| 刚察县|