Python'da yöntem aşırı yüklemesini nasıl kullanabilirim?


169

Python yöntem aşırı yükleme uygulamak çalışıyorum:

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

ob=A()
ob.stackoverflow(2)

ancak çıktı second method 2; benzer şekilde:

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

ob=A()
ob.stackoverflow()

verir

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

Bunu nasıl yapabilirim?


39
Python'da, yöntemleri özel bir " öznitelikler " kümesi olarak düşünün ve bir nesne için belirli bir adın yalnızca bir " özniteliği " (ve dolayısıyla bir yöntemi) olabilir. Son yöntem önceki yöntemlerin üzerine yazılır . Java'da yöntemler birinci sınıf vatandaşlar değildir ("nesnelerin öznitelikleri" değildir), en yakın türe ( aşırı yüklenmenin geldiği yere ) göre statik olarak çözümlenen "ileti gönderme" ile çağrılırlar .



6
Bu sorunun cevapları neden henüz kabul edilmiyor? En sevdiğiniz cevabın solundaki onay işaretine tıklamanız yeterli ...
glglgl

Yanıtlar:


150

It yöntemi aşırı yükleme yöntemi değildir basan . Ve Python'da hepsini tek bir işlevde yaparsınız:

class A:

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

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

Python'da aynı ada sahip iki yönteminiz olamaz ve buna gerek yoktur.

Bkz Standart Argüman Değerler Python öğretici bölümüne. Kaçınılması gereken yaygın bir hata için "En Küçük Şaşkınlık" ve Değişken Varsayılan Argüman'a bakınız .

Düzenleme : Python 3.4'teki yeni tek dağıtım genel işlevleri hakkında bilgi için PEP 443'e bakın .


120
ve gerek yok - IMHO bazen yöntem aşırı yükleme gibi C ++ gibi çok kullanışlı olurdu. Tamam, başka yapılar kullanılarak yapılamayacağı anlamında 'gerekli' değildir - ama bazı şeyleri daha kolay ve basit hale getirir.
Andreas Florath

7
@AndreasFlorath katılmıyorum. Ördek yazmayı sevmeyi ve her yöntemi yazmayı öğrenin, böylece sadece bir şey yapar ve yöntem aşırı yüklenmesine gerek yoktur.
agf

4
Yakalanmadan önce beni "önlemek için yaygın hata" hakkında okumak için +1
mdup

44
Ben biraz katılmıyorum istiyorum;) ... aşırı yükleme genellikle kod temiz yapmak, çünkü farklı durumlarda işlemek için çok fazla if-else deyimi ile yöntemi paketi yok. Bir anlamda işlevsel dillerin tüm gamı ​​benzer bir fikir kullanır, yani argüman-desen eşleşmesi. Bu da dev okunamayanlardan daha küçük, daha temiz yöntemlere sahip olacağınız anlamına geliyor.
sten

2
@ user1019129 Python 3.4'e eklenen ve cevabımda bağlantılı olan tek gönderim genel fonksiyonlarının amacı budur.
agf

62

Ayrıca pythonlangutil kullanabilirsiniz :

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
Sorunun tek geçerli cevabı olduğunu düşünüyorum. Yapabilseydim ikiye katlanırdım.
Michael

3
iyi, ama ham işlevler üzerinde çalışmıyor, sadece bir sınıftaki yöntemler.
Yasal Yığın

1
@LegitStack Bu işlevsellik de eklenebilir. İmkansız değil.
Ehsan Keshavarzian

3
@LegitStack GitHub'daki kodu güncelledim, şimdi işlevlerle de çalışıyor.
Ehsan Keshavarzian

1
@PaulPrice Doğru. Cevabımı güncelledim ve resmi destek bölümünü kaldırdım. Aşırı yükler göndermek için kodumu kullanmaya devam edebilirsiniz. Artık hem yöntem hem de işlevlerle çalışıyor. Kodu GitHub'dan alın. Henüz PyPi'yi güncellemedim.
Ehsan Keshavarzian

48

Python'da işleri böyle yapmazsınız. İnsanlar bunu Java gibi dillerde yaptığında, genellikle varsayılan bir değer ister (istemezlerse, genellikle farklı bir ada sahip bir yöntem ister). Yani, Python'da varsayılan değerlere sahip olabilirsiniz .

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'

Gördüğünüz gibi, sen yapabilirsiniz sadece bir varsayılan değer olan yerine farklı davranışa tetiklemek için kullanacağız.

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

2
Çoğunlukla Nonedeğiştirilebilir varsayılan bir değer istediğinizde kullanışlıdır. Ayrı davranış ayrı işlevlerde olmalıdır.
agf

@ agf: Noneorijinal bir varsayılan değer olarak da yararlı olabilir.
Chris Morgan

Evet, ama bunu bir sentinel değeri olarak kullanmaktan bahsediyordum, bu cevabı cevabınızda nasıl kullanıyorsunuz ve bence yorumum netleşiyor.
agf

