【问题标题】:Generic function to handle single element or sequence处理单个元素或序列的通用函数
【发布时间】:2020-12-14 05:03:35
【问题描述】:

我想要一个通用函数 get_me() 能够同时处理序列和单个元素参数。

代码如下:

from typing import Sequence

class class_1:
    def __init__(self, i: int=0):
        self.name = 'A'+str(i)

    def __repr__(self):
        return self.name

class class_2:
    def __init__(self, i: int=0):
        self.name = 'B'+str(i)

    def __repr__(self):
        return self.name

def get_me(seq: Sequence):

    for s in seq:
        print(f"\n1 is {s[0].name}, 2 is {s[1].name}")

这适用于以下所有组合:

one = class_1(1), class_2(1)
two = class_1(2), class_2(2)
three = class_1(3), class_2(3)

many = [one, two, three]
many = (one, two, three)
many = {one, two}
many = one, two

get_me(many)

...但给了TypeError

get_me(一个)

如果没有try: except,是否可以让这段代码处理它?

【问题讨论】:

  • 这能回答你的问题吗? Check for [] operator
  • @fountainhead: def get_me(seq: Union[Sequence, Tuple]): if hasattr(seq, '__getitem__'): for s in seq: print(f"\n1 is {s[0].name}, 2 is {s[1].name}") else: print(f"\n1 is {s[0].name}, 2 is {s[1].name}") get_me(one) 仍然报错
  • 在您的else 子句中,您根本不应该使用[] 运算符。
  • @fountainhead: ... 但是one[0].name, one[1].name 可以工作....那么,可以用什么代替?
  • 您编写它的方式,在else 子句中,s 未定义(在if 子句中,sfor 循环定义)。这可能就是您在else 子句中收到错误的原因。因此,在else 子句中,您应该打印seq[0].nameseq[1].name

标签: python


【解决方案1】:

也许这就是你所追求的:

from typing import Sequence, Union, Tuple

# ...

def get_me(seq: Union[Sequence, Tuple]):
    if isinstance(seq, tuple):
        seq = (seq,)
    for s in seq:
        print(f"\n1 is {s[0].name}, 2 is {s[1].name}")

这依赖于单个元素是一个元组,就像在您的示例中一样 - 但您的 print 语句也是如此,所以这似乎是合理的。如果您需要它适用于任何类型,您可以将其替换为 Any 并检查它是否不是序列 - 但当然您还必须修改 print 语句以及使用的任何其他代码参数。

您注意到当您将many 定义为时,此解决方案不起作用:

many = one, two

没错,因为这也产生了很多Tuple

为了支持这一点,你需要类似的东西:

def get_me(seq: Sequence):
    if not isinstance(seq[0], tuple):
        seq = (seq,)
    for s in seq:
        print(f"\n1 is {s[0].name}, 2 is {s[1].name}")

但是,这并不严格或明确。另一种方法是:

class SuperClass:
    pass


class Class1(SuperClass):
    # ...


class Class2(SuperClass):
    # ...


# ... 


def get_me(seq: Union[Sequence[SuperClass], SuperClass]):
    if isinstance(seq, SuperClass):
        seq = (seq,)
    for s in seq:
        print(f"\n1 is {s[0].name}, 2 is {s[1].name}")

如果所有显式输入都是必需的,我更喜欢哪种解决方案。

【讨论】:

  • 这适用于 get_me(one),但由于 get_me(many) 的 AttributeError: 'tuple' object has no attribute 'name' 而失败。
  • 我已经更新了答案,将many 作为一个元组考虑在内,并提供了一个可能更可取的解决方案。 (请注意,我将您的 class_1 重命名为 Class1,这是遵循 Python 的类命名约定)
【解决方案2】:

由于参数类型的各种可能排列,看起来try: except 无法避免,同时保持代码简单。

所以代码...

def get_me(seq: Sequence):

    try:
        for s in seq:
            print(f"\n1 is {s[0].name}, 2 is {s[1].name}")
    except (TypeError, AttributeError):
        print(f"\n1 is {seq[0].name}, 2 is {seq[1].name}")

...适用于我所有可能的情况:

one = class_1(1), class_2(1)
two = class_1(2), class_2(2)
three = class_1(3), class_2(3)

many = [one, two, three]
many = (one, two, three)
many = {one, two}
many = one, two

get_me(many)
get_me(one)
get_me(two)
get_me(three)

【讨论】:

  • 您现在在except 子句中拥有的print 是您应该在if hasattr()else 部分中使用的。 (请参阅我在您问题下方的最后一条评论)
猜你喜欢
  • 2016-02-17
  • 1970-01-01
  • 2021-05-27
  • 1970-01-01
  • 1970-01-01
  • 2022-01-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多