如何统一单个值和序列/元组?

时间:2014-04-24 23:25:38

标签: python

在我的工作中,我的Python脚本从非Python专业用户那里获得了很多输入。 所以,例如,如果我的函数需要处理单个值和一系列值(Polymorphism / Duck Typing,哟!),我想做一些像这样的伪代码:

def duck_typed(args):
    """
    args - Give me a single integer or a list of integers to work on.

    """
    for li in args:
        <do_something>

如果用户向我传递了一个列表:

[1,2]

一个元组:

(1,2)

甚至是单身元组(请在此处提供术语帮助)

(1,)

一切都按预期工作。但是一旦用户传入一个整数,一切都会转到$%^&amp;:

1

TypeError: 'int' object is not iterable  


Smart和Clever之间的区别

现在,我立刻想到,&#34;没问题,我只需要聪明一点!&#34;我做了这样的事情:

def duck_typed(args):
    """
    args - Give me a single integer or a list of integers to work on.

    """
    args = (args,)  # <= Ha ha!  I'm so clever!

    for li in args:
        <do_something>


好吧,现在它适用于单个整数情况:

args = (1,)
  

(1)

但是当用户传入一个iterable时,$%^&amp; * s再次出现。我的技巧给了我一个嵌套的可迭代:

args = ((1,2),)
  

((1,2),)

哎呀!


常见嫌犯

当然有通常的解决方法。尝试/除外条款:

try:
    args = tuple(args)
except TypeError:
    args = tuple((args,))


这些工作,但我遇到了这个问题 A LOT 。这实际上是一个问题,try / except是一个4行解决方案。如果我能打电话,我真的很喜欢它:

tuple(1)

让它返回(1,)并将其称为一天。


其他人也使用这种语言,你知道

现在我意识到我在Python编程领域的小角落里的需求并不适用于Python世界的其他部分。动态类型化使得Python成为一种优秀的语言 - 特别是在C等神经质语言的多年工作之后。(对不起,对不起。我不是在抨击C.它非常擅长于它擅长,但你知道:xkcd

我非常确定Python语言的创建者有充分理由不允许tuple(1)


问题1

有人请解释为什么创作者选择不允许tuple(1)和/或list(1)工作?我确信这完全是理智的,对很多人来说都很明显。我可能在我在Hard Knocks学校任职期间错过了它。 (它位于霍格沃茨山的另一边。)

问题2

是否有更实际的 - 希望是1行 - 进行以下转换?

X(1) - &gt; (1)
X((1,2)) - > (1,2)

如果没有,我想我可以分解并自己动手。

2 个答案:

答案 0 :(得分:3)

Duck typing 解释并验证 list(1)失败的原因。

该方法期待鸭子,但是给了仓鼠,仓鼠不能游泳 1

  

在鸭子打字中,程序员只关心确保对象在给定的上下文中按其所需的行为,而不是确保它们是特定的类型

但并非所有对象/类型都表现相同或“按要求”。在这种情况下,整数的行为类似于iterable并导致异常。但是,list("quack")正是因为一个字符串 就像一个可迭代的行为而去了Quack - ['q','u','a','c','k']!要使list采用不可迭代实际上意味着特殊套管,而不是鸭子打字

期望整数“可迭代”听起来像设计问题,因为这需要隐含的多重性变化。也就是说,[零>或更多]值的序列的概念应该保持分开。多态性在这种情况下不适用,因为多态(任何类型)只适用于统一 - 并且没有统一来“迭代不可迭代”。

此外,只有list(itr) 接受迭代才能适应强类型Python模型并避免边缘情况。考虑如果list(x)以一种允许非迭代的方式编写,则无法确定结果是[x]还是[x 0 .. x n ],不知道提供的值。 Python只是禁止这个操作并将改变多重性的负担 - 或者传递一个Duck - 放在调用代码上。


参见In Python, how do I determine if an object is iterable?,它提供了几个解包(或以其他方式处理)不可迭代值的解决方案。

虽然我推荐这种方法,因为它改变了多样性,我可能会编写如下强制函数。与isinstance检查不同,它将处理所有不可迭代的值。但是,您必须制定ensure_iterable(None)上应该发生的事情的规则。

def ensure_iterable(x):        
    try:
        return iter(x)
    except TypeError:
        return (x,)

然后“一行”用法:

for li in ensure_iterable(args):
    pass

1 仓鼠可以游泳..或至少保持漂浮一点点。然而,我发现这个比喻很容易(而且更难忘),因为湿漉漉的仓鼠是一种悲伤的想法。保持那些小动物的安全和干燥!

答案 1 :(得分:2)

试试这个:

if isinstance(variable, int):
   variable = (variable, )