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

df

select(df, 'one')

rename(select(df, 'one'), one='other')

"""
Explanation: 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 (%&gt;%), onde x %&gt;% f(y) é equivalente a f(x, y). Adicionalmente, ele gostaria de usar uma sintaxe parecida com o pacote 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')
End of explanation
"""


class Idem(object):
    def __add__(self, other):
        return other * 2

    
idem = Idem()

idem + 5

5 + idem

class Idem(object):
    def __add__(self, other):
        return other * 2
    
    def __radd__(self, other):
        return self.__add__(other)
    
idem = Idem()

5 + idem

"""
Explanation: 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__.
End of explanation
"""


import datetime

data = datetime.date.today()
hora = datetime.time(19)

data

hora

datetime.datetime.now()

data + hora

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)


data = SmartDate(*data.timetuple()[:3])

data + hora

"""
Explanation: Um exemplo polêmico
Somar datetime.date com datetime.time:
End of explanation
"""


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

df >> select('two', 'one')

df

df >> select('one') >> rename(one='first') 

16 << 1

"""
Explanation: Princípio da Menor Surpresa
<img src="operacao.png">
Finalmente
End of explanation
"""


