Назначить функцию как метод класса

1

Я хочу передать только действительные параметры функции ("read_excel") Я пробовал следующий код, но получаю сообщение об ошибке...

import pandas as pd
expected_keys=['io', 'sheet_name','header', 'names', 'index_col', 'usecols', 'squeeze', 'dtype', 'engine', 
               'converters', 'true_values',  'false_values', 'skiprows', 'nrows', 'na_values', 'parse_dates',
               'date_parser', 'thousands', 'comment', 'skipfooter', 'convert_float']

def safe_read_excel(self,  *args, **kwargs):
    if set(kwargs.keys()).difference(set(expected_keys)): 
        raise ValueError('invalid parameter found')
    return self.read_excel(f_name, *args, **kwargs)

pd.safe_read_excel = safe_read_excel

Когда я использую метод "read_excel" по умолчанию, создается фреймворк данных...

df= pd.read_excel('sales_summary.xlsx', header=0)

Но мой пользовательский метод выдает ошибку...

df= pd.safe_read_excel('sales_summary.xlsx', header=0)

AttributeError: объект 'str' не имеет атрибута 'read_excel'

Как назначить мою функцию как метод pandas?

  • 2
    Насколько я могу судить, вы не можете назначить новую функцию импортированному модулю, так что это плохая идея, несмотря на ошибку.
  • 0
    И даже если бы вы могли, pd.read_excel() не является методом класса для начала, и OP реализовал safe_read_excel предполагая, что это так.
Теги:
pandas

3 ответа

3
Лучший ответ

Это потому, что вы пишете вашу функцию safe_read_excel как метод класса, тогда как это "нормальная функция" (или статический метод).

Практически говоря, вам не нужно self:

def safe_read_excel(f_name,  *args, **kwargs):
    if set(kwargs.keys()).difference(set(expected_keys)): 
        raise ValueError('invalid parameter found')
    return pd.read_excel(f_name, *args, **kwargs)

Я изменил первый вход функции от self к f_name и изменил возврат к pd.read_excel

3

Вы добавили новую функцию в модуль верхнего уровня библиотеки Pandas. Функциональные атрибуты объекта модуля не привязываются и не передаются объекту модуля как self (модули не реализуют доступ к протоколу дескриптора. Просто удалите аргумент self, просто read_excel функции read_excel в ссылку pd к модулю.

Вместо этого переменная self была привязана к 'sales_summary.xlsx', которая не имеет атрибута read_excel.

Обратите внимание, что dict.keys(), в Python 3, является объектом просмотра словаря, который может использоваться как набор напрямую:

def safe_read_excel(*args, **kwargs):
    if not kwargs.keys() <= expected_keys: 
        raise ValueError('invalid parameter found')
    return pd.read_excel(f_name, *args, **kwargs)

Операция <= действует только в том случае, если kwargs.keys() является подмножеством или равно именам в expected_keys. Это более эффективно, чем использование set.difference() или set_object - set_object, так как не нужно создавать новый заданный объект. Я бы сделал expected_keys заданным объектом, а не списком, чтобы помочь настроить производительность операции:

expected_keys = {
    'io', 'sheet_name','header', 'names', 'index_col', 'usecols', 'squeeze',
    'dtype', 'engine', 'converters', 'true_values',  'false_values',
    'skiprows', 'nrows', 'na_values', 'parse_dates', 'date_parser',
    'thousands', 'comment', 'skipfooter', 'convert_float'
}

В Python 2 вместо этого вы должны использовать kwargs.viewkeys(), чтобы получить ту же функциональность. Для библиотеки, которая должна поддерживать оба Python 2 и 3, вы можете использовать six.viewkeys() или создать свои собственные локальные версии того, что делает six библиотек.

Обратите внимание, что вам никогда не нужно связываться с модулем; вам уже нужно иметь доступ к модулю, чтобы добавить вашу новую функцию в пространство имен, а модули - одиночные. Ваша функция всегда будет иметь дело только с одним модульным объектом, а не с несколькими экземплярами библиотеки Pandas, поэтому здесь не нужно усложнять свою базу кода с поддержкой привязки. Методы требуют привязки только потому, что у вас может быть любое количество экземпляров для одного класса, и ваш метод должен иметь доступ к определенному экземпляру из них, чтобы иметь доступ к атрибутам экземпляра.

1

Вы можете связать новый метод с классом с помощью модуля types, который позволит вам делать интроспекцию/ссылаться на self внутри нового метода класса:

import pandas as pd
import types

expected_keys=['io', 'sheet_name','header', 'names', 'index_col', 'usecols', 'squeeze', 'dtype', 'engine',
               'converters', 'true_values',  'false_values', 'skiprows', 'nrows', 'na_values', 'parse_dates',
               'date_parser', 'thousands', 'comment', 'skipfooter', 'convert_float']

def safe_read_excel(self,  *args, **kwargs):
    if set(kwargs.keys()).difference(set(expected_keys)):
      raise ValueError('invalid parameter found')
    return self.read_excel(args[0], *args, **kwargs)

pd.safe_read_excel = types.MethodType(safe_read_excel, pd)

df = pd.safe_read_excel('sales_summary.xlsx', header=0)
  • 0
    Почему это было бы лучше, хотя? У вас уже есть доступ к имени pd прямо здесь. Это не помогает удобочитаемости кода.
  • 0
    Я не думаю, что доступ к self полезен для конкретной проблемы, которую поставил пользователь, но если пользователь хотел получить доступ к self я хотел показать, что это возможно.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню