命令行增强程序中的Python身份函数

时间:2014-10-16 00:37:23

标签: python python-3.x

我正在编写命令行增强程序。我选择这样做而不是使用optparseargparse或其他可用的,因为:1)我想要体验; 2)我不喜欢他们。 ;)

一个简单的例子:

@Script(
    live_daemon=Spec('test the installed daemon', FLAG, None, remove=True),
        verbose=Spec('more info on tests', FLAG),
        port=Spec('port for daemon to use for mini-tcp server', OPTION, type=int, remove=True),
        log=Spec('specific tests to log', MULTI, remove=True),
        tests=Spec('specific tests to run', OPTION),
        )
def main(live_daemon, verbose, log, port=8079, *tests):
    pass

从上面的port选项中可以看出,可以指定将传递给函数的参数的类型;默认类型为str,但允许任何可调用。

上述示例中未显示的一种可能性是映射:

@Script( random_vars=('for example', OPTION, type=(str, int)) )
def main(**random_vars):
    pass

此实用程序的内容是将传入参数转换为默认或请求类型的函数 - 它必须使用的是用于存储结果的列表,用于执行转换的函数,和数据(可能是一个单项,或两个项目)。

这是一个棘手的问题:默认转换器函数应该正确处理任意数量的输入项,并按原样返回 - 而不是使用一系列if / else块来选择正确的默认转换器...换句话说,一个身份功能。

我现在看起来像两个lambda:

lamba x: x
lambda x, y: (x, y)

我真正想要的是一个单一的功能:

identity(x) --> x
identity(x, y) --> x, y

1 个答案:

答案 0 :(得分:0)

不,Python没有身份功能,也不太可能获得身份功能。

一个人会是什么样子?或许,更容易回答应该做的事情:

something = ...
something is identity(something)
换句话说,你应该准确地回到你所放入的东西,理想情况下,你应该能够放入任何东西。

一个诱人但不充分的解决方案:

wrong_id1 = lambda x: x

此版本的问题在于我们只能传递单个项目,因此可以使用:

>>> wrong_id1('a thing')
'a thing'

但这不是:

>>> wrong_id1('a thing', 'and another thing')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: <lambda>() takes exactly 1 argument (2 given)

下一个诱人的解决方案可能是:

wrong_id2 = lambda *x: x

这适用于多个输入:

>>> (1, 2, 3) == wrong_id2(1, 2, 3)
True

但单输入效果不佳:

>>> 9 == wrong_id2(9)
False

问题在于,为了接受多个输入,必须使用*args,但它具有将单项输入转换为元组的副作用,而简单的wrong_id2只是返回那个元组:

>>> wrong_id2(9)
(9,)

现在我们知道问题是什么,我们可以编写一个正确的身份函数:

def identity(*args):
    if len(args) == 1:
        # only one item passed in, return that one item
        return args[0]
    # many items passed in, return them as a tuple
    return args

一些简单的测试表明它的工作原理如下:

>>> 'a thing' == identity('a thing')
True

>>> (1, 2, 3) == identity(1, 2, 3)
True

>>> a_tuple = 7, 8, 9
>>> a_dict = {True: 'Python Rocks!', False: 'up is down'}
>>> none = None
>>> (a_tuple, a_dict, none) == identity(a_tuple, a_dict, none)
True
>>> a_tuple is identity(a_tuple)
True
>>> a_dict is identity(a_dict)
True
>>> none is identity(none)
True

DaoWen对identity的实现提出了一些有趣的观点,主要的一点是返回值的一致性 - 也就是说,即使单个项目案例返回一个元组,那么我们也可以一直对待它:在其上调用len(),将其放入for循环等等。

虽然这可能是非常方便的行为,但这不是身份功能,原因很简单1 != (1, ) - 因此identity(1)应该返回1而不是(1, ) }。