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

use*_*578 147 python overloading class

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

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

ob=A()
ob.stackoverflow(2)
Run Code Online (Sandbox Code Playgroud)

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

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

ob=A()
ob.stackoverflow()
Run Code Online (Sandbox Code Playgroud)

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

我该如何工作?

agf*_*agf 139

它的方法是重载而不是方法重写.在Python中,您可以在一个函数中完成所有操作:

class A:

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

ob=A()
ob.stackoverflow(2)
ob.stackoverflow()
Run Code Online (Sandbox Code Playgroud)

你不能在Python中有两个同名的方法 - 你不需要.

请参阅Python教程的Default Argument Values部分.有关要避免的常见错误,请参阅"最小惊讶"和可变默认参数.

编辑:有关Python 3.4中新的单一调度泛型函数的信息,请参阅PEP 443.

  • _并且你不需要to_ - 恕我直言,如果在C++中有方法重载会非常方便.好吧,它不是'需要',因为它不能使用其他结构来完成 - 但它会使一些事情变得更容易和更简单. (101认同)
  • 我想不同意一点;)...重载通常会使代码更清晰,因为你没有用太多if-else语句打包方法来处理不同的情况.从某种意义上说,整个函数式语言都使用类似的概念,即参数模式匹配.这意味着你会有更小的更清洁的方法..而不是巨大的不可读的方法. (33认同)
  • @AndreasFlorath我不同意.学会喜欢鸭子打字并编写每个方法,这样它只做一件事,而且不需要方法重载. (6认同)
  • 在我被抓住之前让我读到关于"要避免的常见错误"的+1 (4认同)
  • @agf:通过“厚脸皮”,我的意思是诸如“它不存在,因为不需要它”之类的答案对读者来说是低头的,这通常是不合理的。 (3认同)
  • @ user1019129这是Python 3.4中添加的单个调度泛型函数的目的,并在我的答案中链接. (2认同)
  • 所以我们必须明确地对传递给“单一调度泛型函数”的不同参数执行`if:`、`elif:`,如果说我们需要几个基于不同参数集执行不同操作的重载? (2认同)
  • @agf:我并不是真的在质疑(非)“需要”。C++ 也不“需要”它们,就像 C++ 不“需要”智能指针一样,因为人们可以手动管理内存。重载只是盒子里的另一个工具;一种可以将参数组合的显式和较慢的手动检查委托给解释器的调用解析级别。正如您所暗示的,它可以是用于提高代码健壮性的工具(因为当您重载时,解释器会为您进行检查)。 (2认同)
  • 当有人用“你不需要它”来描述缺失的功能时,认知失调会在一百英里之外响起。看在上帝的份上,重载比默认值强得多。强类型可以继续解决无数其他问题,但 Python 中并不存在,因为它是作为脚本语言诞生的,并且最近试图改变它。欣赏 Python 作为一种优秀的脚本语言,但不要忘记它是什么。真正的重载需要区分类型的原型,像 python 这样的脚本语言不会这样做,并且因此失去了很多优雅和可读性。 (2认同)

Ehs*_*ian 48

你也可以使用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
Run Code Online (Sandbox Code Playgroud)

  • 我认为这是问题的唯一有效答案.如果可以的话,我会双倍投票. (5认同)
  • 很好,但不适用于原始函数,仅适用于类中的方法。 (3认同)
  • @LegitStack 我更新了 GitHub 上的代码,现在它也可以使用函数了。 (3认同)

Chr*_*gan 46

在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'
Run Code Online (Sandbox Code Playgroud)

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

>>> ob = A()
>>> ob.stackoverflow()
first form
>>> ob.stackoverflow(2)
second form
Run Code Online (Sandbox Code Playgroud)

  • 通常,当您想要可变的默认值时,“无”很有用。单独的行为应在单独的功能中进行。 (2认同)

Kar*_*tel 24

你不能,永远不需要也不想真的.

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

有一个叫做A类的对象.它有一个名为的属性stackoverflow.它只能有一个这样的属性.

当您编写时def stackoverflow(...): ...,会发生的是您创建一个方法对象,并将其分配给该stackoverflow属性A.如果您编写两个定义,则第二个定义将替换第一个定义,与分配始终表现的方式相同.

此外,您不希望编写的代码可以解决有时用于重载的各种事物.这不是语言的运作方式.

而不是试图为每种类型的事物定义一个单独的函数(由于你没有指定函数参数的类型,这没什么意义),不要再担心事情什么,并开始考虑他们可以做什么.

