采用单个对象或可迭代的Python函数中的参数名称

时间:2010-09-10 08:17:57

标签: python naming-conventions

我的代码中有一些函数接受一个对象或一个可迭代的对象作为输入。我被教导要为所有事情使用有意义的名字,但我不确定如何遵守这里。我应该将一个参数称为sinlge对象或可迭代对象?我提出了两个想法,但我不喜欢其中任何一个:

  1. FooOrManyFoos - 这表示发生了什么,但我可以想象一个不习惯它的人可能无法立即理解它意味着什么
  2. param - 一些通用名称。这清楚地表明它可以是几件事,但没有解释参数的用途。
  3. 通常我将对象的迭代称为我称之为单个对象的复数。我知道这似乎有点强迫,但Python应该是(其中包括)可读性。

9 个答案:

答案 0 :(得分:7)

  

我的代码中有一些函数接受一个对象或一个可迭代的对象作为输入。

这是一个非常特殊而且往往非常糟糕的事情。这是可以避免的。

即,在调用此函数时传递[foo]而不是foo。

唯一可以证明这样做的时候是(1)你有一个软件的安装基础,它需要一个表单(可迭代或单例)和(2)你必须扩展它以支持另一个用例。所以。在扩展具有现有代码库的现有函数时,执行此操作。

如果这是新开发,请不要这样做。

  

我提出了两个想法,但我不喜欢其中任何一个:

[只有两个?]

  

FooOrManyFoos - 这表示发生了什么,但我可以想象一个不习惯它的人可能无法立即理解它意味着什么

什么?你是说你没有提供其他文件,也没有其他培训?没有支持?没有建议?谁是“不习惯的人”?与他们交谈。不要假设或想象他们的事情。

另外,请勿使用前导大写字母名称。

  

param - 一些通用名称。这清楚地表明它可以是几件事,但没有解释参数的用途。

可怕。决不。做。此

我查看了Python库中的示例。执行此操作的大多数功能都有简单的描述。

http://docs.python.org/library/functions.html#isinstance

isinstance(object,classinfo)

他们称之为“classinfo”,它可以是类或类的元组。

你也可以这样做。

必须考虑常见用例和例外情况。遵循80/20规则。

  1. 80%的情况下,您可以用迭代替换它,而不会出现此问题。

  2. 在剩余的20%的案例中,您已经建立了基于假设(可迭代或单项)的软件安装基础,您需要添加其他案例。不要更改名称,只需更改文档即可。如果它曾经说过“foo”它仍然会说“foo”,但是你让它接受了一个“foo”的迭代,而不对参数做任何改动。如果它曾经说“foo_list”或“foo_iter”,那么它仍然会说“foo_list”或“foo_iter”,但它会悄悄地容忍一个单身而不会破坏。

    • 80%的代码是遗产(“foo”或“foo_list”)

    • 20%的代码是新功能(“foo”可以是可迭代的,或者“foo_list”可以是单个对象。)

答案 1 :(得分:4)

我想我参加派对有点晚了,但我很惊讶没有人建议装饰师。

def withmany(f):
    def many(many_foos):
        for foo in many_foos:
            yield f(foo)
    f.many = many
    return f

@withmany
def process_foo(foo):
    return foo + 1


processed_foo = process_foo(foo)

for processed_foo in process_foo.many(foos):
    print processed_foo

我在Alex Martelli的一个帖子中看到了类似的模式,但我不记得手边的链接。

答案 2 :(得分:3)

听起来你在为代码的丑陋感到痛苦,如:

def ProcessWidget(widget_thing):
  # Infer if we have a singleton instance and make it a
  # length 1 list for consistency
  if isinstance(widget_thing, WidgetType):
    widget_thing = [widget_thing]

  for widget in widget_thing:
    #...

我的建议是避免重载您的界面来处理两个不同的情况。我倾向于编写有利于重复使用的代码,并通过巧妙的动态使用参数来清除方法的命名:

