在 Python 中迭代集合的笛卡尔积时如何处理边缘情况?

How to handle edge case when iterating over cartesian product of sets in Python?

我有零个或多个函数 Pyomo sets:

def myfunc(*sets):
    if len(sets) == 0:
         return # Do something else that is irrelevant here
    indices = reduce(lambda x, y: x * y, sets)  # Cartesian product of sets
    for i in indices:
        call_some_other_function(*i)

当我向它传递一组整数时,它失败了,比如

import pyomo.environ
myset = pyomo.environ.Set(initialize=[1, 2])
myfunc(*myset)

因为那时我正在对一个整数求 *i。处理这种情况的优雅方式是什么?

您始终可以检查它是否是 collections.Iterable 以捕获不可迭代的情况(列表、集合等是可迭代的 - 整数不是):

from collections import Iterable
a = 1
isinstance(a, Iterable) # returns False
a = [1,2,3]
isinstance(a, Iterable) # returns True

所以在将它传递给函数之前先检查一下:

if isinstance(myset, Iterable):
    myfunc(*myset)
else:
    # something else

我认为您通过实施自己的笛卡尔积让事情变得更难。 Python 从 2.6 开始提供 itertools.product,它适用于任意数量的输入集。

import itertools


def args(*args):
    return repr(args)


def for_each_index(*sets):
    if not sets:
         print('No sets given.  Doing something else.')
         return
    for index in itertools.product(*sets):
        print('Do something with ' + args(*index) + '...')
    return

我添加 args 函数只是为了显示展开 *args 的确切结果。你不需要它,除非可能用于调试。

另请注意,无需调用 len 来测试元组是否为非空。 if not sets: 就行了。