В моем коде есть некоторые функции, которые принимают в качестве входных данных либо объект, либо итерацию объектов. Меня учили использовать значимые имена для всего, но я не уверен, как соблюдать здесь. Что я должен назвать параметр, который может sinlge объект или итерируемые объекты? У меня есть две идеи, но мне не нравится ни одна из них:

  1. FooOrManyFoos - Это выражает то, что происходит, но я мог бы предположить, что кто-то не привык к этому, может иметь проблемы с пониманием того, что это означает сразу
  2. param - какое-то общее имя. Это ясно показывает, что это может быть несколько вещей, но ничего не объясняет, для чего используется параметр.

Обычно я называю итерируемые объекты просто множественным числом того, что я бы назвал одним объектом. Я знаю, что это может показаться немного навязчивым, но предполагается, что Python (помимо прочего) должен быть удобочитаемым.

8
Björn Pollex 10 Сен 2010 в 12:17

8 ответов

Сейчас я работаю над довольно большим проектом, мы раздаем карты и просто вызываем наш параметр map. Содержимое карты зависит от вызываемой функции. Вероятно, это не лучшая ситуация, но мы многократно используем один и тот же код на картах, поэтому копирование и вставка проще.

Я бы сказал, вместо того, чтобы называть это, как это, вы должны назвать это, для чего он используется. Также, будьте осторожны, вы не можете вызвать use in для не повторяемого объекта.

-1
Falmarri 10 Сен 2010 в 08:26

Так как вам абсолютно безразлично, какой тип итерации вы получаете, вы можете попытаться получить итератор для параметра, используя iter (). Если iter () вызывает исключение TypeError, параметр не может быть повторен, поэтому вы создаете список или кортеж из одного элемента, который является повторяемым, и Боб - ваш дядя.

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», даже если вы примете один элемент, поскольку ваше намерение состоит в том, чтобы принять список. Если это не повторяется, то это технически ошибка, хотя вы и исправите ее для вызывающего, поскольку, вероятно, они хотят обработать только один элемент. Кроме того, если вызывающий думает , что он должен передать итеративный хотя бы один элемент, то это, конечно, будет работать нормально и требует очень небольшого синтаксиса, так зачем беспокоиться об исправлении их неправильного понимания?

0
kindall 23 Сен 2010 в 23:31

Я бы сделал 1 вещь,

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

Так что тогда вам не нужно больше беспокоиться о его названии.

В функции вы должны попытаться достичь 1 действия, принять тот же тип параметра и вернуть тот же тип.

Вместо заполнения функций ifs вы можете иметь 2 функции.

0
dnuske 10 Сен 2010 в 14:31

Я хотел бы пойти с именем, объясняющим, что параметр может быть экземпляром или списком экземпляров. Скажи one_or_more_Foo_objects. Я нахожу это лучше, чем мягкий param.

0
Manoj Govindan 10 Сен 2010 в 09:04

Можете ли вы назвать свой параметр на очень высоком уровне? люди, которые читают код, больше заинтересованы в том, чтобы знать, что представляет параметр («клиенты»), чем их тип («list_of_tuples»); тип может быть определен в строке документации функции, что является хорошей вещью, поскольку он может измениться в будущем (тип иногда является деталью реализации).

1
Eric O Lebigot 10 Сен 2010 в 08:50

Вы можете использовать магию * args (varargs), чтобы ваши параметры всегда были повторяемыми.

Передайте один или несколько известных элементов как обычные аргументы функций, например 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)
2
lunixbochs 10 Сен 2010 в 11:04

Похоже, вы мучаетесь из-за уродства кода, например:

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
Kevin Jacobs 10 Сен 2010 в 11:03

Думаю, я немного опоздал на вечеринку, но удивлен, что никто не предложил декоратора.

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

Я видел похожий шаблон в одном из постов Алекса Мартелли, но не помню ссылку с руки.

4
aaronasterling 24 Сен 2010 в 00:01