2014-10-18 2 views
1

Я создаю объект типа базы данных, который, когда индекс не найден, использует api для извлечения информации, сохраняет ее в объект/файл и возвращает ее.Перегрузка в python - pandas

Я хотел бы сделать это, перегрузив метод pandas DataFrame .loc[x, y], но я не могу решить, как это сделать!

На данный момент у меня есть:

import pandas as pd 
pd.set_option('io.hdf.default_format','table') 

class DataBase(pd.DataFrame): 
    """DataBase Object which can be updated by external api""" 
    def __init__(self, path, api=None): 
     super(DataBase, self).__init__(pd.read_hdf('store.h5','df')) 
     self.api = api 

я могу хотеть изменить функцию __init__ включить where аргумент, так что я могу читать только то, что мне нужно.

Не могу придумать способ перегрузить метод .loc правильно!

Кроме того, hdf5 - это всего лишь один метод. Я хотел бы сохранить возможность использовать любые другие методы хранения, как SQL, или даже Csv при необходимости

+0

Как вы можете видеть, LOC не метод, а свойство, которое затем, в свою очередь имеет свой собственный метод GET. Так что ответ на этот вопрос сложный. – mdurant

+0

Нет, я не вижу. Я не могу найти ничего полезного в '.loc' int docs или в основных файлах. – Lucidnonsense

+0

Как я понимаю, просто использовать "?" консоли ipython. В любом случае это уже в синтаксисе: метод thing.do(); но свойство/атрибут выглядит как вещь. Еще и все в конце этого действия на свойство. 'pd.core.indexing._LocationIndexer' и его производные имеют некоторые методы get, которые действуют на loc.obj, поэтому у вас есть тот, который выбран для вашего фрейма данных, подкласса и перегружает получателя. – mdurant

ответ

1

loc это свойство, которое создает возвращает имя с именем _loc, если его не None иначе она создает pandas.core.indexing._LocIndexer по требованию. Индекторы по умолчанию имеют доступ к DataFrame, который их создал, поэтому вы можете модифицировать DataFrame при пропуске ключа.

Вы можете отменить поведение DataFrame.loc путем подклассификации DataFrame и _LocIndexer как таким образом.

class MyLocIndexer(_LocIndexer):  
    def __getitem__(self, key): 
     try:     
      return super().__getitem__(key) 
     except KeyError: 
      item = db.fetch_item(key) 
      self[key] = item 
      return item 
      # `return self[key]' is better as it also works when accessing a 
      # whole axis 

class MyDataFrame(DataFrame): 
    def __init__(self, *args, **kwargs): 
     super().__init__(*args, **kwargs) 
     self._loc = MyLocIndexer(self, "loc") 

выше написано в Python3, так что вам придется исправить супер операторов, если вы используете python2.

0

Добавление лет спустя в ответе выше, если вы когда-нибудь в конечном итоге перегрузки основных классов панд, вы можете переопределить некоторые свойства конструктора, чтобы гарантировать, что новый класс поддерживается за счет стандартных панд манипуляций с Internals:

  • _constructor: Используется, когда результат обработки имеет те же самые значения, что и оригинал.
  • _constructor_sliced: Используется, когда результат обработки имеет один более низкий размер (ы) в качестве оригинала, например, одиночные столбцы DataFrame .
  • _constructor_expanddim: Используется, когда результат обработки имеет один более высокий размер в качестве оригинала, такой как Series.to_frame() и DataFrame.to_panel().

.: например

@property 
def _constructor(self): 
    return MyDataFrame 
Смежные вопросы