#!/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[ ]: