Bagaimana cara menggunakan metode overloading di Python?


169

Saya mencoba menerapkan metode overloading di Python:

class A:
    def stackoverflow(self):    
        print 'first method'
    def stackoverflow(self, i):
        print 'second method', i

ob=A()
ob.stackoverflow(2)

tetapi hasilnya adalah second method 2; demikian pula:

class A:
    def stackoverflow(self):    
        print 'first method'
    def stackoverflow(self, i):
        print 'second method', i

ob=A()
ob.stackoverflow()

memberi

Traceback (most recent call last):
  File "my.py", line 9, in <module>
    ob.stackoverflow()
TypeError: stackoverflow() takes exactly 2 arguments (1 given)

Bagaimana saya membuat ini bekerja?


39
Dalam Python, pikirkan metode sebagai set khusus " atribut ", dan hanya ada satu " atribut " (dan dengan demikian satu metode) dari nama yang diberikan untuk objek. Metode terakhir menimpa metode sebelumnya. Di Jawa, metode bukan warga negara kelas pertama (mereka bukan "atribut objek"), tetapi lebih dipicu oleh "mengirim pesan" yang diselesaikan secara statis berdasarkan tipe terdekat (yang merupakan tempat kelebihan muatan masuk).



6
Mengapa belum ada jawaban untuk pertanyaan ini diterima? Cukup klik pada tanda centang outlied di sebelah kiri jawaban favorit Anda ...
glglgl

Jawaban:


150

Metode overloading bukan metode overriding . Dan dengan Python, Anda melakukan semuanya dalam satu fungsi:

class A:

    def stackoverflow(self, i='some_default_value'):    
        print 'only method'

ob=A()
ob.stackoverflow(2)
ob.stackoverflow()

Anda tidak dapat memiliki dua metode dengan nama yang sama dengan Python - dan Anda tidak perlu melakukannya.

Lihat bagian Nilai Argumen Default dari tutorial Python. Lihat "Terkejut" dan Argumen Default Mutable untuk menghindari kesalahan umum.

Sunting : Lihat PEP 443 untuk informasi tentang fungsi generik pengiriman tunggal baru di Python 3.4.


119
dan Anda tidak perlu - kadang-kadang IMHO akan sangat berguna untuk memiliki metode overloading seperti misalnya di C ++. Ok, itu tidak 'diperlukan' dalam arti bahwa itu tidak dapat dilakukan dengan menggunakan konstruksi lain - tetapi itu akan membuat beberapa hal lebih mudah dan sederhana.
Andreas Florath

7
@AndreasFlorath saya tidak setuju. Belajar mencintai bebek mengetik dan menulis setiap metode sehingga hanya melakukan satu hal, dan tidak perlu untuk metode overloading.
agf

4
+1 untuk membuat saya membaca tentang "kesalahan umum yang harus dihindari" sebelum saya tertangkap
mdup

43
Saya ingin sedikit tidak setuju;) ... overload sering membuat kode lebih bersih, karena Anda tidak mengemas metode ini dengan terlalu banyak pernyataan if-else untuk menangani kasus yang berbeda. Dalam arti keseluruhan keseluruhan bahasa fungsional menggunakan ide yang sama yaitu pencocokan argumen-pola. Yang berarti Anda akan memiliki metode lebih bersih lebih kecil .. daripada yang tidak terbaca raksasa.
sten

2
@ user1019129 Itulah tujuan dari fungsi pengiriman tunggal yang ditambahkan dengan Python 3.4, dan ditautkan dalam jawaban saya.
agf

62

Anda juga dapat menggunakan pythonlangutil :

from pythonlangutil.overload import Overload, signature

class A:
    @Overload
    @signature()
    def stackoverflow(self):    
        print 'first method'

    @stackoverflow.overload
    @signature("int")
    def stackoverflow(self, i):
        print 'second method', i

6
Saya pikir itu satu-satunya jawaban yang valid untuk pertanyaan itu. Saya akan menggandakan suaranya jika saya bisa.
Michael

3
itu bagus, tetapi tidak berfungsi pada fungsi mentah, hanya metode dalam kelas.
Legit Stack

1
Fungsionalitas @LegitStack Itu juga dapat ditambahkan. Bukan tidak mungkin.
Ehsan Keshavarzian

3
@LegitStack Saya memperbarui kode di GitHub, sekarang berfungsi dengan fungsi juga.
Ehsan Keshavarzian

1
@ PaulPrice Benar. Saya memperbarui jawaban saya dan menghapus bagian dukungan resmi. Anda masih dapat menggunakan kode saya untuk mengirim kelebihan. Sekarang berfungsi dengan baik metode dan fungsi. Raih kode dari GitHub. Saya belum memperbarui Pypi.
Ehsan Keshavarzian

