python函数的位置参数(Positional)和关键字参数(keyword)

        python函数具有各种灵活的参数, 功能着实强大. 不过因为过于灵活, 故比较难于理清, 所以给初学者带来了不小的困扰. 以下是我搜集的资料, 力图将这个问题明朗化.

1. parameter 和 argument

        以前一直认为这两个单词的含义是相同的, 今天才发现其实不然.
        parameter 为函数定义时的叫法, 它指明了函数可以接受的argument类型. 可以理解为C语言中的形参;
        argument 为函数调用时的叫法, 可以理解为实参, 即传入的值;

2. 我理解的 位置参数(positional) 和 关键字参数(keyword)

        从参考文档中可知, 函数定义时确定了五种参数, 但可以简化为两种基本类型, 其余的都可以在此基础上进行引申:

基本类型:
        位置参数(positional):   传参时前面不带 "变量名=", 顺序不可变, 按顺序赋给相应的局部变量.
        关键字参数(keyword):  传参时前面加上 "变量名=", 顺序可变,    按名称赋给同名的局部变量.

引申:
        仅位置参数(positional-only): 在 / 之前定义的参数, 传参时不带变量名. 这个在 python 3.8 中可以自己定义, 不过内置函数早已经使用这种方法了, 可参考 help() 输出的内部函数说明.
        位置或关键字参数(positional_or_keyword): 在 / 后面和 * 号前面定义的参数, 即我们自定义函数时最常用的. 传参时可以把它当作位置参数或关键字参数看待, 可以带变量名也可以不带. 这就是我们自定义的函数与内置函数的区别之处了, 这一点最迷惑人.
        集合位置参数(var_positional): 即函数定义时采用 *args 指定的参数. 我们一般都把它理解为"可变参数", 实际上理解为"集合位置参数"最精确. 传参时不能带变量名. 注意: 根据"关键字参数不能在位置参数前面"的原则, *args 会将之前的参数全部转化为 位置参数, 之后的参数全部转化为 关键字参数
        仅关键字参数(keyword-only): 在 * 后面定义的参数(或在 *args 后面定义, ... 类似于 *args). 传参时必需带变量名.
        集合关键字参数(var_keyword): 即函数定义时采用 **args 指定的参数. 它可以接受我们传入的任意个数的关键字参数. 传参时必须带变量名.

        注意: 传递参数时, "关键字参数不能在位置参数前面", 否则就会报错. 根据这条原则, 那么上述顺序也应该是 parameter 定义的顺序了.

        另外根据定义时是否有默认参数, 又可分为两种修饰类型, 它们不影响参数的基本类型定义:
        必需参数: 定义时没有默认值的参数, 调用时不可省略.
        可选参数: 定义时有默认值的参数,     调用时可省略.

        举一个例子, 这个是 python 3.8 里面的例子:

def func(a, b=2, /, c, d=4, *, e=5, f): 
    pass

         a, b 是 仅位置参数; a 是必需的, b 则是可选的;
        c, d 是 位置或关键字参数;
        e, f 是 仅关键字参数;

         而我们平常所自定义的简单函数

def f(a): pass

        应该等价于

def f(/, a, *): pass

3. 参考资料

        下面的文档一部分是我从 python 3.7.4 的手册摘录来, 另一部分是网上找到的相关资料, 大家可以参考着看一下.

3.1 parameter

        A named entity in a function(or method) definition that specifies an argument (or in some cases, arguments) that the function can accept. There are five kinds of parameter:

        positional-or-keyword: specifies an argument that can be passed either positionally or as a keyword argument. This is the default kind of parameter, for example foo and bar in the following:
def func(foo, bar=None):
    pass

        positional-only: specifies an argument that can be supplied only by position. Python has no syntax for defining positional-only parameters. However, some built-in functions have positional-only parameters (e.g. abs()).

        keyword-only: specifies an argument that can be supplied only by keyword. Keyword-only parameters can be defined by including a single var-positional parameter or bare * in the parameter list of the function definition before them, for example kw_only1 and kw_only2 in the following:
