代码之家  ›  专栏  ›  技术社区  ›  Björn Pollex

采用单个对象或ITerable的python函数中的参数名

  •  8
  • Björn Pollex  · 技术社区  · 14 年前

    我的代码中有一些函数接受一个对象或一个可访问的对象作为输入。我被教导对每件事都使用有意义的名字,但我不知道该如何遵守。我应该如何调用可以是sinlge对象或iterable对象的参数?我想出了两个主意,但我不喜欢其中任何一个:

    1. FooOrManyFoos -这表达了正在发生的事情,但我可以想象,不习惯它的人很难马上理解它的含义。
    2. param -一些通用名称。这清楚地表明它可以是多个东西,但不能解释参数的用途。

    通常我称它为物体的复数,我称之为单个物体。我知道这看起来有点强迫性,但Python应该(和其他人一样)具有可读性。

    9 回复  |  直到 14 年前
        1
  •  7
  •   S.Lott    14 年前

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

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

    也就是说,调用这个函数时传递[foo]而不是foo。

    唯一可以证明这一点的时候是:(1)您已经安装了一个需要一种形式(iterable或singleton)的软件库;(2)您必须扩展它以支持另一个用例。所以。你 只有 展开具有现有代码基的现有函数时,请执行此操作。

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

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

    只有两个?]

    FooormanyFoos——这表达了正在发生的事情,但我可以想象,不习惯它的人可能很难马上理解它的含义。

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

    另外,不要使用前导大写名称。

    参数-一些通用名称。这清楚地表明它可以是多个东西,但不能解释参数的用途。

    可怕的。从未。做。这个。

    我在Python库中查找了一些示例。大多数这样做的函数都有简单的描述。

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

    IsInstance(对象,ClassInfo)

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

    你也可以这样做。

    必须 考虑常见的用例和异常。遵循80/20规则。

    1. 80%的时候,你可以用一个iTable来代替它,而不是有这个问题。

    2. 在剩下的20%的案例中,您有一个基于一个假设(可选项或单个项目)构建的软件安装基础,您需要添加另一个案例。不要更改名称,只需更改文档即可。如果它以前说“foo”,它仍然说“foo”,但是你让它接受一个不可更改的“foo”参数。如果它曾经说“foo-list”或“foo-iter”,那么它仍然说“foo-list”或“foo-iter”,但是它会安静地容忍一个单身汉而不会崩溃。

      • 80%的代码是遗留代码(“foo”或“foo-list”)。

      • 20%的代码是新特性(“foo”可以是iterable,或者“foo-list”可以是单个对象。)

        2
  •  4
  •   aaronasterling    14 年前

    我想我参加聚会有点晚了,但我很惊讶没有人建议我做装饰。

    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
    

    我在亚历克斯·马泰利的一个帖子里看到了类似的模式,但我记不清这个链接是什么。

        3
  •  3
  •   Kevin Jacobs    14 年前

    听起来你在为代码的丑陋而苦恼,比如:

    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”这样的名称,尽管两者之间的区别是一个容易丢失的字符。

        4
  •  2
  •   lunixbochs    14 年前

    您可以使用*args magic(varargs)使您的参数始终是不可更改的。

    将单个项或多个已知项作为普通函数参数传递,如 func(arg1,arg2,…) 并且传递前面带星号的可ITerable参数,例如 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)
    
        5
  •  1
  •   Eric O. Lebigot    14 年前

    你能用一种非常高级的方式命名你的参数吗?阅读代码的人更感兴趣的是了解参数代表什么(“客户机”),而不是他们的类型(“元组列表”);类型可以在函数文档字符串中定义,这是一件好事,因为它将来可能会改变(类型有时是实现细节)。

        6
  •  0
  •   Manoj Govindan    14 年前

    我会用一个名称来解释参数可以是一个实例或实例列表。说 one_or_more_Foo_objects . 我觉得它比平淡的要好 param .

        7
  •  0
  •   dnuske    14 年前

    我会做一件事,

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

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

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

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

        8
  •  0
  •   kindall    14 年前

    因为您不关心得到的是什么样的iterable,所以可以尝试使用iter()为参数获取迭代器。如果iter()引发了typeerror异常,则该参数不可iterable,因此您将创建一个iterable和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”,即使你只接受一个项目,因为 意图 是接受一个列表。如果它不是无可辩驳的,那就是 技术上 一个错误,尽管您将为调用者纠正一个错误,因为处理一个项目可能是他们想要的。另外,如果来电者 认为 他们必须传递一个甚至是一个项目的不可重复的信息,好吧,那当然会很好地工作,而且只需要很少的语法,那么为什么还要担心纠正他们的误解呢?

        9
  •  -1
  •   Falmarri    14 年前

    我正在做一个相当大的项目,我们在传递地图,并调用参数 map . 映射内容因调用的函数而异。这可能不是最好的情况,但是我们在地图上重用了很多相同的代码,因此复制和粘贴更容易。

    我想说的是,你不应该把它命名为它是什么,而应该把它命名为它的用途。另外,请注意,不能调用use in 在一个不可测的。