48

Dengan Python, Anda tidak melakukan hal-hal seperti itu. Ketika orang melakukannya dalam bahasa seperti Java, mereka umumnya menginginkan nilai default (jika tidak, mereka umumnya menginginkan metode dengan nama yang berbeda). Jadi, dengan Python, Anda dapat memiliki nilai default .

class A(object):  # Remember the ``object`` bit when working in Python 2.x

    def stackoverflow(self, i=None):
        if i is None:
            print 'first form'
        else:
            print 'second form'

Seperti yang Anda lihat, Anda dapat menggunakan ini untuk memicu perilaku terpisah daripada hanya memiliki nilai default.

>>> ob = A()
>>> ob.stackoverflow()
first form
>>> ob.stackoverflow(2)
second form

2
Sebagian besar Noneberguna ketika Anda menginginkan nilai default yang bisa berubah. Perilaku terpisah harus dalam fungsi yang terpisah.
agf

@agf: Nonejuga dapat berguna sebagai nilai default asli.
Chris Morgan

Ya, tapi saya merujuk untuk menggunakannya sebagai nilai sentinel, yang merupakan cara Anda menggunakannya dalam jawaban Anda, dan saya pikir komentar saya menjelaskan.
agf

Anda mengatakan "secara umum"? apakah Anda menyiratkan ini tidak selalu begitu?
joel

24

Anda tidak bisa, tidak pernah perlu dan tidak benar-benar ingin.

Dalam Python, semuanya adalah objek. Kelas adalah benda, jadi benda adalah benda. Begitu juga metode.

Ada objek yang disebut Ayang merupakan kelas. Ini memiliki atribut yang disebut stackoverflow. Itu hanya dapat memiliki satu atribut seperti itu.

Saat Anda menulis def stackoverflow(...): ..., yang terjadi adalah Anda membuat objek yang merupakan metode, dan menetapkannya ke stackoverflowatribut A. Jika Anda menulis dua definisi, yang kedua menggantikan yang pertama, dengan cara yang sama yang selalu berlaku tugas

Anda juga tidak ingin menulis kode yang lebih liar dari hal-hal yang kadang-kadang digunakan untuk overloading. Bukan itu cara kerjanya.

Alih-alih mencoba mendefinisikan fungsi terpisah untuk setiap jenis hal yang dapat Anda berikan (yang tidak masuk akal karena Anda tidak menentukan jenis untuk parameter fungsi), berhenti khawatir tentang hal - hal apa saja dan mulailah memikirkan apa yang dapat mereka lakukan .

Anda tidak hanya tidak dapat menulis yang terpisah untuk menangani tuple vs daftar, tetapi juga tidak mau atau perlu .

Yang Anda lakukan hanyalah mengambil keuntungan dari fakta bahwa keduanya, misalnya, dapat diubah (yaitu Anda dapat menulis for element in container:). (Fakta bahwa mereka tidak terkait langsung dengan warisan tidak relevan.)


6
TBH, saya akan lebih berhati-hati dengan "tidak perlu". Ini adalah sesuatu yang dapat ditandai pada setiap fitur dari dunia nyata dan menggunakan bahasa pemrograman yang lengkap, dan karenanya bukan argumen yang valid. Siapa yang butuh generator? Siapa yang butuh kelas? Bahasa pemrograman hanyalah gula sintaksis untuk sesuatu yang lebih konkret.
Sebastian Mach

6
Sepenuhnya tidak setuju. Mungkin Anda "tidak pernah perlu" atau "tidak pernah ingin", tetapi ada cukup banyak aplikasi di mana Anda menginginkannya. Coba misalnya menulis sebuah program yang menangani array Python dan numpy dengan anggun tanpa mengotori program Anda dengan instanceof ...
Elmar Zander

1
Berdasarkan jawaban masi, saya akan mengatakan bahwa "Anda tidak bisa" sekarang salah dan usang. Berdasarkan keberadaan @overloaddekorator, saya akan mengatakan bahwa "tidak benar-benar ingin" bisa diperdebatkan, paling-paling. Dari PEP-3124, "... saat ini merupakan anti-pola umum untuk kode Python untuk memeriksa jenis argumen yang diterima ... 'cara yang jelas' untuk melakukan ini adalah dengan jenis inspeksi, tetapi ini rapuh dan tertutup untuk ekstensi ... "Jadi sepertinya cukup banyak orang yang menginginkannya, bahwa itu menjadi bagian dari Python.
Mike S

@ Mike, standarnya @overloadhanya untuk mengetik.
Narfanar

@Narfanar Saya tidak tahu bagaimana tanggapan Anda berlaku untuk komentar saya. Bisakah Anda jelaskan?
Mike S

16

