转化为;“收藏”;(list、set、single object等)放入Python中相同类型的新集合中

转化为;“收藏”;(list、set、single object等)放入Python中相同类型的新集合中,python,python-3.x,Python,Python 3.x,首先,我以非常一般的方式使用术语“容器”和“集合”,而不是与任何Python术语相关联 我在Python中有以下函数。它获取ID列表idlist,并返回与这些ID对应的objs对象列表。这很好: def findObj(idlist, objs): return [next(o for o in objs if id == o.id) for id in idlist] 问题是:idlist,返回值不一定必须是Python列表。我希望idlist也可以是一个普通id,并且函数将返回单个

首先,我以非常一般的方式使用术语“容器”和“集合”,而不是与任何Python术语相关联

我在Python中有以下函数。它获取ID列表
idlist
,并返回与这些ID对应的
objs
对象列表。这很好:

def findObj(idlist, objs):
    return [next(o for o in objs if id == o.id) for id in idlist]
问题是:
idlist
,返回值不一定必须是Python
列表。我希望
idlist
也可以是一个普通id,并且函数将返回单个对象。或者,
idlist
将是一个Python
set
,函数将返回对象的
set


如何实现我可以为
idlist
使用各种“容器”类型(包括普通id)并返回相同的“容器”类型?

您可以将代码更改为:

import collections



def findObj(idlist, objs):
   if isinstance(idlist, collections.Iterable):
       return type(idlist)([next(o for o in objs if id == o.id) for id in idlist])
   else:
       #cover case when idlist is just plain object
       pass

您可以将代码更改为:

import collections



def findObj(idlist, objs):
   if isinstance(idlist, collections.Iterable):
       return type(idlist)([next(o for o in objs if id == o.id) for id in idlist])
   else:
       #cover case when idlist is just plain object
       pass

如果您的普通对象的id作为int(而不是string)传递(对于idliist),那么这应该可以工作


如果您的普通对象的id作为int(而不是string)传递(对于idliist),那么这应该可以工作


我认为你心目中的不是一个好的API。 让函数返回特定类型并让用户处理最终的转换更简单、更健壮、更不容易出错

特别是,我更喜欢使用生成器使函数变为惰性:

def find_obj(ids, objs):
    try:
        for id in ids:
            yield next(o for o in objs if o.id == id)
    except TypeError:
        # ids not iterable? assume it is a plain id
        yield next(o for o in objs if o.id == ids)
现在,用户只需执行以下操作:

list(find_obj(...))
set(find_obj(...))
next(find_obj(...))   # 1 element
得到他想要的东西

附加好处:

  • 显式优于隐式:这里的类型转换是显式的。调用类型为find_obj(在别处定义的某些变量,对象)的图像代码现在,如果输入的定义不在附近,您如何知道将返回哪种类型
  • 您可以传递类型
    X
    作为输入,并将其转换为类型
    Y
    ,而无需浪费中间空间和进行不必要的转换
  • 不需要特殊情况。调用者可以提供一个不遵循通常的容器构造方法的输入(注意,没有标准的容器构造方法)

特殊情况下的备选方案单一身份证情况:

def find_obj(ids, objs):
    try:
        return (next(o for o in objs if o.id == id) for id in ids)
    except TypeError:
        for o in objs:
            if o.id == id:
                return o
当给定一系列
id
时,上述函数返回一个生成器;当传入单个
id
时,返回一个普通对象(而不是一个1元素生成器)


最后:大多数情况下(但不是总是),序列都有一个接受iterable的构造函数,并用这些元素构建容器。这意味着:

type(some_iterable)(something for el in some_iterable)
将生成一个与
某些\u iterable
相同类型的容器


请注意,有些类需要一个
列表
而不是泛型iterable,因此您必须使用
类型(some_iterable)([使用中的抽象基类来查看对象是否是、a、a等。

我认为您心目中的不是一个好的API。 让函数返回特定类型并让用户处理最终的转换更简单、更健壮、更不容易出错

特别是,我更喜欢使用生成器使函数变为惰性:

def find_obj(ids, objs):
    try:
        for id in ids:
            yield next(o for o in objs if o.id == id)
    except TypeError:
        # ids not iterable? assume it is a plain id
        yield next(o for o in objs if o.id == ids)
现在,用户只需执行以下操作:

list(find_obj(...))
set(find_obj(...))
next(find_obj(...))   # 1 element
得到他想要的东西

附加好处:

  • 显式优于隐式:这里的类型转换是显式的。图像代码中调用的类型是
    find\u obj(在别处定义的一些变量,对象)
    现在,如果输入的定义不在附近,您如何知道将返回哪种类型
  • 您可以传递类型
    X
    作为输入,并将其转换为类型
    Y
    ,而无需浪费中间空间和进行不必要的转换
  • 不需要特殊情况。调用者可以提供不遵循通常的容器构造方法的输入(请注意,没有标准的容器构造方法)

特殊情况下的备选方案单一身份证情况:

def find_obj(ids, objs):
    try:
        return (next(o for o in objs if o.id == id) for id in ids)
    except TypeError:
        for o in objs:
            if o.id == id:
                return o
当给定一系列
id
时,上述函数返回一个生成器;当传入单个
id
时,返回一个普通对象(而不是一个1元素生成器)


最后:大多数情况下(但不总是序列)序列都有一个构造函数,该构造函数接受iterable并使用这些元素构建容器。这意味着:

type(some_iterable)(something for el in some_iterable)
将生成一个与
某些\u iterable
相同类型的容器


请注意,有些类需要一个
列表
而不是泛型iterable,因此您必须使用
类型(some_iterable)([使用中的抽象基类来查看对象是否为、a、a等。

返回类型(idlist)如何([下一步(objs中的o表示o,如果id==o.id)表示idlist中的id])?
类型(idlist)
将为您提供传递给函数的对象的类型。现在您必须调用该类型构造函数[
t=type(idlist);t(input_参数)
],并计算出所有的角点情况(如不是序列,而是对象等)。返回类型(idlist)如何(接下来(如果id=o,则在objs中为o)在idlist中为id),
type(idlist)
将为您提供传递给函数的对象类型。现在您必须调用该类型构造函数[
t=type(idlist);t(input_参数)
],并找出所有关键情况(如不是序列,而是对象等)。对实际上不是“异常”的对象使用异常是一个好主意吗?我不知道Python社区是怎么想的。对实际上不是“异常”的东西使用异常是一个好主意吗?我不知道Python社区是怎么想的。