你不仅不能写一个单独的处理元组与列表,而且也不想要或不需要.

你要做的只是利用它们都是可迭代的事实(即你可以写for element in container:).(它们与继承没有直接关系的事实是无关紧要的.)

  • TBH,我会更加小心"永远不需要".这可以在任何现实世界的每个特征上标记并且使用完整的编程语言,因此不是有效的参数.谁_需要发电机?谁_needs_上课?编程语言只是更具体的语法糖. (5认同)
  • 根据马西的回答,我想说“你不能”现在是不正确且过时的。基于“@overload”装饰器的存在,我想说“其实不想”充其量是有争议的。来自 PEP-3124,“...目前 Python 代码检查接收到的参数的类型是一种常见的反模式...执行此操作的“明显方法”是通过类型检查,但这很脆弱并且无法实现扩展...”所以似乎有足够多的人想要它成为 Python 的一部分。 (4认同)
  • 完全不同意。可能是您“不需要”或“从未想要”,但是有许多应用程序是您迫切想要的。尝试例如编写一个优雅地处理Python和numpy数组的程序,而不会因instanceof的设置而乱码... (3认同)

Gin*_*lus 16

我在Python 3.2.1中写了我的答案.

def overload(*functions):
    return lambda *args, **kwargs: functions[len(args)](*args, **kwargs)
Run Code Online (Sandbox Code Playgroud)

这个怎么运作:

  1. overload获取任意数量的callables并将它们存储在元组中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) \
    )
Run Code Online (Sandbox Code Playgroud)


may*_*ewr 14

我认为你要找的那个词是"超载".python中没有方法重载.但是,您可以使用默认参数,如下所示.

def stackoverflow(self, i=None):
    if i != None:     
        print 'second method', i
    else:
        print 'first method'
Run Code Online (Sandbox Code Playgroud)

当你传递一个参数时,它将遵循第一个条件的逻辑并执行第一个print语句.当你传递没有参数时,它将进入else条件并执行第二个print语句.


Moo*_*thu 13

我在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
Run Code Online (Sandbox Code Playgroud)


S. *_*gee 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'
         ...
Run Code Online (Sandbox Code Playgroud)

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


Voi*_*ler 8

python 3.5添加了打字模块。这包括一个重载装饰器。

该装饰器的预期目的是帮助类型检查器。从功能上来说,它只是鸭子打字。

from typing import Optional, overload


@overload
def foo(index: int) -> str:
    ...


@overload
def foo(name: str) -> str:
    ...


@overload
def foo(name: str, index: int) -> str:
    ...


def foo(name: Optional[str] = None, index: Optional[int] = None) -> str:
    return f"name: {name}, index: {index}"


foo(1)
foo("bar", 1)
foo("bar", None)
Run Code Online (Sandbox Code Playgroud)

这导致 VS Code 中出现以下类型信息:

vscode 中的结果

虽然这会有所帮助,但请注意,这会添加许多“奇怪的”新语法。它的目的——纯粹的类型提示——并不是立即显而易见的。

使用类型联合通常是更好的选择。


Joh*_*Jr. 7

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

class A:

    def stackoverflow(self, i=None):    
        if i == None:
            print 'first method'
        else:
            print 'second method',i
Run Code Online (Sandbox Code Playgroud)


mas*_*asi 6

虽然@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>
Run Code Online (Sandbox Code Playgroud)

  • 太疯狂了,必须滚动浏览至少 5 个“你不应该那样做!!” 要做到这一点,实际上要回答问题。谢谢@马西! (4认同)
  • @th3coop 这在某种程度上是可以预料的,因为这个问题和早期答案已经有多久了。当时,答案确实是“你可以通过黑客来做到这一点,但你可能不应该这样做”。一旦标准库中包含了一种实际的方法,就很容易推荐它。我知道 StackOverflow 正在研究一种按最相关的答案进行排序的方法,而不仅仅是那些有最多时间积累点赞的答案。 (3认同)

Mar*_*nce 5

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

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

重载是一个模块,它根据运行时参数的类型和数量提供函数调度.

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

特征

注册时的功能验证和详细的解决规则可确保在运行时获得独特,明确的结果.实现功能解析缓存以获得出色的性能.支持函数签名中的可选参数(默认值).在解析最佳匹配时评估位置和关键字参数.支持回退功能和共享代码的执行.支持参数多态性.支持类和继承,包括classmethods和staticmethods.


Ati*_*ska 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)
Run Code Online (Sandbox Code Playgroud)

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

礼貌Python | 方法重载