简体   繁体   English

为什么可以将函数分配给type,const和default?

[英]Why can you assign functions to type, const and default?

I want to understand why this code works. 我想了解为什么此代码有效。 Why can you give type , const and default a built-in function? 为什么要给typeconstdefault一个内置函数?

def printList(i):
    print("Integer:", i)
    return(i)

def getParser():
    from argparse import ArgumentParser

    parser = ArgumentParser()
    parser.add_argument("integers", type=printList, nargs="+")
    parser.add_argument("--sum", dest="accumulate", const=sum, default=max, nargs="?")
    return(parser)


args = getParser().parse_args(["2", "3", "9", "5"])
print(args.integers)
print(args.accumulate(args.integers))

Output: 输出:

>>> Integer: 2
>>> Integer: 3
>>> Integer: 9
>>> Integer: 5
>>> ['2', '3', '9', '5'] 
>>> 9

I want to understand why it is working. 我想了解它为什么起作用。

Edit: 编辑:

You misunderstood me. 你误解我了。

For example "type" I would expect to see "type=int", because you want only to allow Integers. 例如,“ type”我希望看到“ type = int”,因为您只想允许Integers。 So you give "type" something. 所以你给“类型”一些东西。 But in my example "type" gives something to the "printList" functions, so that it can print it. 但是在我的示例中,“类型”为“ printList”函数提供了一些功能,以便可以打印它。 Or for example "default". 或例如“默认”。 I would expect to give some value, liken an int or str. 我希望给出一些值,例如int或str。 I give something to "default". 我给“默认”的东西。 But in my example I give the build-in function "max". 但是在我的示例中,我给内置函数“ max”。 Why does "max" get a list? 为什么“ max”获得列表? Why is that working? 为什么行得通? That is what I want to know. 这就是我想知道的。

parser.add_argument("--sum", dest="accumulate", const=sum, default=max, nargs="?")

is, assuming you don't supply an argument with '--sum' , a little bit like: 是,假设你不提供与参数'--sum' ,像一点点

args.accumulate = sum if '--sum' in arg_list else max
                               # ^ it also needs to be in the right place!

Per the docs for nargs='?' 根据nargs='?' :

One argument will be consumed from the command line if possible, and produced as a single item. 如果可能,将从命令行使用一个参数,并将其作为单个项目产生。 If no command-line argument is present, the value from default will be produced. 如果不存在命令行参数,则将生成默认值。 Note that for optional arguments, there is an additional case - the option string is present but not followed by a command-line argument. 请注意,对于可选参数,还有另外一种情况-选项字符串存在,但后面没有命令行参数。 In this case the value from const will be produced. 在这种情况下,将产生const的值。

Functions are first-class objects in Python, and can be passed around like any other object, so there's no reason they can't be used for const and default . 函数是Python中的一流对象,可以像其他任何对象一样传递,因此没有理由不能将它们用于constdefault


Note that if you actually did supply an argument with '--sum' , args.accumulate would be that value instead: 请注意,如果您确实提供了带有'--sum'的参数,则args.accumulate将是该值:

>>> args = getParser().parse_args(["1", "--sum", "this one"])
('Integer:', '1')
>>> args.accumulate
'this one'

Short answer: 简短答案:

argparse expects type to be a callable (with limited provision for a string). argparse期望type是可调用的(对字符串的限制有限)。

argparse allows const and default to be almost anything. argparse允许constdefault几乎是任何东西。 It doesn't do anything with them except assign them to an attribute (or pass them to your type callable). 除了将它们分配给属性(或将它们传递给可调用的type )之外,它对它们没有任何作用。

Long answer: 长答案:

From the internal documentation, for class Action : 在内部文档中,对于class Action

  • type -- A callable that accepts a single string argument, and returns the converted value. 类型-可调用的类型,它接受单个字符串参数,并返回转换后的值。 The standard Python types str, int, float, and complex are useful examples of such callables. 标准的Python类型str,int,float和complex是此类可调用对象的有用示例。 If None, str is used. 如果为None,则使用str。

  • default -- The value to be produced if the option is not specified. 默认值-如果未指定该选项,则将产生的值。

  • const -- The value to be produced if the option is specified and the option uses an action that takes no values. const-如果指定了选项并且选项使用不带值的操作,则将产生的值。

parse.add_argument creates an Action , using the action parameter to specify the subclass. parse.add_argument创建一个Action ,使用action参数指定子类。 You can look at this object interactively or with: 您可以交互地或通过以下方式查看此对象:

a = parser.add_argument(....)
print(repr(a))

