8

我有一个函数,当它被调用时,我想知道返回值将被分配给什么 - 特别是当它被解压缩为元组时。所以:

a = func()         # n = 1

对比

a, b, c = func()   # n = 3

我想使用nin的值func。一定有什么魔法inspect可以_getframe让我做到这一点。有任何想法吗?


免责声明(因为现在这似乎是必要的):我知道这是时髦的,不好的做法,不应该在生产代码中使用。它实际上看起来像我在 Perl 中所期望的。我不是在寻找一种不同的方法来解决我所谓的“实际”问题,但我很好奇如何实现我上面所要求的。这个技巧的一个很酷的用法是:

ONE, TWO, THREE = count()
ONE, TWO, THREE, FOUR = count()

def count():
    n = get_return_count()
    if not n:
        return
    return range(n)
4

2 回答 2

10

改编自http://code.activestate.com/recipes/284742-finding-out-the-number-of-values-the-caller-is-exp/

import inspect
import dis

def expecting(offset=0):
    """Return how many values the caller is expecting"""
    f = inspect.currentframe().f_back.f_back
    i = f.f_lasti + offset
    bytecode = f.f_code.co_code
    instruction = ord(bytecode[i])
    if instruction == dis.opmap['UNPACK_SEQUENCE']:
        return ord(bytecode[i + 1])
    elif instruction == dis.opmap['POP_TOP']:
        return 0
    else:
        return 1

def count():
    # offset = 3 bytecodes from the call op to the unpack op
    return range(expecting(offset=3))

或者作为一个可以检测何时解包的对象:

class count(object):
    def __iter__(self):
        # offset = 0 because we are at the unpack op
        return iter(range(expecting(offset=0)))
于 2013-05-10T12:12:42.907 回答
7

Python 如何做到这一点并没有什么神奇之处。

简而言之,如果在左侧使用多个目标名称,则右侧表达式必须返回一个匹配长度的序列

返回多个值的函数实际上只返回一个元组。那是一个标准的 Python 结构,一个一定长度的序列。您可以测量该长度:

retval = func()

print len(retval)

赋值解包是在编译时确定的,您不能在左侧动态添加更多参数以适应您正在调用的函数。

Python 3 允许您使用 splat 语法(通配符)来捕获解包赋值的剩余部分:

a, b, *c = func()

c现在将是一个列表,其中包含前 2 个之外的任何剩余值:

>>> def func(*a): return a
... 
>>> a, b, *c = func(1, 2)
>>> a, b, c
(1, 2, [])
>>> a, b, *c = func(1, 2, 3)
>>> a, b, c
(1, 2, [3])
>>> a, b, *c = func(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: need more than 1 value to unpack
于 2013-05-10T11:31:38.453 回答