如何在不破坏遗留代码的情况下增加函数的 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= 的行为] 构造函数,所以通过扩展 int
,foo(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)
例如假设您有一个函数:
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= 的行为] 构造函数,所以通过扩展 int
,foo(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)