【问题标题】:yield tuples where all the elements are ints产生所有元素都是整数的元组
【发布时间】:2014-09-19 08:32:06
【问题描述】:

我正在编写一个接收可迭代元组的函数,然后我必须生成所有元素都是整数的元组。其中条件:

对于元组中的每个元素:

  • 如果是 int,则保持不变
  • 如果是str,则将其转换为int(如果可能,请参见下面的示例)
  • 否则,返回无

    For example: 
    
    list(func([(1, "48")])) = [(1, 48)]
    list(func([(1, "0xf")])) = [(1, 15)]
    list(func([(1, "junk")]))  = None
    list(func([([3], 4)])) = None
    

到目前为止,这是我的代码,看起来很讨厌并且不起作用

 def func(iterable):
     for x in iterable:
        for i in x:
           if not ((isinstance(i, str) and i.isdigit()) or (isinstance(i, str) and isinstance(int(i, 16), int)) or isinstance(i, int)):
              yield None
      yield [i if isinstance(i, int) else int(i) if i.isdigit() else int(i, 16) for i in x for x in iterable]

你有更好的解决方案吗?我是 python 新手,非常感谢任何帮助:)

【问题讨论】:

  • Python 相信“如果它是一只鸭子,它就是一只鸭子”。你最好在每个元素上调用 int() 并捕获异常而不是使用 isinstance。
  • 我不禁注意到这次尝试中明显没有yield。你知道yield 是什么吗?
  • 另外,你真的是指return None,就像“忘记所有其他好的元素,如果一个元素不好就不返回任何东西? "
  • "list(func([([3], 4)])) = None" -- 我很确定列表构造函数在任何情况下都不会返回 None。
  • 我仍然不认为你明白yield 的意思。如果有任何错误值,这将产生一大堆 None 值,然后引发异常;否则,它将只产生一个值。你想要的输出看起来不像那样。

标签: python list


【解决方案1】:

这有点奇怪,但看起来你想处理任何 Python 整数文字格式,就好像它是 int。最好的方法可能是调用ast.literal_eval 来解析它,然后查看它是否解析为int。像这样:

def intify(x):
    if isinstance(x, int):
        return x
    parsed = ast.literal_eval(x)
    if isinstance(parsed, int):
        return parsed
    raise ValueError('{} is not an int literal'.format(x))

请注意,您可能希望改为测试isinstance(x, numbers.Integral),如果是,则返回int(x),或者甚至只要成功就返回int(x),或者其他不同的东西,具体取决于您想对是int-like 和int-convertible 但实际上不是int,对于int-like 的一些适当定义。

现在,您只需这样做:

try:
    return tuple(intify(x) for x in iterable)
except ValueError:
    return None

如果您想对整个可迭代对象执行此操作,则需要一个嵌套循环,如下所示:

try:
    return [tuple(intify(x) for x in subiterable) for subiterable in iterable]
except ValueError:
    return None

如果您想懒惰地执行此操作,在不构建列表的情况下生成元素,则无法“提早退出”并返回 None——一旦您已经生成了一些值,就无法取消它们.所以,你想要的不是直接可能的。但是如果你能解释你为什么想要它,那么类似有用的东西实际上可能是可行的。例如:

yield from (tuple(intify(x) for x in subiterable) for subiterable in iterable)

或者,如果您没有 Python 3.3:

for subiterable in iterable:
    yield tuple(intify(x) for x in subiterable)

这将在第一个错误值上引发异常。因此,如果您只是使用迭代器来传递对list 的调用,则将放弃部分构建的列表来处理异常。

再一次,如果你用这个函数做的唯一事情就是建立一个列表,那么一开始就没有理由使用生成器;只返回一个列表。

【讨论】:

  • 我喜欢这个答案,但有一个快速警告,你真的得到了 python 的整数视图。例如,'010' 是 8。所以请确保您对前导零的想法适合 python 的。
  • @tdelaney:我认为这就是 OP 想要的。或者,如果不是 Python 的整数视图,那么可能是 JavaScript 或 C 或 chmod 命令或其他。但当然我可能是错的。 (另外,请注意 010 在 Python 3 中不是 8,而是 SyntaxError,正是因为他们认为避免混淆比解析 C 文字更重要。)
  • 所以 70 年代的字符串约定终于在 python 3 中消失了。我想也许是时候扔掉那个 PDP-11 参考手册了。
  • @tdelaney:但是如果没有 PDP-11 参考手册,你怎么会记得现在字节是 8 位而不是 9 位? :)
  • @AdamSmith:二进制文字,1972 年?这是每个单词 19 个字符而不是 7 个字符!你有磁带公司的股票吗?
【解决方案2】:

我的(未经测试的)拍摄:

def to_int(item):
    try:
        return int(item)
    except ValueError:
        return None

def func(iterable):
    for input_tuple in iterable:
        yield tuple(to_int(item) for item in input_tuple)

如果无法转换为 int,我假设“对于元组中的每个元素”,您将为该元素返回 None,而不是整个元组。

[更新]

现在您更新了问题,如果您希望func([(1, "junk")]) 在输入的任何位置出现任何不可转换的项目时返回None,那么使用yield 毫无意义; yield 的重点是在计算值后立即开始返回值。对于所需的输出,您必须保留结果,直到您处理整个列表。也许你误读了你的作业?

【讨论】:

  • 这错过了所有奇怪的十六进制逻辑
  • 我将把所需的“to_int”函数作为练习留给 OP,我只是展示了我将如何组织代码,而不是做他的功课。 :-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-01-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多