Я хочу передать только действительные параметры функции ("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?
Это потому, что вы пишете вашу функцию 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
Вы добавили новую функцию в модуль верхнего уровня библиотеки 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, поэтому здесь не нужно усложнять свою базу кода с поддержкой привязки. Методы требуют привязки только потому, что у вас может быть любое количество экземпляров для одного класса, и ваш метод должен иметь доступ к определенному экземпляру из них, чтобы иметь доступ к атрибутам экземпляра.
Вы можете связать новый метод с классом с помощью модуля 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)
pd
прямо здесь. Это не помогает удобочитаемости кода.
self
полезен для конкретной проблемы, которую поставил пользователь, но если пользователь хотел получить доступ к self
я хотел показать, что это возможно.
pd.read_excel()
не является методом класса для начала, и OP реализовалsafe_read_excel
предполагая, что это так.