Sementara @agf benar dengan jawaban di masa lalu sekarang dengan PEP-3124 kami mendapat gula sintaksis kami. Lihat mengetik dokumentasi untuk detail pada @overloaddekorator tetapi perhatikan bahwa ini benar-benar hanya gula sintaks dan IMHO. Ini semua orang telah berdebat sejak itu. Secara pribadi saya setuju bahwa memiliki beberapa fungsi dengan tanda tangan yang berbeda membuatnya lebih mudah dibaca kemudian memiliki fungsi tunggal dengan 20 + argumen siap untuk nilai default ( Nonesebagian besar waktu) dan kemudian harus biola sekitar menggunakan habisnya if, elif, elserantai untuk mencari tahu apa penelepon sebenarnya ingin fungsi kita berhubungan dengan set argumen yang disediakan. Ini sudah lama tertunda mengikuti Python Zen

Cantik lebih baik dari yang jelek.

dan bisa dibilang juga

Sederhana lebih baik daripada kompleks.

Langsung dari dokumentasi Python resmi yang ditautkan di atas:

from typing import overload
@overload
def process(response: None) -> None:
    ...
@overload
def process(response: int) -> Tuple[int, str]:
    ...
@overload
def process(response: bytes) -> str:
    ...
def process(response):
    <actual implementation>

persis apa yang saya cari, lebih rapi daripada mendefinisikan dekorator overload sendiri
pcko1

2
btw: bagi siapa saja yang bertanya-tanya mengapa ini tidak berhasil, saya sarankan untuk melihat diskusi di stackoverflow.com/questions/52034771/... - @overloadfungsi ed seharusnya tidak memiliki implementasi aktual. Ini tidak jelas dari contoh dalam dokumentasi Python.
masi

15

Saya menulis jawaban saya dengan Python 3.2.1.

def overload(*functions):
    return lambda *args, **kwargs: functions[len(args)](*args, **kwargs)

Bagaimana itu bekerja:

  1. overloadmengambil jumlah callable dan menyimpannya dalam tuple functions, lalu mengembalikan lambda.
  2. Lambda mengambil sejumlah argumen, lalu mengembalikan hasil fungsi panggilan yang disimpan dalam functions[number_of_unnamed_args_passed]dipanggil dengan argumen yang diteruskan ke lambda.

Pemakaian:

class A:
    stackoverflow=overload(                    \
        None, \ 
        #there is always a self argument, so this should never get called
        lambda self: print('First method'),      \
        lambda self, i: print('Second method', i) \
    )

14

Saya pikir kata yang Anda cari adalah "kelebihan beban". Tidak ada metode overloading di python. Namun Anda dapat menggunakan argumen default, sebagai berikut.

def stackoverflow(self, i=None):
    if i != None:     
        print 'second method', i
    else:
        print 'first method'

Ketika Anda memberikan argumen, itu akan mengikuti logika kondisi pertama dan menjalankan pernyataan cetak pertama. Ketika Anda tidak memberikan argumen, itu akan masuk ke elsekondisi dan menjalankan pernyataan cetak kedua.


13

Saya menulis jawaban saya dengan Python 2.7:

Dengan Python, metode overload tidak dimungkinkan; jika Anda benar-benar ingin mengakses fungsi yang sama dengan fitur yang berbeda, saya sarankan Anda menggunakan metode override.

class Base(): # Base class
    '''def add(self,a,b):
        s=a+b
        print s'''

    def add(self,a,b,c):
        self.a=a
        self.b=b
        self.c=c

        sum =a+b+c
        print sum

class Derived(Base): # Derived class
    def add(self,a,b): # overriding method
        sum=a+b
        print sum



add_fun_1=Base() #instance creation for Base class
add_fun_2=Derived()#instance creation for Derived class

add_fun_1.add(4,2,5) # function with 3 arguments
add_fun_2.add(4,2)   # function with 2 arguments

9

Dalam Python, overloading bukan konsep terapan. Namun, jika Anda mencoba membuat kasus di mana, misalnya, Anda ingin satu inisialisasi dijalankan jika melewati argumen tipe foodan inisialisasi lain untuk argumen tipe barkemudian, karena segala sesuatu di Python ditangani sebagai objek, Anda dapat memeriksa nama tipe kelas objek yang dilewati dan menulis penanganan bersyarat berdasarkan itu.

class A:
   def __init__(self, arg)
      # Get the Argument's class type as a String
      argClass = arg.__class__.__name__

      if argClass == 'foo':
         print 'Arg is of type "foo"'
         ...
      elif argClass == 'bar':
         print 'Arg is of type "bar"'
         ...
      else
         print 'Arg is of a different type'
         ...

Konsep ini dapat diterapkan ke beberapa skenario berbeda melalui metode yang berbeda sesuai kebutuhan.


