命令行增强器程序中的Python标识函数

命令行增强器程序中的Python标识函数,python,python-3.x,Python,Python 3.x,我正在写一个命令行增强程序。我选择这样做,而不是使用optparse、argparse或其他可用的方法,因为:1我想要体验;我不喜欢他们 一个简单的例子: @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

我正在写一个命令行增强程序。我选择这样做,而不是使用optparse、argparse或其他可用的方法,因为:1我想要体验;我不喜欢他们

一个简单的例子:

@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
从上面的端口选项可以看出,可以指定将传递给函数的参数类型;默认类型为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
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

不,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)
这确实适用于多个输入:

>>> (1, 2, 3) == wrong_id2(1, 2, 3)
True
>>> 9 == wrong_id2(9)
False
但对于单输入而言,情况并非如此:

>>> (1, 2, 3) == wrong_id2(1, 2, 3)
True
>>> 9 == wrong_id2(9)
False
问题在于,为了接受多个输入,必须使用*args,但它的副作用是将单个项输入转换为一个元组,而天真的错误_id2只返回该元组:

>>> wrong_id2(9)
(9,)
现在我们知道了问题所在,我们可以编写一个正确的标识函数:

identity(x) --> x
identity(x, y) --> x, y
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对这种身份的实现提出了一些有趣的观点,主要的一点是返回值的一致性——也就是说,如果即使是单个项目案例返回一个元组,那么我们也可以对它一视同仁:调用len,将其放入for循环,等等


虽然这可能是非常方便的行为,但这不是一个标识函数,原因很简单,1!=1,-因此,identity1应该返回1,而不是1。

这可能是的重复,但在这个问题上,OP接受了自己的答案,只给出了两个错误的解决方案。ok。我已经看过链接了。它似乎与演示的完全相同。@J.F.Sebastian:重写问题lambda x:x作为一元函数的整个问题对我来说没有意义。对标量和元组使用单独的标识函数有什么不对?对于给定的情况,哪一个是正确的选择应该总是显而易见的。然而,我想不出一个需要非一元身份函数的具体情况。你的身份函数不适用于星图。为什么支持多属性映射变量而不支持星图变量?这里的逻辑是什么?另一方面,您的最终正确标识功能似乎仍然被破坏。您实际上只需要单独的元组和标量标识函数。这里有一个简单的例子:xs=[[1,2],[3],[4,5,6],[7],[8,9];ys=[identity*x代表xs中的x]。ys的结果值为[1,2,3,4,5,6,7,8,9]。我本以为3和7会返回1元组。因此,该表达式给出了一个类型错误:zs=maplen,ys。编辑:我实际上认为这与@J.F.Sebastian关于星图的观点是相同的。有些情况下,你无法提前知道你需要什么。在这种情况下,您可以放入if/else块来选择正确的一个,或者只使用一个足够智能的函数来处理这两种情况。@DaoWen:x的传入与x的传入不同。拿出*你就能得到你放进去的东西。