91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

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

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

Python怎么定義多個構造器方法重載和泛方法

發布時間:2023-05-19 16:57:53 來源:億速云 閱讀:127 作者:iii 欄目:編程語言

今天小編給大家分享一下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

    巴楚县| 天镇县| 辰溪县| 堆龙德庆县| 云龙县| 奉节县| 星座| 色达县| 侯马市| 灵璧县| 丹凤县| 漳平市| 泸州市| 八宿县| 大安市| 綦江县| 郁南县| 双牌县| 浙江省| 丽水市| 苏尼特右旗| 勃利县| 云林县| 息烽县| 新密市| 哈巴河县| 罗甸县| 潮安县| 冀州市| 金堂县| 吉林市| 贵阳市| 吉林省| 文登市| 会宁县| 营山县| 外汇| 萝北县| 安陆市| 盐津县| 武邑县|