如何在不破坏遗留代码的情况下增加函数的返回值?



例如,假设你有一个函数:

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构造函数的行为,因此通过扩展intfoo(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)

最新更新