我试图在Python中实现方法重载:
class A:
def stackoverflow(self):
print 'first method'
def stackoverflow(self, i):
print 'second method', i
ob=A()
ob.stackoverflow(2)
但是输出是第二种方法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)
我该怎么做呢?
我用Python 3.2.1写了我的答案。
def overload(*functions):
return lambda *args, **kwargs: functions[len(args)](*args, **kwargs)
工作原理:
Overload接受任意数量的可调用对象,并将它们存储在元组函数中,然后返回lambda。
接受任意数量的参数,
然后返回存储在函数[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) \
)
我用Python 3.2.1写了我的答案。
def overload(*functions):
return lambda *args, **kwargs: functions[len(args)](*args, **kwargs)
工作原理:
Overload接受任意数量的可调用对象,并将它们存储在元组函数中,然后返回lambda。
接受任意数量的参数,
然后返回存储在函数[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) \
)
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中,所有东西都是对象。类是事物,所以它们是对象。方法也是如此。
有一个对象叫做A,它是一个类。它有一个名为stackoverflow的属性。它只能有一个这样的属性。
当你写def stackoverflow(…):…,所发生的是你创建一个对象,它是方法,并将它赋值给a的stackoverflow属性。如果你写了两个定义,第二个会替换第一个,这与赋值的行为相同。
此外,您也不希望编写的代码执行重载有时会用到的那种过分的操作。语言不是这样的。
与其尝试为可能给定的每种类型的东西定义一个单独的函数(这没什么意义,因为你没有为函数参数指定类型),不如停止担心这些东西是什么,开始思考它们能做什么。
您不仅不能单独编写一个来处理元组和列表,而且也不想或不需要这样做。
你所要做的就是利用它们都是可迭代的这一事实,例如,你可以写for element in container:)。(他们之间没有直接的遗传关系,这一点无关紧要。)
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)
这将导致vs code中的以下类型信息:
虽然这可能有所帮助,但请注意,这添加了许多“奇怪的”新语法。它的目的——纯粹的类型提示——不是很明显。
使用类型的联合通常是更好的选择。