def func(arg, *, kw_only1, kw_only2):
    pass

        var-positional: specifies that an arbitrary sequence of positional arguments can be provided (in addition to any positional arguments already accepted by other parameters). Such a parameter can be defined by prepending the parameter name with *, for example args in the following:
def func(*args, **kwargs):
    pass

        var-keyword: specifies that arbitrarily many keyword arguments can be provided (in addition to any keyword arguments already accepted by other parameters). Such a parameter can be defined by prepending the parameter name with **, for example kwargs in the example above.

        Parameters can specify both optional and required arguments, as well as default values for some optional arguments.

        See also the argument glossary entry, the FAQ question on the difference between arguments and parameters, the inspect.Parameter class, the Function definitions section, and PEP 362.

3.2 argument

        A value passed to a function (or method) when calling the function. There are two kinds of argument:

        keyword argument: an argument preceded by an identifier (e.g. name=) in a function call or passed as a value in a dictionary preceded by **. For example, 3 and 5 are both keyword arguments in the following calls to complex():
complex(real=3, imag=5)
complex(**{'real': 3, 'imag': 5})

        positional argument: an argument that is not a keyword argument. Positional arguments can appear at the beginning of an argument list and/or be passed as elements of an iterable preceded by *. For example, 3 and 5 are both positional arguments in the following calls:
complex(3, 5)
complex(*(3, 5))

         Arguments are assigned to the named local variables in a function body. See the Calls section for the rules governing this assignment. Syntactically, any expression can be used to represent an argument; the evaluated value is assigned to the local variable.
          See also the parameter glossary entry, the FAQ question on the difference between arguments and parameters, and PEP 362.

3.3 What is the difference between arguments and parameters?

        Parameters are defined by the names that appear in a function definition, whereas arguments are the values actually passed to a function when calling it. Parameters define what types of arguments a function can accept. For example, given the function definition:
def func(foo, bar=None, **kwargs):
    pass

        foo, bar and kwargs are parameters of func. However, when calling func, for example:
func(42, bar=314, extra=somevar)
        the values 42, 314, and somevar are arguments.


3.4 What does the slash(/) in the parameter list of a function mean?

         A slash in the argument list of a function denotes that the parameters prior to it are positional-only. Positional-only parameters are the ones without an externally-usable name. Upon calling a function that accepts positional-only parameters, arguments are mapped to parameters based solely on their position. For example, pow() is a function that accepts positional-only parameters. Its documentation looks like this:
>>> help(pow)
Help on built-in function pow in module builtins:
pow(x, y, z=None, /)
          Equivalent to x**y (with two arguments) or x**y % z (with three arguments)
          Some types, such as ints, are able to use a more efficient algorithm when invoked using the three argument form.

          The slash at the end of the parameter list means that all three parameters are positional-only. Thus, calling pow() with keyword aguments would lead to an error:
>>> pow(x=3, y=4)
Traceback (most recent call last):
    File "", line 1, in
TypeError: pow() takes no keyword arguments

          Note that as of this writing this is only documentational and no valid syntax in Python, although there is PEP 570, which proposes a syntax for position-only parameters in Python.

3.5 https://stackoverflow.com/questions/9450656/positional-argument-v-s-keyword-argument

        Since python 3.8 introduced positional arguments only, this post need an update.
        Positional arguments, keyword arguments, required arguments and optional arguments are often confused. Positional arguments ARE NOT THE SAME AS required arguments. and keywords arguments ARE NOT THE SAME AS optional arguments.
        Positional arguments are arguments that can be called by their position in the function definition.
        Keyword arguments are arguments that can be called by their name.
        Required arguments are arguments that must passed to the function.
        Optional arguments are argument that can be not passed to the function. In python optional arguments are arguments that have a default value.

Positional argument that is optional (python 3.8)
def f(a=2, /): pass
f()         # Allowed, argument is optional
f(1)        # Allowed, it's a positional argument
f(a=1)      # Error, positional only argument


Positional argument that is required (python 3.8)
def f(a, /): pass
f()         # Error, argument required
f(1)        # Allowed, it's a positional argument
f(a=1)      # Error, positional only argument


Keyword argument that is optional
def f(*, a=1): pass
f()         # Allowed
f(1)        # Error, keyword only arguments
f(a=1)      # Allowed, it's a keyword argument


keyword argument that is required
def f(*, a): pass
f()         # Error, argument required
f(1)        # Error, keyword only arguments
f(a=1)      # Allowed, it's a keyword argument


Positional and keyword argument that is optional
def f(a=1): pass
f()         # Allowed, argument is optional
f(1)        # Allowed, it's a positional argument
f(a=1)      # Allowed, it's a keyword argument
    # In fact this function is the same as
def f(/, a=1, *): pass


Positional and keyword argument that is required
def f(a): pass
f()         # Error, argument required
f(1)        # Allowed, it's a positional argument
f(a=1)      # Allowed, it's a keyword argument
    # In fact this function is the same as
def f(/, a, *): pass


        Conclusion, an argument can be optional or required not both at the same time. It can also be positional, keyword or both at the same time.

        Python 3.8 introduced positional only parameters.
def f(positional_argument, /, positional_or_keyword_argument, *, keyword_argument):
    pass


3.6 https://docs.python.org/3.8/whatsnew/3.8.html#positional-only-parameters

Positional-only parameters
        There is a new function parameter syntax / to indicate that some function parameters must be specified positionally and cannot be used as keyword arguments. This is the same notation shown by help() for C functions annotated with Larry Hastings' Argument Clinic tool.
        In the following example, parameters a and b are positional-only, while c or d can be positional or keyword, and e or f are required to be keywords:
def f(a, b, /, c, d, *, e, f):
        print(a, b, c, d, e, f)

        The following is a valid call:
f(10, 20, 30, d=40, e=50, f=60)

        However, these are invalid calls:
f(10, b=20, c=30, d=40, e=50, f=60)   # b cannot be a keyword argument
f(10, 20, 30, 40, 50, f=60)                   # e must be a keyword argument


        One use case for this notation is that it allows pure Python functions to fully emulate behaviors of existing C coded functions. For example, the built-in divmod() function does not accept keyword arguments:
def divmod(a, b, /):
        "Emulate the built in divmod() function"
        return (a // b, a % b)

        Another use case is to preclude keyword arguments when the parameter name is not helpful. For example, the builtin len() function has the signature len(obj, /). This precludes awkward calls such as:
len(obj='hello')  # The "obj" keyword argument impairs readability


        A further benefit of marking a parameter as positional-only is that it allows the parameter name to be changed in the future without risk of breaking client code. For example, in the statistics module, the parameter name dist may be changed in the future. This was made possible with the following function specification:
def quantiles(dist, /, *, n=4, method='exclusive')
        ...


        Since the parameters to the left of / are not exposed as possible keywords, the parameters names remain available for use in **kwargs:
>>> def f(a, b, /, **kwargs):
...   print(a, b, kwargs)
...
>>> f(10, 20, a=1, b=2, c=3)         # a and b are used in two ways
10 20 {'a': 1, 'b': 2, 'c': 3}
        This greatly simplifies the implementation of functions and methods that need to accept arbitrary keyword arguments. For example, here is an excerpt from code in the collections module:

class Counter(dict):
        def __init__(self, iterable=None, /, **kwds):
                # Note "iterable" is a possible keyword argument
See PEP 570 for a full description.
(Contributed by Pablo Galindo in bpo-36540.)

3.7 Python 中的关键字(具名)参数: 如何使用它们

https://blog.csdn.net/u012040909/article/details/80170573

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值