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

WBOY
Lepaskan: 2023-05-09 14:34:23
ke hadapan
1292 orang telah melayarinya

    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
    Salin selepas log masuk

    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
    Salin selepas log masuk

    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
    Salin selepas log masuk

    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
    Salin selepas log masuk

    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()
    Salin selepas log masuk

    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
      Salin selepas log masuk
    • 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!

    Label berkaitan:
    sumber:yisu.com
    Kenyataan Laman Web ini
    Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
    Tutorial Popular
    Lagi>
    Muat turun terkini
    Lagi>
    kesan web
    Kod sumber laman web
    Bahan laman web
    Templat hujung hadapan
    Tentang kita Penafian Sitemap
    Laman web PHP Cina:Latihan PHP dalam talian kebajikan awam,Bantu pelajar PHP berkembang dengan cepat!