Python函数中的输入参数

2024-04-18 08:20:53 发布

您现在位置:Python中文网/ 问答频道 /正文

我刚接触Python语言,我有点沮丧。
直到今天,我还以为在函数调用中传递参数名不是强制性的。例如,如果您有以下功能:

def computeRectangleArea(width=7, height=8):
    return width * height

我以为您可以像这样调用computeRectangleArea(width=7,height=8),只是为了更清楚地说明参数的含义,但实际上不需要输入参数的关键字,所以您也可以这样调用同一个函数:computeRectangleArea(7, 8)

今天,在使用openpyxl.styles.PatternFill()时,我意识到在调用这个函数时,fill_type关键字是必需的。在

假设您以这种方式调用函数:openpyxl.styles.PatternFill('FFFFFF','FFFFFF','solid'),那么对输入参数的解释将是错误的。在

我对OOP语言(Java,C#)有一定的经验,但这些东西在那里并不存在。在

在我看来,有些参数名(如上例中的start_colorend_color)是可选的,而其他参数名(如fill_type)必须在其值之前指定,这似乎是一种不一致的行为。在

有人能解释一下为什么这个明显奇怪的政策?此外,如果有人能为我指出一些有用的资源来理解它的实现方式,我将很高兴。在


Tags: 函数语言参数type方式关键字widthfill
2条回答

Can someone explain me why we need this "headache"…

对于您的特定示例,似乎没有任何仅限关键字的参数。相反,您尝试传递第一个、第二个和第四个参数的参数,而不必为您不关心的参数传递参数。在

换句话说,这一点也不头疼。这是一个方便(和健全性检查)你可以很容易忽视,但可能不想。在

而不是这样:

PatternFill('FFFFFF', 'FFFFFF', fill_type='solid')

…你可以写下:

^{pr2}$

…但是为了让知道您需要发送的内容,您需要阅读源代码或文档以查看整个参数列表,并查看要跳过的参数的默认值,然后显式地将它们添加到调用中。在

我怀疑有人会觉得更好。在

另外,正如许多人在评论中指出的,这几乎就是命名参数在C#中的工作方式。在


意外地,这个类是一个很好的例子,说明了为什么Python实际上允许只使用关键字的参数,尽管这里没有使用它们。在

事实上,您可以编写PatternFill('FFFFFF', 'FFFFFF', 'solid')而不会因为PatternFill的错误参数而得到TypeError,而是一个关于{}不能作为颜色工作的神秘错误,这并不是一件好事。而且(至少在没有类型暗示注释的情况下,这种类型没有),您的IDE或任何其他工具都无法捕捉到这个错误。在

而且,事实上,如果不使用关键字,你甚至会在没有意识到的情况下,把初始参数弄错了。你几乎肯定想这么做:

PatternFile(None, 'FFFFFF', 'FFFFFF')

…但是你没有发现一个明显的错误:

PatternFile('FFFFFF', 'FFFFFF')

…这意味着您将前景色作为图案类型传递,背景色作为前景色传递,而保留默认背景色。在

这可以通过使所有或大多数参数关键字只。但是如果没有关键字参数,唯一的选择就是**kwargs,而且这种折衷通常是不值得的。在

引用PEP 3102的基本原理,建议在语言中添加仅关键字参数:

There are often cases where it is desirable for a function to take a variable number of arguments. The Python language supports this using the 'varargs' syntax (*name), which specifies that any 'left over' arguments be passed into the varargs parameter as a tuple.

One limitation on this is that currently, all of the regular argument slots must be filled before the vararg slot can be.

This is not always desirable. One can easily envision a function which takes a variable number of arguments, but also takes one or more 'options' in the form of keyword arguments. Currently, the only way to do this is to define both a varargs argument, and a 'keywords' argument (**kwargs), and then manually extract the desired keywords from the dictionary.

如果不清楚为什么使用*args**kwargs不够好:

  • 当查看源代码中的函数定义、内联help、或自动生成的文档时,函数的实际签名不可见。在
  • 签名对于使用inspect模块或类似模块的动态反射代码也不可用。在
  • 签名对于静态反射代码也不可用,比如许多ide用来完成和建议的代码。在
  • 函数的实现就不那么清晰了,因为它充其量只是提取和测试参数的半样板文件,而在最坏的情况下,args和{}访问分散在函数体中。在

关于此功能允许的示例,请考虑内置的^{}函数,可以这样调用:

print(x, y, z, sep=', ')

这是因为print的定义如下:

print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False):

如果不是关键字参数,就没有办法将sep作为与实际打印值不同的内容来传递。在

您可以强制用户在一个元组中传递所有对象,而不是作为单独的参数,但是这样做的友好性要差得多,即使这样做了,也无法传递flush而不传递所有{}、end和{}的值。在

而且,即使使用关键字参数,如果不是仅关键字参数,函数签名也必须如下所示:

print(*objects, **kwargs):

…这会让你很难找出你能传递什么样的关键字参数。在

位置参数和关键字参数的工作原理与在您更熟悉的语言中一样。您需要查看所使用方法的文档并查看签名。要创建PatternFill对象,请转到类的__init__方法。在

class PatternFill(Fill):
    def __init__(self, patternType=None, fgColor=Color(), bgColor=Color(),
                 fill_type=None, start_color=None, end_color=None):

您可以指定不带关键字的参数,只要您按顺序提供它们,而不跳过任何参数。例如,您的失败呼叫可以合法地给出为:

^{pr2}$

它们将匹配前四个参数。任何时候,如果您提供的参数顺序不正确,则必须为该参数和该调用中的所有后续参数提供关键字。例如,在上面的调用中,如果您想让它们的样式默认为None,那么您必须为您提供的三个参数提供关键字。如果您只需省略None,那么解析器仍会尝试从前面按顺序匹配它们:

patternType <= 'FFFFFF'
fgColor <= 'FFFFFF'
bgColor <= 'solid'

。。。你的调用无法通过解析。在

这能让事情变得清楚一点吗?在

相关问题 更多 >