Parameters like type , nargs , default are stored as attributes of this object. typenargsdefault这样的参数都存储为该对象的属性。

At some depth in the parse_args action, parser._get_values() ends up calling parser._get_value on each string that is allocated to a particular action. parse_args操作的某个深度parse_argsparser._get_values()最终在分配给特定操作的每个字符串上调用parser._get_value

def _get_value(self, action, arg_string):
    type_func = self._registry_get('type', action.type, action.type)
    if not callable(type_func):
        msg = _('%r is not callable')
        raise ArgumentError(action, msg % type_func)

    # convert the value to the appropriate type
    try:
        result = type_func(arg_string)

This looks in a dictionary ( parser._registries ) to see if action.type has been defined (as a string). 这将在字典( parser._registries )中action.type是否已定义action.type (作为字符串)。 If not, it assumes action.type is itself a function. 如果不是,则假定action.type本身是一个函数。 The type is used in the result = type_func(arg_string) line. type用于result = type_func(arg_string)行。

As a default None is the only registered type 默认情况下, None是唯一注册的type

def identity(string):
   return string

argparse.FileType is a factory that creates a type function, one that can open a file (ie take a file name and return an open file). argparse.FileType是创建type函数的工厂,该函数可以打开文件(即,获取文件名并返回打开的文件)。

int , float are builtin Python functions that take a string and return a value, or raise an error if there is a problem. intfloat是内置的Python函数,它们接受字符串并返回值,或者在出现问题时引发错误。 These specify the function that is called to convert the string. 这些指定用于转换字符串的函数。 They do not, directly, specify that the string must represent an integer or float. 它们没有直接指定字符串必须表示整数或浮点数。 Users sometimes mistakenly use boolean in the same way. 用户有时会错误地以相同方式使用boolean

The action parameter is looked up in the _registries . _registries查找action参数。 All of the default action classes have an entry, hence we use values like store , store_true , and append . 所有默认操作类都有一个条目,因此我们使用诸如storestore_trueappend But we can also specify a custom Action class. 但是我们也可以指定一个自定义的Action类。

As for default , early in the parse_args stack, this line is executed for each action (defined argument): 对于default ,在parse_args堆栈的早期,对每个操作(定义的参数)执行以下行:

setattr(namespace, action.dest, action.default)

This makes not assumptions about the nature of action.default . 这不对action.default的性质做任何假设。 It could be None , a string, a number, a list, a function, or any Python object. 它可以是None ,字符串,数字,列表,函数或任何Python对象。

Near the end of parse_args , it may pass action.default through the type function. parse_args的结尾附近,它可能通过type函数传递action.default It does this only if default is a string. 仅当default值为字符串时,它才执行此操作。

 setattr(namespace, action.dest, self._get_value(action, action.default))

Look at your args . 看看你的args It probably looks like: 它可能看起来像:

Namespace(integers=['2', '3', '9', '5'], accumulate=max)

Since you did not specify a --sum option, the default value is placed in the namespace without change or checking. 由于未指定--sum选项,因此默认值无需更改或检查就放置在名称空间中。 If you had specified --sum , but without an argument, then accumulate=sum (the const parameter) would be in the name space. 如果您指定了--sum ,但没有参数,则名称空间中将为accumulate=sumconst参数)。 But --sum some_other_function would have created accumulate="some_other_function" . 但是--sum some_other_function应该会创建accumulate="some_other_function"

Your chosen type function has the side effect of printing its input, but it returns the string unchanged, hence you see strings in the integers list. 您选择的type函数具有打印其输入的副作用,但是它返回的字符串不变,因此您会在integers列表中看到字符串。

When you execute 执行时

args.accumulate(args.integers)

It is the same as 与...相同

max(["2", "3", "9", "5"])

which returns "9" - the string, not the number. 返回"9" -字符串,而不是数字。

sum(["2", "3", "9", "5"])

raise an error. 引发错误。 The misnamed printList only prints a string, not a list, and does not convert its values to integers. 命名错误的printList仅打印字符串,而不打印列表,并且不会将其值转换为整数。

Sorry to be long winded, but you did ask what is going on. 抱歉,请耐心等待,但您确实想知道这是怎么回事。 In short, argparse is written to give the user a lot of power, but it also tries to handle many common cases in a simple default manner. 简而言之,编写argparse可以为用户提供很多功能,但是它也尝试以一种简单的默认方式来处理许多常见情况。

Because functions are first-class objects in Python. 因为函数是Python中的一流对象。 They can be bound, accessed, and moved around just like any other type. 可以像其他任何类型一样绑定,访问和移动它们。

>>> foo = max
>>> foo(2, 3, 1)
3

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM