7

我正在尝试使我的代码不接受关键字参数,就像某些 bulitins 也不接受关键字参数一样,但是我无法这样做。以下是我根据我有限的理解的想法:-

def somefunc(a,b):
    print a,b

somefunc(10,20)

输出:

10 20

现在,当我运行以下命令时(我知道这不应该是函数定义中的关键字参数,但是,看看函数调用,它似乎与调用接受关键字参数的函数时的语法相同) :

somefunc(b=10,a=20)

输出:

20 10

我有两个问题:-

  1. 查看函数调用somefunc(b=10,a=20)而不是函数定义,这似乎是对仅接受普通参数的函数或接受关键字参数的函数的调用。口译员如何区分这两者?
  2. 是否可以将我们的任何函数转换为一种形式,使其不像许多内置函数那样接受关键字参数?

为什么我要这样做呢? 我只是在检查我是否可以做到这一点,这样我就不会错过深入理解 python 的任何内容。我确实知道python是否允许这样做。

4

5 回答 5

8

您可以使用任意参数列表来执行此操作。请参阅http://docs.python.org/tutorial/controlflow.html#arbitrary-argument-lists

例如:

def somefunc(*args):
    print args[0], args[1]

不带关键字的调用:

somefunc(10,20)

给出:

10 20

使用关键字调用:

somefunc(a=10,b=20)

给出一个错误:

TypeError: someFunc() got an unexpected keyword argument 'a'

目前尚不清楚您为什么要这样做。

于 2012-09-08T18:57:18.513 回答
5

广告 1) Python 会自动验证正确的名称,如果它们被称为somefunct(name=value, ...). 我不需要记住参数的确切标准顺序,并且通过在每次使用时每月查看文档来验证它是否过于“神经质”,如果我记得一个具有良好描述性参数名称的函数并且将测试它们是否被接受通过 Python。相反,使用参数的正确顺序只能通过文档来验证。通过命名参数调用优于非常长的位置参数列表。因此,报告的行为是有根据的。(当然,短的单字母参数“a,b”无助于防止错误。)

ad 2) 一些众所周知的 C 语言内置快速函数,需要的参数数量很少,不支持使用命名参数调用。(例如hasattr

这是因为它们仅使用简单的标头...(... PyObject *args),因此所有命名参数都会被自动拒绝。(Python 永远无法自省 C 源代码中的参数名称。:-)

许多其他 C 函数都有一个标头...(... PyObject *args, PyObject *kwds),它们通过实现更复杂的验证PyArg_ParseTupleAndKeywords并将名称写入文档字符串来显式地支持名称的精确列表。


编辑:在Python 3.8中,仅位置参数可以通过新的函数参数语法来指示某些函数参数必须在位置上指定并且不能用作关键字参数。/

def somefunc(a, b, /):
    print(a, b)
于 2012-09-09T07:07:58.750 回答
4

查看函数调用 somefunc(b=10,a=20) 而不是函数定义,这似乎是对仅接受普通参数的函数或接受关键字参数的函数的调用。口译员如何区分这两者?

不确定这是否正是您要问的,但如果我理解正确,答案是“不是”。无论函数中如何定义参数,都可以使用关键字调用函数。如果您使用关键字语法(例如,)传递任何参数,Python 会将相应的值绑定到函数定义中具有相同名称的参数。是否定义了默认值并不重要。这两种函数定义不会创建不同“种类”的参数,只是一些参数可能具有默认值,而另一些可能没有。所以不管你做,你还是可以做的。唯一的限制是您必须首先传递/定义位置参数(例如,f(a=...)def f(a)def f(a=2)f(a=...)def f(a=2, b)f(a=2, 3))。另请参阅此答案

至于你问题的第二部分,我不知道有什么方法可以阻止 Python 函数接受命名参数的关键字传递值。如果您只定义*argsthen 它不会接受关键字参数,但位置参数不能有单独的名称。

于 2012-09-08T18:54:15.907 回答
3

在 Python 中,关键字参数和位置参数之间没有如此明显的区别。事实上,它很简单:

位置参数按照它们在函数调用中列出的顺序进行解析 关键字参数可以按任何顺序添加,但不能位于位置参数之前。

所以,如果你有这个:

def foo(x):
    pass

你可以做:

foo(1) # positional
foo(x=1) # keyword

但是您不能这样做foo(),因为您没有提供默认值。

同样,如果你有这个:

def foo(x,y='hello'):
    pass

foo(1) # this works fine
foo() # this is invalid, as an argument without a default isn't passed
foo(y='hello',1) # error - positional arguments come before keyword arguments

不要忘记阅读任意参数列表

于 2012-09-08T18:58:32.053 回答
0

我认为这是一个非常糟糕的 Python 功能,并且可能导致非常难以维护和错误的代码。假设你有一个函数:

def myurl(x, y):
    url = "{}:{}".format(x, y)
    return url

尽管用关键字参数替换位置看起来是个好主意,但永远不要这样做。我很惊讶没有 Python 选项可以阻止使用关键字参数调用此函数:

>> print myurl(x="localhost", y=8080)

如果有人发现如果写成这样,图书馆会更具可读性:

def myurl(hostname, port):
    url = "{}:{}".format(hostname, port)
    return url

然后使用关键字调用 as 的其余代码myurl(x="localhost", y=8080)将失败:

TypeError: myurl() got an unexpected keyword argument 'x'

这意味着你的局部函数变量突然变成了全局变量!我希望这个问题能在 Python 3 中得到解决。

于 2012-10-29T22:06:04.357 回答