7

Dengan Python, Anda akan melakukan ini dengan argumen default.

class A:

    def stackoverflow(self, i=None):    
        if i == None:
            print 'first method'
        else:
            print 'second method',i

5

Baru saja menemukan https://github.com/bintoro/overloading.py ini bagi siapa saja yang mungkin tertarik.

Dari readme repositori terkait:

overloading adalah modul yang menyediakan pengiriman fungsi berdasarkan jenis dan jumlah argumen runtime.

Ketika fungsi kelebihan dipanggil, dispatcher membandingkan argumen yang disediakan untuk tanda tangan fungsi yang tersedia dan memanggil implementasi yang menyediakan kecocokan paling akurat.

fitur

Validasi fungsi setelah registrasi dan aturan resolusi terperinci menjamin hasil yang unik dan terdefinisi dengan baik saat runtime. Menerapkan caching resolusi fungsi untuk kinerja luar biasa. Mendukung parameter opsional (nilai default) dalam tanda tangan fungsi. Mengevaluasi argumen posisi dan kata kunci saat menyelesaikan kecocokan terbaik. Mendukung fungsi mundur dan pelaksanaan kode bersama. Mendukung argumen polimorfisme. Mendukung kelas dan pewarisan, termasuk metode dan metode statis.


3

Python tidak mendukung metode overloading seperti Java atau C ++. Kami mungkin kelebihan metode, tetapi hanya dapat menggunakan metode yang ditetapkan terbaru.

# First sum method.
# Takes two argument and print their sum
def sum(a, b):
    s = a + b
    print(s)

# Second sum method
# Takes three argument and print their sum
def sum(a, b, c):
    s = a + b + c
    print(s)

# Uncommenting the below line shows an error    
# sum(4, 5)

# This line will call the second sum method
sum(4, 5, 5)

Kami perlu memberikan argumen opsional atau * argumen untuk memberikan jumlah argumen yang berbeda pada panggilan.

Atas perkenan dari https://www.geeksforgeeks.org/python-method-overloading/


Ini bukan kelebihan beban. Ini disebut menimpa. Yang kemudian didukung oleh Python. Yang pertama dapat diimplementasikan dengan dekorator.
Paebbels

2

Python 3.x termasuk perpustakaan pengetikan standar yang memungkinkan untuk metode overloading dengan menggunakan dekorator overload @. Sayangnya, ini untuk membuat kode lebih mudah dibaca, karena metode yang dihiasi dengan @ kelebihan perlu diikuti oleh metode yang tidak dihiasi yang menangani argumen yang berbeda. Lebih banyak dapat ditemukan di sini di sini tetapi untuk contoh Anda:

from typing import overload
from typing import Any, Optional
class A(object):
    @overload
    def stackoverflow(self) -> None:    
        print('first method')
    @overload
    def stackoverflow(self, i: Any) -> None:
        print('second method', i)
    def stackoverflow(self, i: Optional[Any] = None) -> None:
        if not i:
            print('first method')
        else:
            print('second method', i)

ob=A()
ob.stackoverflow(2)

1
"The" di akhir jawaban Anda membuat saya berpikir bahwa Anda belum selesai menulis jawaban Anda. Harap edit jawaban Anda untuk melengkapinya.
Artjom B.

0

Dalam file MathMethod.py

from multipledispatch import dispatch
@dispatch(int,int)
def Add(a,b):
   return a+b 
@dispatch(int,int,int)  
def Add(a,b,c):
   return a+b+c 
@dispatch(int,int,int,int)    
def Add(a,b,c,d):
   return a+b+c+d

Dalam file Main.py

import MathMethod as MM 
print(MM.Add(200,1000,1000,200))

Kita dapat membebani metode dengan menggunakan multipledispatch


Ini membutuhkan penggunaan paket multipledispatch ( pypi.org/project/multipledispatch ), yang bukan bagian dari inti python.
Antony

0

Python menambahkan dekorator @ overload dengan PEP-3124 untuk menyediakan gula sintaksis untuk overloading melalui inspeksi tipe - alih-alih hanya bekerja dengan menimpa.

Contoh kode tentang kelebihan muatan melalui @overload dari PEP-3124

from overloading import overload
from collections import Iterable

def flatten(ob):
    """Flatten an object to its component iterables"""
    yield ob

@overload
def flatten(ob: Iterable):
    for o in ob:
        for ob in flatten(o):
            yield ob

@overload
def flatten(ob: basestring):
    yield ob

ditransformasikan oleh @ overload-dekorator ke:

def flatten(ob):
    if isinstance(ob, basestring) or not isinstance(ob, Iterable):
        yield ob
    else:
        for o in ob:
            for ob in flatten(o):
                yield ob
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.