210

我正在尝试在 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)

我该如何进行这项工作?

4

15 回答 15

167

这是方法重载,而不是方法覆盖。在 Python 中,您可以在一个函数中完成所有操作:

class A:

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

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

在 Python 中你不能有两个同名的方法——你也不需要。

请参阅 Python 教程的默认参数值部分。请参阅“Least Astonishment”和 Mutable Default Argument以了解要避免的常见错误。

有关Python 3.4 中新的单调度泛型函数的信息,请参阅PEP 443 。

于 2012-04-18T04:53:05.673 回答
89

您还可以使用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
于 2015-04-26T12:11:53.100 回答
50

在 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
于 2012-04-18T04:55:24.180 回答
49

虽然agf 过去的答案是正确的 pre-3.4,但现在有了PEP-3124,我们得到了我们的语法糖。

有关装饰器的详细信息,请参阅打字文档@overload,但请注意,这实际上只是语法糖,恕我直言,这是人们从那时起一直在争论的问题。

就我个人而言,我同意拥有多个具有不同签名的函数使其更具可读性,然后将具有 20 多个参数的单个函数都设置为默认值(None大多数情况下),然后不得不摆弄使用无穷无尽if的 , elif,else链来找出调用者实际上希望我们的函数对提供的参数集做什么。这在 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>

编辑:对于任何想知道为什么这个例子没有像你期望的那样工作的人,如果我建议从其他语言看一下这个讨论。这些@overloaded功能不应该有任何实际的实现。这在 Python 文档中的示例中并不明显。

于 2018-09-23T16:27:48.057 回答
24

你不能,永远不需要,也不想这样做。

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

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

当您编写def stackoverflow(...): ...时,会发生什么是您创建一个作为方法的对象,并将其分配给 的stackoverflow属性A。如果你写了两个定义,第二个会替换第一个,就像赋值总是一样。

此外,您不想编写代码来执行重载有时使用的更疯狂的事情。这不是语言的工作方式。

与其尝试为可能给定的每种类型的事物定义一个单独的函数(这没有什么意义,因为无论如何您都没有为函数参数指定类型),而是停止担心事物什么并开始思考它们可以做什么

您不仅不能单独编写一个来处理元组与列表,而且也不希望或不需要.

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

于 2012-04-18T06:24:51.587 回答
17

我认为您正在寻找的词是“重载”。Python 中没有任何方法重载。但是,您可以使用默认参数,如下所示。

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

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

于 2012-04-18T04:54:54.577 回答
15

我在 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) \
    )
于 2014-10-24T19:07:46.837 回答
14

我在 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
于 2015-07-15T07:00:57.207 回答
9

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

这个概念可以根据需要通过不同的方法应用于多个不同的场景。

于 2016-09-26T21:30:08.490 回答
7

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

class A:

    def stackoverflow(self, i=None):    
        if i == None:
            print 'first method'
        else:
            print 'second method',i
于 2012-04-18T04:55:29.240 回答
5

我刚刚遇到了可能感兴趣的任何人的重载.py(Python 3 的函数重载)

从链接存储库的 README 文件中:

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

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

特征

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

于 2015-02-06T20:51:53.783 回答
5

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 以便在调用时提供不同数量的参数。

礼貌Python | 方法重载

于 2018-05-28T19:53:41.403 回答
3

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)
于 2018-10-10T15:26:23.177 回答
2

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
于 2020-06-21T05:02:07.850 回答
2

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

我们可以通过使用multipledispatch 来重载该方法。

于 2018-04-23T08:46:36.937 回答