有什么理由不总是使用关键字参数?

时间:2011-08-12 14:40:49

标签: coding-style python

在进入python之前,我开始使用一些Objective-C / Cocoa书籍。我记得,大多数函数都需要明确说明关键字参数。直到最近我才忘记了这一切,并在Python中使用了位置参数。但是最近,我遇到了一些由不正当的职位造成的错误 - 他们是偷偷摸摸的小东西。

让我思考 - 一般来说,除非有特别需要非关键字参数的情况 - 是否有任何理由不使用关键字参数?即使是简单的功能,它总是被认为是不好的风格吗?

我觉得我的大多数50行程序已经定期扩展到500行或更多行,如果我习惯于总是使用关键字参数,那么随着代码的增长,代码将更容易阅读和维护。这可能不是这样的原因吗?

更新

我得到的一般印象是它的风格偏好,有许多好的参数,它们通常不应该用于非常简单的参数,但是否则与良好的风格一致。在接受之前我只是想澄清一下 - 这种方法是否存在任何特定的非风格问题 - 例如,重要的性能命中?

11 个答案:

答案 0 :(得分:54)

除了代码的清晰度和可读性之外,没有任何理由不使用关键字参数。是否使用关键字的选择应基于关键字是否在阅读代码时添加其他有用信息。

我遵循以下一般规则:

  1. 如果很难从函数名称推断出参数的函数(名称) - 按关键字传递它(例如我不想在我的代码中使用text.splitlines(True))。
  2. 如果很难推断出参数的顺序,例如,如果你有太多的参数,或者你有独立的可选参数 - 通过关键字传递它(例如funkyplot(x, y, None, None, None, None, None, None, 'red')看起来不是特别好)
  3. 如果参数的目的明显,切勿通过关键字传递前几个参数。您看,sin(2*pi)优于sin(value=2*pi)plot(x, y, z)也是如此。
  4. 在大多数情况下,稳定的强制参数是位置,可选参数是关键字。

    在性能上也存在可能的差异,因为在每个实现中,关键字参数会稍微慢一点,但考虑到这通常是一个不成熟的优化,并且它的结果不会很重要,我不认为这是至关重要的做出决定。

    更新:非风格问题

    关键字参数可以执行位置参数可以执行的所有操作,如果您要定义新API,除了可能的性能问题之外,没有任何技术缺点。但是,如果您将代码与现有元素组合在一起,则可能没什么问题。

    请考虑以下事项:

    • 如果您使您的函数采用关键字参数,那么它将成为您界面的一部分。 您不能将您的函数替换为具有相似签名但具有相同参数的不同关键字的其他函数。
    • 您可能希望在函数上使用装饰器或其他实用程序,假定您的函数采用位置参数。未绑定方法是此类实用程序的一个示例,因为它们在将其作为位置读取后始终将第一个参数作为位置传递,因此即使定义中存在参数cls.method(self=cls_instance)self也不起作用。

    如果您很好地设计API并记录关键字参数的使用,这些都不是真正的问题,特别是如果您没有设计可以与已存在的东西互换的东西。

答案 1 :(得分:17)

如果您考虑提高函数调用的可读性,为什么不简单地将函数声明为正常,例如

def test(x, y):
    print "x:", x
    print "y:", y

只需通过明确声明名称来调用函数,如下所示:

test(y=4, x=1)

这显然可以为您提供输出:

x: 1
y: 4

或者这项练习毫无意义。

这避免了参数是可选的并且需要默认值(除非你想要它们,在这种情况下只需要继续使用关键字参数!:)并为你提供所有的多功能性和提高的命名参数的可读性,这些参数不受限制按顺序。

答案 2 :(得分:11)

嗯,有几个原因让我不这样做。

如果你的所有参数都是关键字参数,那么它会增加代码中的噪音,并且可能会清除哪些参数是必需的以及哪些参数是可选的。

另外,如果我必须使用你的代码,我可能想杀了你! (开玩笑),但每次都要输入所有参数的名称......不那么有趣。

