Обработка либо списка, либо одного целого числа в качестве аргумента

Функция должна выбирать строки в таблице на основе имени строки (в данном случае это столбец 2). Он должен иметь возможность принимать либо одно имя, либо список имен в качестве аргументов и правильно их обрабатывать.

Это то, что у меня есть сейчас, но в идеале не было бы этого дублированного кода, и что-то вроде исключений использовалось бы разумно для выбора правильного способа обработки входного аргумента:

def select_rows(to_select):
    # For a list
    for row in range(0, table.numRows()):
        if _table.item(row, 1).text() in to_select:
            table.selectRow(row)
    # For a single integer
    for row in range(0, table.numRows()):
        if _table.item(row, 1).text() == to_select:
            table.selectRow(row)

person Steven Hepting    schedule 15.06.2009    source источник


Ответы (6)


На самом деле я согласен с ответом Эндрю Хэйра, просто передайте список с одним элементом.

Но если вам действительно необходимо принять не-список, как насчет того, чтобы в таком случае просто превратить его в список?

def select_rows(to_select):
    if type(to_select) is not list: to_select = [ to_select ]

    for row in range(0, table.numRows()):
        if _table.item(row, 1).text() in to_select:
            table.selectRow(row)

Снижение производительности за выполнение 'in' в списке из одного элемента вряд ли будет высоким :-) Но это указывает на еще одну вещь, которую вы, возможно, захотите рассмотреть, если ваш список 'to_select' может быть длинным: подумайте о приведении его в набор, чтобы поиск был более эффективным.

def select_rows(to_select):
    if type(to_select) is list: to_select = set( to_select )
    elif type(to_select) is not set: to_select = set( [to_select] )

    for row in range(0, table.numRows()):
        if _table.item(row, 1).text() in to_select:
            table.selectRow(row)
person NickZoic    schedule 16.06.2009
comment
В настоящее время считается, что лучше использовать isinstance, а не type, см. stackoverflow.com/questions/1549801/ - person Dr_Zaszuś; 20.03.2018
comment
И при использовании isinstance для определенных типов возникают проблемы совместимости 2/3. Например, строковые типы — это str (в версии 3) или basestring (в версии 2.7). Вы можете использовать six.string_types или six.integer_types для этого. К сожалению, six.float_types нет, поэтому, если вам нужен long из Python 2.7, вам придется кодировать его вручную. - person Dakota; 27.08.2020

Вы можете переопределить свою функцию, чтобы она принимала любое количество аргументов, например:

def select_rows(*arguments):
    for row in range(0, table.numRows()):
        if _table.item(row, 1).text() in arguments:
            table.selectRow(row)

Затем вы можете передать один аргумент следующим образом:

select_rows('abc')

несколько таких аргументов:

select_rows('abc', 'def')

А если у вас уже есть список:

items = ['abc', 'def']
select_rows(*items)
person Steef    schedule 15.06.2009
comment
+1 Такой подход лучше, чем у Эндрю Хэйра ... Проблема может заключаться в том, что вам нужно передать больше аргументов одной и той же функции, а не только список/один аргумент. Но вы могли либо использовать их раньше, либо использовать аргументы ключевого слова, например, **kwargs. - person Jaime; 16.06.2009
comment
Этот ответ явно лучше. +1 Самодокументирующийся код. *args умоляет об итерации. - person tortal; 19.08.2016

Я бы сделал только это:

def select_rows(to_select):
    # For a list
    for row in range(0, table.numRows()):
        if _table.item(row, 1).text() in to_select:
            table.selectRow(row)

и ожидайте, что аргумент всегда будет списком, даже если это просто список из одного элемента.

Помните:

Легче попросить прощения, чем разрешения.

person Andrew Hare    schedule 15.06.2009
comment
+1 ... гораздо проще поддерживать только один набор кода для выполнения задачи и более pythonic; пусть он взорвется, если кто-то назовет это вопреки документам. Если действительно нужна функция, которая принимает одно целое число в качестве аргумента, создайте вторую с именем 'def select_row(to_select)' и упакуйте 'to_select' в виде списка, а затем вызовите select_rows. - person Jarret Hardie; 16.06.2009

Я бы согласился с версией Шарки, но использовал немного больше утиной печати:

def select_rows(to_select):
    try:
        len(to_select)
    except TypeError:
        to_select = [to_select]

    for row in range(0, table.numRows()):
        if _table.item(row, 1).text() in to_select:
            table.selectRow(row)

Это имеет преимущество при работе с любым объектом, поддерживающим оператор in. Кроме того, предыдущая версия, если ей давали кортеж или какую-то другую последовательность, просто заключала его в список. Недостатком является то, что использование обработки исключений снижает производительность.

person DopplerShift    schedule 16.06.2009
comment
Это проблематично для юникодов и строк. cf: stackoverflow.com/ вопросы/305359/ - person Gregg Lind; 17.06.2009
comment
Действительная точка, по крайней мере, должна была быть в (список, кортеж) ... или, может быть, не в (строка, юникод). Я полагаю, вы бы хотели напрямую посмотреть, поддерживает ли эта штука «внутри». - person NickZoic; 17.06.2009
comment
На самом деле, Python не так сильно снижает производительность при обработке исключений, как другие языки. См., например: jeffknupp.com/blog/ 06.02.2013/ - person Bobort; 06.12.2018

Можно использовать простую оболочку для обработки списка или одного объекта.

  def wrap_list(val):
    if type(val) is list:
      return val
    return [val] 
person FlashDD    schedule 05.11.2019

Немного менее общий, но краткий, с использованием numpy:

numpy.unique()

обрабатывает это автоматически, сохраняя только уникальные значения типа массива или скаляра, и возвращает список уникальных значений или скаляра.

import numpy as np

def select_rows(to_select):
   to_select = np.unique(to_select)

   for row in range(0, table.numRows()):
       if _table.item(row, 1).text() in to_select:
           table.selectRow(row)
person Paul Lebaigue    schedule 03.06.2020