Распаковка ** кварги - PullRequest
0 голосов
/ 08 октября 2019

Я работаю над проектом, который включает в себя большую фильтрацию базы данных с использованием Pandas. Поэтому я написал следующую функцию:

def filterList(df, dropL, col, criteria, reason="", strCont=False, isIN=False,
                   notEq=False, isEq=False, isNAN=False, isDup=False, useDropL=True, 
                   dropCol=False, dropColDropList=False, useDropReason=True):

    # make a mask
    if strCont:
        mask = df[col].str.contains(criteria)
    elif notEq:
        mask = df[col] != criteria
    elif isEq:
        mask = df[col] == criteria
    elif isNAN:
        mask = np.isnan(df[col])
    elif isIN:
        mask = df[col].isin(criteria)
    elif isDup:
        mask = df.duplicated(col, keep=False)
    else:
        print("you must specify how to make the mask")
        sys.exit()

    # fill the droplist
    if useDropL:
        dropL = dropL.append(df[mask]).fillna("")
        dropL.reset_index(drop=True, inplace=True)
        if useDropReason:
            dropL.loc[dropL["Reason Dropped"] == '', 'Reason Dropped'] = reason
        if dropColDropList:
            dropL.drop(col, axis='columns', inplace=True)

    # filter the list
    df_Filtered = df.drop(df[mask].index)
    df_Filtered.reset_index(drop=True, inplace=True)

    # special instructions
    if dropCol:
        df_Filtered.drop(col, axis='columns', inplace=True)

    return df_Filtered, dropL

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

Я бы не хотел иметь такого длинного оператора объявления. Я имею в виду, это работает, я просто думаю, что это выглядит некрасиво.

Итак, я решил, что могу использовать **kwargs, чтобы перехватить все логические переменные, а затем просто искать в них имена переменных, но везде, где я смотрю, я вижу, как это сделать, говорит, что это худшееИдея в мире.

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

Так что

  1. моя ситуацияприемлемый для непосредственного приведения ключей kwarg к именам переменных?

и

Если так / нет, как (иначе) я бы пошел по этому поводу? (Я совсем не знаком с kwargs, и только немного знаком со словарями, которые, как я понимаю, kwargs)

Ответы [ 2 ]

0 голосов
/ 08 октября 2019

Не обращаясь к вашему конкретному варианту использования, но будут времена, когда необходимо иметь функцию, которая может принимать множество аргументов, и они должны быть конкретными. Использование kwargs не самая плохая идея в мире, но это создаст две проблемы, которые вам придется решить:

  1. Программист / пользователь, который будет использовать эту функцию, не будет иметь никаких признаков /документация о том, что функция ожидает получить, какие значения могут быть переданы и т. д.
  2. Вы должны будете самостоятельно установить аргументы по умолчанию, если их нет в объекте kwargs, и вы также должны иметьдля обработки того, какие элементы являются необязательными, а какие - необходимыми.

Сказав это, удобочитаемость также является фактором, и вы правы, когда соглашаетесь с «уродливостью» большого оператора decleration. Чтобы решить эту проблему, я думаю, будет разумнее просто изменить формат объявления. Написание чего-то подобного совершенно приемлемо и гораздо более читабельно:

def filterList(df,
               dropL,
               col,
               criteria,
               reason="",
               strCont=False,
               isIN=False,
               notEq=False, 
               isEq=False, 
               isNAN=False,
               isDup=False,
               useDropL=True, 
               dropCol=False, 
               dropColDropList=False,
               useDropReason=True):

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

0 голосов
/ 08 октября 2019

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

def filterList(df, dropL, col, filterType, reason="", useDropL=True, 
               dropCol=False, dropColDropList=False, useDropReason=True):
    if filterType == "strCont":
        mask = df[col].str.contains(criteria)
    elif filterType == "notEq":
        mask = df[col] != criteria
    ...
    else:
        print("you must specify how to make the mask")
        sys.exit()
    ...
...