例如,假设你有一个函数:
def foo(a):
return a
并且有大量的遗留代码使用此函数:
amount = 4 + foo(a)
如果我需要在不破坏现有代码的情况下增加foo
的返回值怎么办?
def foo(a)
return a, a + 5
现在,当我这样做时,变量amount
不是正确答案,因为a
现在,用皮林特的话来说,"一个元组",所以amount
将从返回a + 4
变为返回(a, a+5) + 4
。
如何将a + 5
添加到foo
,同时仍然允许数量是单个标量值,而不是元组?
也许这样的事情会起作用:
def foo(a, new_usage=False):
if not new_usage:
return a
return a + 5
然后针对所有新的使用情况像这样调用您的函数:
foo(a, True)
例如,您的旧代码仍然可以工作:
In [40]: amount = 4 + foo(4)
In [41]: amount
Out[41]: 8
对于新用法,您可以这样做:
In [42]: amount = 4 + foo(4, True)
In [43]: amount
Out[43]: 13
一个更优雅的解决方案是将foo
变成一个扩展int
(或float
,取决于旧foo()
的输出)的类,同时实现__iter__
方法以允许它在序列上下文中使用时作为序列解压缩:
class foo(int):
def __iter__(self):
return iter((self, self + 5))
因此:
amount = 4 + foo(1) # used as an int
print(amount)
a, b = foo(1) # used in a sequence context so foo.__iter__ is called
print(a, b)
将输出:
5
1 6
但是,当然,上面的代码之所以有效,只是因为在您的问题中,foo(a)
只是返回a
,而这恰好是int
构造函数的行为,因此通过扩展int
,foo(a)
也方便地返回a
。
但是,如果foo(a)
实际返回生产旧代码中除a
以外的任何内容,则需要重写__new__
方法,以便它返回不同值的新int
实例。
下面显示了旧版foo(a)
返回a + 1
的示例:
class foo(int):
@classmethod
def __new__(cls, type, a):
return super(foo, cls).__new__(type, a + 1)
def __iter__(self):
return iter((self, self + 5))
因此:
amount = 4 + foo(1)
print(amount)
a, b = foo(1)
print(a, b)
将输出:
6
2 7
重命名函数并添加新的返回值。 然后编写一个像原始函数一样命名的包装器,它提取遗留的返回值:
原始代码:
def foo(x):
return a
新代码:
def enhanced_foo(x):
return a, extra_info
def foo(x):
return enhanced_foo(x)[0]
遗留代码仍然有效:
a = foo(x)
新代码使用新名称:
a, extra = enhanced_foo(x)