"genellikle" mi diyorsun? bunun her zaman böyle olmadığını mı ima ediyorsun?
joel

24

Yapamazsınız, asla gerek yoktur ve gerçekten istemezsiniz.

Python'da her şey bir nesnedir. Sınıflar bir şeydir, yani nesnelerdir. Yöntemler de öyle.

ABir sınıf olan bir nesne var . Adlı bir özniteliği vardır stackoverflow. Böyle bir niteliğe sahip olabilir.

Yazdığınızda def stackoverflow(...): ..., yöntem olan bir nesne oluşturmanız ve nesnesinin stackoverflowniteliğine atamanız gerekir A. İki tanım yazarsanız, ikincisi ödevin yerine geçer, ödev her zamanki gibi.

Ayrıca, aşırı yüklenmenin bazen için kullanıldığı şeyleri daha vahşi yapan kod yazmak istemezsiniz. Dil böyle çalışmaz.

Verilebilecek her bir şey türü için ayrı bir işlev tanımlamaya çalışmak yerine (işlev parametreleri için türler belirtmediğiniz için çok az mantıklıdır), şeylerin ne olduğu konusunda endişelenmeyi bırakın ve yapabilecekleri hakkında düşünmeye başlayın .

Bir listeyi ve bir listeyi işlemek için sadece ayrı bir tane yazamazsınız, aynı zamanda istemek veya istemek de gerekmez .

Tek yaptığınız, her ikisinin de örneğin yinelenebilir (yani yazabilirsiniz for element in container:) olmasından yararlanmaktır . (Kalıtımla doğrudan ilişkili olmamaları önemsizdir.)


6
TBH, "asla gerek duymuyorum" konusunda daha dikkatli olurdum. Bu, herhangi bir gerçek dünyanın her özelliğine etiketlenebilir ve tam programlama diline çevrilebilir ve bu nedenle geçerli bir argüman değildir. Kimin jeneratörlere ihtiyacı var ? Kim derse ihtiyaç duyar ? Programlama dilleri daha somut bir şeye sadece sözdizimsel şekerdir.
Sebastian Mach

6
Kesinlikle katılmıyorum. "Asla ihtiyaç duymadınız" veya "asla istemediniz" olabilir, ancak umutsuzca istediğiniz yerde yeterli uygulama vardır. Örneğin, instanceof's ile programınızı çöpe atmadan hem Python hem de numpy dizilerini işleyen bir program yazmayı deneyin ...
Elmar Zander

1
Masi'nin cevabına dayanarak, "yapamazsınız" ın artık yanlış ve eski olduğunu söyleyebilirim. @overloadDekoratörün varlığına dayanarak, "gerçekten istemiyorum" un en iyi tartışmalı olduğunu söyleyebilirim. PEP-3124'ten "... şu anda Python kodunun alınan argüman türlerini incelemesi için yaygın bir anti-kalıptır ... bunu yapmanın 'bariz yolu' tip denetimidir, ancak bu kırılgan ve kapalıdır. "Python'un bir parçası haline gelmiş gibi görünüyor.
Mike S

@MikeS, standart @overloadyalnızca yazmak içindir.
Narfanar

@Narfanar Yanıtınızın yorumum için nasıl geçerli olduğunu bilmiyorum. Açıklayabilir misiniz?
Mike S

16

@Agf geçmişte PEP-3124 ile doğru cevap verirken sözdizimi şekeri aldık. Dekoratörle ilgili ayrıntılar için yazım belgelerine bakın , @overloadancak bunun gerçekten sadece sözdizimi şekeri olduğunu ve IMHO'nun o zamandan beri tartıştığı tüm insanlar olduğunu unutmayın. Şahsen ben farklı imzalara sahip birden fazla işlevi olan daha sonra 20+ argümanlar varsayılan bir değere tüm seti (tek bir fonksiyona sahip daha okunaklı hale getirir konusunda hemfikir Nonesonsuz kullanarak uğraşmak zorunda ardından çoğu zaman) ve if, elif, elseöğrenmek için zincirleri neyi arayan aslında fonksiyonumuzun sunulan argüman setiyle ilgili olmasını ister. Bu Python Zen'den sonra gecikmişti

Güzel, çirkin olmaktan iyidir.

ve tartışmasız olarak

Basit, karmaşık olmaktan iyidir.

Doğrudan bağlantılı resmi Python belgelerinden:

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>

tam olarak ne aradığını, kendi aşırı yük dekoratör tanımlamaktan daha neater
pcko1

2
btw: bunun neden çalışmadığını merak eden herkes için stackoverflow.com/questions/52034771/… adresindeki tartışmaya bakmanızı öneririm - @overloaded işlevlerinin gerçek bir uygulaması olması gerekmez. Bu, Python belgelerindeki örnekte açık değildir.
masi

15

Cevabımı Python 3.2.1'de yazıyorum.

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

Nasıl çalışır:

  1. overloadherhangi bir miktarda callables alır ve bunları demet halinde saklar functions, sonra lambda döndürür.
  2. Lambda herhangi bir miktarda argüman alır, sonra functions[number_of_unnamed_args_passed]lambda'ya iletilen argümanlar ile çağrılan çağrı işlevinin sonucunu döndürür .

Kullanımı:

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

Bence aradığınız kelime "aşırı". Python'da aşırı yükleme yöntemi yoktur. Ancak, varsayılan bağımsız değişkenleri aşağıdaki gibi kullanabilirsiniz.

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

Bir argüman ilettiğinizde, ilk koşulun mantığını izler ve ilk print deyimini yürütür. Hiçbir argüman ilettiğinizde, elsekoşula gider ve ikinci print deyimini yürütür.


13

Cevabımı Python 2.7'de yazıyorum:

Python'da yöntem aşırı yüklenmesi mümkün değildir; farklı işlevlerle aynı işleve gerçekten erişmek istiyorsanız, yöntem geçersiz kılmayı tercih etmenizi öneririm.

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

Python'da aşırı yükleme uygulanan bir kavram değildir. Bununla birlikte, örneğin, bir tür bağımsız değişkenini ve bir tür foobağımsız değişkeni için başka bir başlatıcıyı geçtiyse bir başlatıcı gerçekleştirilmesini istediğiniz bir durum oluşturmaya çalışıyorsanız bar, Python'daki her şey nesne olarak ele alındığından, iletilen nesnenin sınıf türünün adı ve buna dayalı koşullu işlem yazma.

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'
         ...

Bu kavram, gerektiğinde farklı yöntemlerle birden fazla farklı senaryoya uygulanabilir.


7

Python'da bunu varsayılan bir argümanla yaparsınız.

class A:

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

5

İlgilenebilecek herkes için bu https://github.com/bintoro/overloading.py ile karşılaştım .

Bağlantılı deponun benioku dosyasından:

aşırı yükleme, çalışma zamanı argümanlarının türlerine ve sayısına göre işlev gönderilmesini sağlayan bir modüldür.

Aşırı yüklenmiş bir işlev çağrıldığında, dağıtım programı sağlanan bağımsız değişkenleri kullanılabilir işlev imzalarıyla karşılaştırır ve en doğru eşleşmeyi sağlayan uygulamayı çağırır.

Özellikleri

Kayıt sırasında işlev doğrulaması ve ayrıntılı çözümleme kuralları çalışma zamanında benzersiz, iyi tanımlanmış bir sonucu garanti eder. Mükemmel performans için işlev çözünürlüğü önbelleği uygular. İşlev imzalarında isteğe bağlı parametreleri (varsayılan değerler) destekler. En iyi eşleşmeyi çözerken hem konumsal hem de anahtar kelime bağımsız değişkenlerini değerlendirir. Yedek fonksiyonları ve paylaşılan kodun yürütülmesini destekler. Argüman polimorfizmini destekler. Sınıf yöntemleri ve statik yöntemler dahil olmak üzere sınıfları ve kalıtımı destekler.


3

Python, Java veya C ++ gibi aşırı yükleme yöntemini desteklemez. Yöntemleri aşırı yükleyebiliriz, ancak yalnızca en son tanımlanan yöntemi kullanabiliriz.

# 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)

Arama sırasında farklı sayıda bağımsız değişken sağlamak için isteğe bağlı bağımsız değişkenler veya * bağımsız değişkenler sağlamalıyız.

Https://www.geeksforgeeks.org/python-method-overloading/ adresinden nezaket


Bu aşırı yüklenmiyor. Buna üzerine yazma denir. Sonuncusu Python tarafından desteklenir. Birincisi dekoratörler ile uygulanabilir.
Paebbels

2

Python 3.x, @overload dekoratör kullanılarak yöntem aşırı yüklenmesine izin veren standart yazma kütüphanesini içerir. Ne yazık ki, bu kodu daha okunabilir kılmaktır, çünkü @overload dekore edilmiş yöntemlerin farklı argümanları işleyen dekore edilmemiş bir yöntem izlemesi gerekecektir. Daha fazlasını burada bulabilirsiniz, ancak örneğiniz için:

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
Cevabınızın sonundaki “The” cevabınızı yazmayı bitirmediğinizi düşündürüyor. Lütfen cevabınızı tamamlamak için düzenleyin .
Artjom B.10

0

MathMethod.py dosyasında

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

Main.py dosyasında

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

Multipledispatch kullanarak yöntemi aşırı yükleyebiliriz


Bu , python çekirdeğinin bir parçası olmayan multipledispatch paketinin ( pypi.org/project/multipledispatch ) kullanılmasını gerektirir .
Antony

0

Python , sadece üzerine yazma ile çalışmak yerine, tip denetimi yoluyla aşırı yükleme için sözdizimsel şeker sağlamak için @ overload dekoratörünü PEP-3124 ile ekledi .

PEP-3124'ten @overload üzerinden aşırı yükleme ile ilgili kod örneği

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

@ aşırı yük dekoratörü tarafından şu şekilde dönüştürülür:

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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.