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

How to increase return values of functions without breaking legacy code?

例如假设您有一个函数:

def foo(a): 
    return a

还有大量使用此函数的遗留代码:

amount = 4 + foo(a)

如果我需要在不破坏现有代码的情况下增加 foo 的 return 值怎么办:

def foo(a)
   return a, a + 5

现在,当我这样做时,变量 'amount' 不是正确答案,因为 a 现在是,用 pylint 的话说 'a tuple' 所以数量将从 returning a + 4 改变, 至 returning (a, a+5) + 4

如何将 'a + 5' 添加到 foo,同时仍然允许 amount 是单个标量值,而不是元组?

也许这样的事情会奏效:

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 的 class,具体取决于您遗留 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) 只是 returns a,而这恰好是 [=17= 的行为] 构造函数,所以通过扩展 intfoo(a) 也很方便 returns a.

但是,如果您的 foo(a) 实际上 returns 在您的生产遗留代码中除了 a 之外的任何东西,您将需要重写 __new__ 方法,以便它 returns 不同值的新 int 实例。

下面显示了一个示例,如果您的遗产 foo(a) returns 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

重命名函数并添加新的 return 值。 然后写一个像原始函数一样命名的包装器,它提取遗留的 return 值:

原代码:

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)