从函数中 return 多个值的非侵入式方法?

Non-invasive way to return multiple values from a function?

我正在处理一个大型代码库,我想知道在不改变所有用途的情况下向函数添加额外 return 值的非侵入性方法是什么。例如:

现有设置:

def foo():
    return 'bar'

re = foo()

我的尝试:

def foo():
    return 'bar', 'baz'


re, _ = foo()  # re has a correct value but I had to add `, _` in all uses
re    = foo()  # Error: re is now a tuple, thus semantic has changed. 

了解您只能 return 一个值非常重要,该值可能是一个容器,如元组,就像您的第二个示例中那样。但始终是单一类型。

如果您更改 return 值,那么您不能期望没有下游影响,除非您将该值更改为某些 LSP 兼容子类型。在这种情况下,如果您不想破坏下游用途,您可以 return 一些具有额外属性的 字符串子类型

class StringWithMetadata(str):
    def __new__(cls, obj, metadata=None):
        return super().__new__(cls, obj)
    def __init__(self, obj, metadata=None):
        # note, ignoring obj
        self.metadata = metadata # or whatever appropriate name you want


def foo():
    return StringWithMetadata('bar', 'baz')

re = foo()
print(re, re.metadata)

编辑:

看到你用 Python 2.7 标记了这个(如果可以的话你真的应该避免这个),那么你可以使用 super:

的长格式
return super(StringWithMetadata, cls).__new__(cls, obj)

或者只是明确的方式(你总是可以这样做):

return str.__new__(cls, obj)

如果目的是添加工具到一个使用量相对较大的函数(即,不更改使用该函数的所有代码),也许是那些行可能有帮助:

def foo(spy=None):
    result = 'bar'
    if isinstance(spy, dict):
        spy['ret'] = result
        spy['other'] = 'baz'
        # ...
    return result

示例:

原来的用途可以保持不变:

r = foo()
>>> r
'bar'

但是你也可以传递一个字典来从你的函数中获取一些其他信息:

spy = {}
r2 = foo(spy=spy)
>>> spy
{'ret': 'bar', 'other': 'baz'}

您当然可以为您的“间谍”容器使用其他类型。