#!/usr/bin/env python # coding: utf-8 # # Sobrecarga de Operdadores em Python # # By Paulo Scardine - http://goo.gl/Ke1P0p # # ## O problema # # No site StackOverflow um usuário de R perguntou como implementar o pipe-operator do pacote [dplyr](https://cran.rstudio.com/web/packages/dplyr/vignettes/introduction.html) (`%>%`), onde `x %>% f(y)` é equivalente a `f(x, y)`. Adicionalmente, ele gostaria de usar uma sintaxe parecida com o pacote [Pipe](http://pypi.python.org/pypi/pipe/) do cheese shop: # # df = df | select('one') | rename(one='new_one') # # No pacote Pipe esta sintaxe é chamada de "infix notation", e é equivalente a: # # df = rename(select(df, 'one'), one='new_one') # In[3]: import pandas as pd df = pd.DataFrame({'one' : [1., 2., 3., 4., 4.], 'two' : [4., 3., 2., 1., 3.]}) def select(df, *args): return df[list(args)] def rename(df, **kwargs): for name, value in kwargs.items(): df = df.rename(columns={'%s' % name: '%s' % value}) return df # In[4]: df # In[5]: select(df, 'one') # In[6]: rename(select(df, 'one'), one='other') # ## Como sobrecarregar operadores em Python # # Para cada operador em Python existe um ou mais métodos mágicos `__dunder__`, um para a operação normal e um para a operação "à direita". Por exemplo, para implementar o operador `+`, você precisa sobrecarregar o método `__add__`. # # In[7]: class Idem(object): def __add__(self, other): return other * 2 idem = Idem() # In[8]: idem + 5 # In[9]: 5 + idem # In[24]: class Idem(object): def __add__(self, other): return other * 2 def __radd__(self, other): return self.__add__(other) idem = Idem() # In[25]: 5 + idem # ## Um exemplo polêmico # # Somar `datetime.date` com `datetime.time`: # In[11]: import datetime data = datetime.date.today() hora = datetime.time(19) # In[21]: data # In[13]: hora # In[14]: datetime.datetime.now() # In[15]: data + hora # In[16]: class SmartDate(datetime.date): def __add__(self, other): if isinstance(other, datetime.time): return datetime.datetime.combine(self, other) return super(SmartDate, self).__add__(other) # In[17]: data = SmartDate(*data.timetuple()[:3]) # In[18]: data + hora # ## Princípio da Menor Surpresa # # # ## Finalmente # In[19]: def pipe(original): class PipeInto(object): data = {'function': original} def __init__(self, *args, **kwargs): self.data['args'] = args self.data['kwargs'] = kwargs def __rrshift__(self, other): return self.data['function']( other, *self.data['args'], **self.data['kwargs'] ) return PipeInto @pipe def select(df, *args): return df[list(cols)] @pipe def rename(df, **kwargs): for name, value in kwargs.items(): df = df.rename(columns={'%s' % name: '%s' % value}) return df # In[28]: df >> select('two', 'one') # In[29]: df # In[32]: df >> select('one') >> rename(one='first') # In[37]: 16 << 1 # ## Takeaways # # # # # * Python is awesome # * Grupy is awesome # * VivaReal is awesome # * Tenham juízo, crianças! # # http://goo.gl/Ke1P0p # # ## Perguntas ??? # # # # In[ ]: