如何在Python中使用方法重载?

问题:如何在Python中使用方法重载?

我正在尝试在Python中实现方法重载:

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

ob=A()
ob.stackoverflow(2)

但是输出是second method 2; 类似地:

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

ob=A()
ob.stackoverflow()

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

我该如何工作?

I am trying to implement method overloading in Python:

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

ob=A()
ob.stackoverflow(2)

but the output is second method 2; similarly:

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

ob=A()
ob.stackoverflow()

gives

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

How do I make this work?


回答 0

它是方法重载而不是方法重写。在Python中,您可以通过一个函数来完成全部操作:

class A:

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

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

在Python中,不能有两个具有相同名称的方法,而且也不需要。

请参阅Python教程的默认参数值部分。有关避免的常见错误,请参见“最小惊讶”和“可变默认参数 ”。

编辑:有关Python 3.4中新的单调度通用功能的信息,请参阅PEP 443

It’s method overloading not method overriding. And in Python, you do it all in one function:

class A:

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

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

You can’t have two methods with the same name in Python — and you don’t need to.

See the Default Argument Values section of the Python tutorial. See “Least Astonishment” and the Mutable Default Argument for a common mistake to avoid.

Edit: See PEP 443 for information about the new single dispatch generic functions in Python 3.4.


回答 1

您还可以使用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

You can also use 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

回答 2

在Python中,您不会那样做。当人们使用Java之类的语言来执行此操作时,他们通常希望使用默认值(如果不需要,则通常需要使用其他名称的方法)。因此,在Python中,您可以具有默认值

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'

如您所见,您可以使用它来触发单独的行为,而不仅仅是具有默认值。

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

In Python, you don’t do things that way. When people do that in languages like Java, they generally want a default value (if they don’t, they generally want a method with a different name). So, in Python, you can have default values.

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'

As you can see, you can use this to trigger separate behaviour rather than merely having a default value.

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

回答 3

您可以,永远也不需要,也不需要。

在Python中,一切都是对象。类是事物,所以它们是对象。方法也是如此。

有一个称为A类的对象。它具有称为的属性stackoverflow。它只能具有一个这样的属性。

在编写时def stackoverflow(...): ...,发生的事情是创建一个方法对象,并将其分配给的stackoverflow属性A。如果您编写两个定义,则第二个定义将替换第一个定义,即分配始终起作用。

此外,您也不想编写执行有时用于重载的各种事情的代码。这不是这种语言的工作方式。

不要试图为每种类型的事物定义一个单独的函数(这毫无意义,因为您始终不为函数参数指定类型),而不必担心事物什么而开始思考它们可以做什么

您不仅不能编写一个单独的元组来处理一个元组还是一个列表,而且不想要也不需要

您要做的就是利用它们都是可迭代的事实(例如,您可以编写for element in container:)。(它们与继承没有直接关系这一事实无关紧要。)

You can’t, never need to and don’t really want to.

In Python, everything is an object. Classes are things, so they are objects. So are methods.

There is an object called A which is a class. It has an attribute called stackoverflow. It can only have one such attribute.

When you write def stackoverflow(...): ..., what happens is that you create an object which is the method, and assign it to the stackoverflow attribute of A. If you write two definitions, the second one replaces the first, the same way that assignment always behaves.

You furthermore do not want to write code that does the wilder of the sorts of things that overloading is sometimes used for. That’s not how the language works.

Instead of trying to define a separate function for each type of thing you could be given (which makes little sense since you don’t specify types for function parameters anyway), stop worrying about what things are and start thinking about what they can do.

You not only can’t write a separate one to handle a tuple vs. a list, but also don’t want or need to.

All you do is take advantage of the fact that they are both, for example, iterable (i.e. you can write for element in container:). (The fact that they aren’t directly related by inheritance is irrelevant.)


回答 4

虽然@agf过去使用PEP-3124正确地回答了问题,但我们得到了语法糖。有关装饰器的详细信息 ,请参见键入文档。@overload但是请注意,这实际上只是语法糖,恕我直言,这是所有人们从那时以来一直在参数的话题。我个人认为,具有不同特征的多个功能,使它更具可读性则具有20+的参数都设置为默认值(单个功能None的大部分时间),然后不得不反复折腾使用不已ifelifelse链找出什么调用者实际上希望我们的函数处理提供的参数集。在Python Zen之后,早就应该这样做了

美丽胜于丑陋。

并且可以说也是

简单胜于复杂。

直接来自上面链接的官方Python文档:

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>

While @agf was right with the answer in the past now with PEP-3124 we got our syntax sugar. See typing documentation for details on the @overload decorator but note that this is really just syntax sugar and IMHO this is all people have been arguing about ever since. Personally I agree that having multiple functions with different signatures makes it more readable then having a single function with 20+ arguments all set to a default value (None most of the time) and then having to fiddle around using endless if, elif, else chains to find out what the caller actually wants our function to do with the provided set of arguments. This was long overdue following the Python Zen

Beautiful is better than ugly.

and arguably also

Simple is better than complex.

Straight from the official Python documentation linked above:

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>

回答 5

我用Python 3.2.1写出答案。

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

这个怎么运作:

  1. overload接受任意数量的可调用对象并将其存储在tuple中functions,然后返回lambda。
  2. lambda接受任意数量的参数,然后返回存储在functions[number_of_unnamed_args_passed]被调用中的调用函数的结果,并带有传递给lambda的参数。

用法:

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

I write my answer in Python 3.2.1.

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

How it works:

  1. overload takes any amount of callables and stores them in tuple functions, then returns lambda.
  2. The lambda takes any amount of arguments, then returns result of calling function stored in functions[number_of_unnamed_args_passed] called with arguments passed to the lambda.

Usage:

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

回答 6

我认为您要查找的单词是“超载”。python中没有方法重载。但是,您可以使用默认参数,如下所示。

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

当您传递参数时,它将遵循第一个条件的逻辑并执行第一个print语句。当您不传递任何参数时,它将进入else条件并执行第二个print语句。

I think the word you’re looking for is “overloading”. There is no method overloading in python. You can however use default arguments, as follows.

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

When you pass it an argument it will follow the logic of the first condition and execute the first print statement. When you pass it no arguments, it will go into the else condition and execute the second print statement.


回答 7

我用Python 2.7写下答案:

在Python中,方法重载是不可能的。如果您真的想访问具有不同功能的相同功能,建议您进行方法重写。

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

I write my answer in Python 2.7:

In Python, method overloading is not possible; if you really want access the same function with different features, I suggest you to go for method overriding.

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

回答 8

在Python中,重载不是一个可应用的概念。但是,如果您试图创建一种情况,例如,如果要传递一个类型foo为实参的参数,而又要为类型为实参的参数,则希望执行一个初始化程序bar,因为Python中的所有内容都作为对象处理,因此您可以检查传递的对象的类类型的名称,并根据该条件编写条件处理。

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

根据需要,可以通过不同的方法将此概念应用于多个不同的方案。

In Python, overloading is not an applied concept. However, if you are trying to create a case where, for instance, you want one initializer to be performed if passed an argument of type foo and another initializer for an argument of type bar then, since everything in Python is handled as object, you can check the name of the passed object’s class type and write conditional handling based on that.

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

This concept can be applied to multiple different scenarios through different methods as needed.


回答 9

在Python中,您可以使用默认参数来执行此操作。

class A:

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

In Python, you’d do this with a default argument.

class A:

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

回答 10

刚刚遇到这个https://github.com/bintoro/overloading.py的人可能感兴趣。

从链接的存储库的自述文件中:

重载是一个基于运行时参数的类型和数量提供功能分派的模块。

调用重载函数时,调度程序将提供的参数与可用函数签名进行比较,并调用提供最准确匹配的实现。

特征

注册时的功能验证和详细的解决规则可确保在运行时具有唯一的,定义明确的结果。实现功能解析缓存以获得出色的性能。在函数签名中支持可选参数(默认值)。解决最佳匹配时,同时评估位置参数和关键字参数。支持后备功能和共享代码的执行。支持参数多态性。支持类和继承,包括类方法和静态方法。

Just came across this https://github.com/bintoro/overloading.py for anybody who may be interested.

From the linked repository’s readme:

overloading is a module that provides function dispatching based on the types and number of runtime arguments.

When an overloaded function is invoked, the dispatcher compares the supplied arguments to available function signatures and calls the implementation that provides the most accurate match.

Features

Function validation upon registration and detailed resolution rules guarantee a unique, well-defined outcome at runtime. Implements function resolution caching for great performance. Supports optional parameters (default values) in function signatures. Evaluates both positional and keyword arguments when resolving the best match. Supports fallback functions and execution of shared code. Supports argument polymorphism. Supports classes and inheritance, including classmethods and staticmethods.


回答 11

Python不支持Java或C ++之类的方法重载。我们可能会重载这些方法,但只能使用最新定义的方法。

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

我们需要提供可选参数或* args,以便在调用时提供不同数量的args。

来自https://www.geeksforgeeks.org/python-method-overloading/

Python does not support method overloading like Java or C++. We may overload the methods but can only use the latest defined method.

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

We need to provide optional arguments or *args in order to provide different number of args on calling.

Courtesy from https://www.geeksforgeeks.org/python-method-overloading/


回答 12

Python 3.x包含标准的类型库,该库允许使用@overload装饰器来重载方法。不幸的是,这是为了使代码更具可读性,因为@overload装饰的方法将需要后面跟一个处理不同参数的非装饰方法。在这里可以找到更多信息但以您的示例为例:

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)

Python 3.x includes standard typing library which allows for method overloading with the use of @overload decorator. Unfortunately, this is to make the code more readable, as the @overload decorated methods will need to be followed by a non-decorated method that handles different arguments. More can be found here here but for your example:

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)

回答 13

在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

在Main.py文件中

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

我们可以通过使用multidispatch重载方法

In MathMethod.py file

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

In Main.py file

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

We can overload method by using multipledispatch


回答 14

Python在PEP-3124中添加了@overload装饰器,以通过类型检查为重载提供语法糖-而不是仅仅进行覆盖。

PEP-3124中通过@overload重载的代码示例

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

由@ overload-decorator转换为:

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

Python added the @overload decorator with PEP-3124 to provide syntactic sugar for overloading via type inspection – instead of just working with overwriting.

Code example on overloading via @overload from 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

is transformed by the @overload-decorator to:

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