答案 3 :(得分:6)

我记得在UNIX程序中读到了对“选项”的非常好的解释:“选项应该是可选的,程序应该能够在没有任何选项的情况下运行”。

同样的原则可以应用于Python中的 keyword 参数。 这些参数应该允许用户“自定义”函数调用,但是应该能够在没有任何隐式关键字 - 值参数对的情况下调用函数。

答案 4 :(得分:5)

只是提供一个不同的论点,我认为在某些情况下,命名参数可能会提高可读性。例如,假设一个在系统中创建用户的函数:

create_user("George", "Martin", "g.m@example.com", "payments@example.com", "1", "Radius Circle")

从这个定义来看,这些值可能意味着什么并不清楚,即使它们都是必需的,但是对于命名参数,它总是显而易见的:

create_user(
    first_name="George",
    last_name="Martin",
    contact_email="g.m@example.com",
    billing_email="payments@example.com",
    street_number="1",
    street_name="Radius Circle")

答案 5 :(得分:4)

当Python的内置compile()__import__()函数gain keyword argument support时,同样的论点是为了清晰。似乎没有显着的性能影响。

现在,如果你使你的函数只接受接受关键字参数(而不是在调用它们时使用关键字传递位置参数,这是允许的话),那么是的,它会很烦人。< / p>

答案 6 :(得分:4)

有时,事情应该很简单,因为它们很简单。

如果您总是强制您在每个函数调用中使用关键字参数,很快您的代码将无法读取。

答案 7 :(得分:3)

当参数的含义明显时,我没有看到使用关键字参数的目的

答案 8 :(得分:2)

我可以看到的一个缺点是你必须考虑一切合理的默认值,并且在许多情况下可能没有任何合理的默认值(包括None)。然后你会觉得有必要为那些逻辑上应该是位置arg的kwarg未指定的情况编写大量的错误处理代码。

想象一下每次写这样的东西..

def logarithm(x=None):
    if x is None:
        raise TypeError("You can't do log(None), sorry!")

答案 9 :(得分:2)

如果你有很长的参数列表没有明确定义的顺序(你不能轻易想出一个明确的方案来记住),关键字args是好的;然而,在许多情况下,使用它们是过度杀伤或使程序不太清晰。

首先,有时候比关键字参数的名称更容易记住关键字的顺序,并且指定参数的名称可能会使它不那么清晰。使用以下文档字符串从randint获取scipy.random

randint(low, high=None, size=None)    
Return random integers x such that low <= x < high.
If high is None, then 0 <= x < low.

当想要从[0,10)生成随机int时,在我的视图中更清楚地写randint(10)而不是randint(low=10)。如果你需要在[0,10]中生成一个包含100个数字的数组,你可能会记住参数顺序并写入randint(0, 10, 100)。但是,您可能不记得变量名称(例如,第一个参数是低,低,开始,最小,最小),一旦您必须查找参数名称,您可能不会使用它们(因为您只是查找正确的顺序)。

还要考虑可变参数函数(具有可变数量的自身匿名参数的函数)。例如,您可能想要写一些类似的东西:

def square_sum(*params):
    sq_sum = 0
    for p in params:
        sq_sum += p*p
    return sq_sum

可以应用一堆裸参数(square_sum(1,2,3,4,5) # gives 55)。当然,您可以编写函数来获取可命名的关键字def square_sum(params):,并将其称为square_sum([1,2,3,4,5]),但这可能不太直观,尤其是在对参数名称或其内容没有潜在混淆的情况下。

答案 10 :(得分:1)

我经常犯的一个错误是我忘记了在调用函数时必须在任何关键字参数之前指定位置参数。如果John 21 John jr. 是一个函数,那么:

testing

发出testing(arg = 20, 56) 条消息;类似的东西:

SyntaxError

当然很容易解决,这很烦人。因此,在你提到的几行程序的情况下,我可能只是在为函数的参数提供漂亮的描述性名称之后使用位置参数。我不知道我提到的是否是一个很大的问题。