关于类:如何在Python中使用方法重载?

How do I use method overloading in Python?

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

1
2
3
4
5
6
7
8
class A:
    def stackoverflow(self):    
        print 'first method'
    def stackoverflow(self, i):
        print 'second method', i

ob=A()
ob.stackoverflow(2)

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

1
2
3
4
5
6
7
8
class A:
    def stackoverflow(self):    
        print 'first method'
    def stackoverflow(self, i):
        print 'second method', i

ob=A()
ob.stackoverflow()

给予

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

我该怎么做?


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

1
2
3
4
5
6
7
8
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。


在python中,您不会这样做。当人们用Java语言这样做时,他们通常想要一个默认值(如果他们不这样,他们通常需要一个不同名称的方法)。所以,在python中,可以有默认值。

1
2
3
4
5
6
7
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'

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

1
2
3
4
5
>>> ob = A()
>>> ob.stackoverflow()
first form
>>> ob.stackoverflow(2)
second form


您也可以使用pythonlangutil:

1
2
3
4
5
6
7
8
9
10
11
12
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

编辑:通过在python 3中对重载的官方支持,您可以使用@overload decorator。


你不能,不需要,也不想。

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

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

当您编写def stackoverflow(...): ...时,会发生的情况是创建一个对象,该对象就是方法,并将其分配给Astackoverflow属性。如果编写两个定义,第二个定义将替换第一个定义,与赋值的行为方式相同。

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

不要试图为每种类型的对象定义一个单独的函数(这是毫无意义的,因为您无论如何都不为函数参数指定类型),不要担心这些对象是什么,开始考虑它们可以做什么。

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

你所做的就是利用它们都是不可更改的这一事实(例如,你可以写for element in container:)。(事实上,它们与继承没有直接联系是不相关的。)


我用python 3.2.1编写了我的答案。

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

它是如何工作的:

  • overload接受任意数量的可调用文件并将其存储在tuple functions中,然后返回lambda。
  • lambda接受任何数量的参数,然后返回存储在functions[number_of_unnamed_args_passed]中的调用函数的结果,调用时将参数传递给lambda。
  • 用途:

    1
    2
    3
    4
    5
    6
    7
    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) \
        )


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

    1
    2
    3
    4
    5
    def stackoverflow(self, i=None):
        if i != None:    
            print 'second method', i
        else:
            print 'first method'

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


    我用python 2.7写了我的答案:

    在Python中,方法重载是不可能的;如果您真的想要访问具有不同特性的同一个函数,我建议您进行方法重写。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    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


    在Python中,重载不是一个应用的概念。但是,如果您试图创建这样一种情况:例如,如果传递了foo类型的参数,则需要执行一个初始值设定项;如果传递了bar类型的参数,则需要执行另一个初始值设定项;那么,由于python中的所有内容都是作为对象处理的,因此可以检查传递对象的类类型的名称,并编写条件h基于此进行处理。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    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'
             ...

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


    在python中,您可以使用默认参数来实现这一点。

    1
    2
    3
    4
    5
    6
    7
    class A:

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

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

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

    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.


    虽然@agf过去对pep-3124的回答是正确的,但我们得到了语法建议。有关@overload装饰器的详细信息,请参阅键入文档,但请注意,这实际上只是语法sugger和imho,这是所有人从那以后一直在争论的问题。我个人认为,拥有多个具有不同签名的函数会使它更易于阅读,然后拥有一个具有20多个参数的函数,这些参数都设置为默认值(大多数情况下都是None,然后不得不使用无休止的ifelifelse链来查找调用者实际想要的内容。函数处理提供的参数集。这,这是在python zen之后很久以前的事了

    Beautiful is better than ugly.

    也可以说

    Simple is better than complex.

    直接从上面链接的官方python文档:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @overload
    def process(response: None) -> None:
        ...
    @overload
    def process(response: int) -> Tuple[int, str]:
        ...
    @overload
    def process(response: bytes) -> str:
        ...
    def process(response):


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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    # 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)

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

    由https://www.geeksforgeks.org/python-method-overloading提供/


    python 3.x包含标准类型库,允许使用@overload decorator进行方法重载。不幸的是,这是为了提高代码的可读性,因为@overload修饰方法后面需要有一个处理不同参数的非修饰方法。在这里可以找到更多,但是对于您的示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    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)


    在mathmethod.py文件中

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    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文件

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

    我们可以使用multipledispatch来重载方法