Rumah >pembangunan bahagian belakang >Tutorial Python >Bagaimana untuk mentakrifkan kaedah lebihan kaedah pembina dan kaedah generik dalam kelas Python

Bagaimana untuk mentakrifkan kaedah lebihan kaedah pembina dan kaedah generik dalam kelas Python

WBOY
WBOYke hadapan
2023-05-09 14:34:231351semak imbas

    Apakah itu "kaedah generik"?

    Kaedah yang terdiri daripada berbilang kaedah yang melaksanakan operasi yang sama untuk jenis yang berbeza.

    Sebagai contoh

    Kini terdapat keperluan yang memerlukan anda membuat kelas tarikh tersuai (CustomDate) dengan cara berikut:

    • Cap masa

    • Tahun, bulan, hari (tuple mengandungi tiga integer)

    • rentetan format ISO

    • Datetime Kelas

    Pelaksanaan am

    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

    Nota: Kami tidak akan membincangkan sama ada cop tarikh/masa yang masuk adalah sah atau tidak , hanya membuat pertimbangan kasar pada jenis.

    Adakah cara yang lebih baik?

    Kami boleh membahagikan kaedah pembinaan yang berbeza kepada berbilang kaedah dan menggunakan functools penghias dalam singledispatchmethod untuk memutuskan kaedah yang hendak dipanggil berdasarkan jenis parameter yang dihantar.

    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

    Dengan cara ini, kita boleh mengasingkan pemulaan setiap jenis parameter kepada kaedah yang berasingan.

    Kelemahan

    #1 Penghantaran tunggal

    Pelaksanaan kaedah yang manakah harus digunakan semasa panggilan ditentukan oleh algoritma penghantaran. Jika algoritma memutuskan pelaksanaan kaedah untuk digunakan hanya berdasarkan jenis parameter tunggal, ia dipanggil penghantaran tunggal.

    singledispatchmethod Ia adalah satu penghantaran. Iaitu, hanya parameter pertama akan dipertimbangkan. Ini adalah jauh dari cukup dalam perniagaan sebenar.

    #2 tidak menyokong penaipan

    Walau bagaimanapun, seperti di atas, kita masih perlu menggunakan if/else untuk menentukan jenis elemen dalam tuple. Iaitu, kita tidak boleh menggunakan typing.Tuple[int, int, int].

    Sebagai kompromi, mungkin kita boleh mentakrifkan kelas ThreeIntTuple untuk melayakkannya dan mengasingkan pertimbangan ini daripada kelas CustomDate.

    Ini hanya idea untuk rujukan anda, saya tidak akan melaksanakannya (kerana kita ada cara yang lebih baik xD).

    Alternatif: perpustakaan pelbagai kaedah

    Pustaka ini bukan salah satu perpustakaan standard dan perlu dipasang melalui pip:

    pip install multimethod

    Kelebihan

    multimethod Algoritma Berbilang penghantaran yang digunakan boleh memenuhi senario yang lebih kompleks dengan lebih baik. Selain itu, perpustakaan mempunyai sokongan yang baik untuk jenis dalam typing.

    Amalan yang lebih baik

    Berbalik kepada soalan di atas, kita boleh memperbaikinya seperti ini:

    • Gunakan kaedah multimethod dan bukannya singledispatchmethod ;

    • Gunakan Tuple[int, int, int] bukannya tuple, tidak perlu lagi menyemak panjang dan jenis elemen tuple secara manual; >Kaedah praktikal muktamad (pembebanan kaedah sebenar)

    • Sebelum itu, izinkan saya bertanya soalan mudah kepada anda (ini berkait rapat dengan kandungan kami yang seterusnya):
    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

    Apakah yang akan dikeluarkan oleh kod di atas ? Atau adakah ia akan menimbulkan ralat?

    Output

    .

    Dalam Python, jika kaedah dengan nama yang sama ditakrifkan, kaedah terakhir akan menimpa kaedah sebelumnya.

    2Tetapi anda mungkin tidak tahu bahawa kami boleh mengubah tingkah laku ini melalui metaclass:

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

    Dalam baris 7 dan 8, kami menamakan semula kaedah

    pendua untuk

    , dan berjaya memanggilnya pada baris 22. Penyelenggara

    a telah menggunakan ini dengan baik dan telah berurusan dengan nama pendua untuk mencapai "kesan khas". b

    Kembali kepada topik, kita boleh membuat penambahbaikan berikut:

    multimethod

    Tetapkan

    sebagai kelas meta bagi kelas
    • menamakan semua kaedah multimethod.multidata. CustomDate

    • 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
    • Dari segi kesan, ini betul-betul sama dengan kaedah bahasa statik terlebih muatan!

    Atas ialah kandungan terperinci Bagaimana untuk mentakrifkan kaedah lebihan kaedah pembina dan kaedah generik dalam kelas Python. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

    Kenyataan:
    Artikel ini dikembalikan pada:yisu.com. Jika ada pelanggaran, sila hubungi admin@php.cn Padam