def ProcessOneWidget(widget):
  #...

def ProcessManyWidgets(widgets):
  for widget in widgets:
    ProcessOneWidget(widget)

通常,我从这个简单模式开始,但是当有效率可以抵消额外的代码复杂性和部分功能重复时,就有机会优化“多”的情况。如果这个约定似乎过于冗长,那么可以选择像“ProcessWidget”和“ProcessWidgets”这样的名称,尽管两者之间的区别是一个容易遗漏的角色。

答案 3 :(得分:2)

您可以使用* args magic(varargs)使您的参数始终可迭代。

将单个项目或多个已知项目作为正常函数args(如 func(arg1,arg2,...))传递,并使用星号传递可迭代参数,如 func(* args) )

示例:

# magic *args function
def foo(*args):
    print args

# many ways to call it
foo(1)
foo(1, 2, 3)

args1 = (1, 2, 3)
args2 = [1, 2, 3]
args3 = iter((1, 2, 3))

foo(*args1)
foo(*args2)
foo(*args3)

答案 4 :(得分:1)

您能以非常高级的方式命名参数吗?阅读代码的人对于知道参数代表什么(“客户”)比他们的类型(“list_of_tuples”)更感兴趣;类型可以在函数文档字符串中定义,这是一件好事,因为它可能在将来发生变化(类型有时是实现细节)。

答案 5 :(得分:0)

我会使用一个名称来解释该参数可以是实例或实例列表。说one_or_more_Foo_objects。我发现它比平淡的param更好。

答案 6 :(得分:0)

我会做一件事,

def myFunc(manyFoos):
    if not type(manyFoos) in (list,tuple):
        manyFoos = [manyFoos]
    #do stuff here

所以你不必再担心它的名字了。

在一个函数中你应该尝试实现1个动作,接受相同的参数类型并返回相同的类型。

不是用ifs填充函数,而是可以有2个函数。

答案 7 :(得分:0)

因为你不关心你得到什么样的迭代,你可以尝试使用iter()来获取参数的迭代器。如果iter()引发TypeError异常,则该参数不可迭代,因此您创建一个项目的列表或元组,该项目是可迭代的,Bob是您的叔叔。

def doIt(foos):
    try:
        iter(foos)
    except TypeError:
        foos = [foos]
    for foo in foos:
        pass    # do something here

这种方法的唯一问题是如果foo是一个字符串。字符串是可迭代的,因此传入单个字符串而不是字符串列表将导致迭代字符串中的字符。如果这是一个问题,您可以添加一个if测试。在这一点上,它对于样板代码变得冗长,所以我将它分解为它自己的函数。

def iterfy(iterable):
    if isinstance(iterable, basestring):
        iterable = [iterable]
    try:
        iter(iterable)
    except TypeError:
        iterable = [iterable]
    return iterable

def doIt(foos):
    for foo in iterfy(foos):
        pass    # do something

与其中一些回答不同,我喜欢这样做,因为它消除了调用者在使用API​​时可能出错的一件事。 “你所产生的东西要保守,但你接受的东西要自由。”

要回答您的原始问题,即您应该为参数命名的内容,即使您接受单个项目,我仍会使用“foos”,因为您的意图是接受列表。如果它不可迭代,那么技术上是一个错误,虽然你会纠正调用者,因为只处理一个项目可能就是他们想要的。此外,如果调用者认为他们必须传递一个可迭代的一个项目,那么,这当然可以正常工作并且需要很少的语法,那么为什么要担心纠正他们的误解呢?

答案 8 :(得分:-1)

我现在正在开展一个相当大的项目,我们正在传递地图,只是调用我们的参数map。地图内容取决于被调用的功能。这可能不是最好的情况,但我们在地图上重复使用了很多相同的代码,因此复制和粘贴更容易。

我会说它不是命名它是什么,你应该把它命名为它的用途。另外,请注意不要在不可迭代的地方调用use in