Dicas, truques e boas práticas para programadores Python - I

Johni Douglas Marangon

sobre mim

desenvolvedor de software desde de 2008

programador Python há cerca de 7 meses

contato

johnidouglas.com.br

github.com/johnidm

br.linkedin.com/in/johnidouglas​

johni.douglas.marangon@gmail.com

objetivos

compartilhar o que estou aprendendo em Python

mostrar algumas coisas divertidas em Python

DUNDER

https://wiki.python.org/moin/DunderAlias

Dunder (Double UNDERscore)

__init__(self, *args, **kwargs)
__len__(self)
__repr__(self)
__add__(self, other)

Common dunders

OOP

Python não tem tipos primitivos 

Tudo é objeto desde a versão 2.2 

>>> type(7)
<class 'int'>

>>> dir(7)
['__abs__', '__add__', '__and__', '__bool__', '__ceil__', '__class__', 
'__delattr__', '__dir__', '__divmod__', '__doc__', '__eq__', '__float__', 
'__floor__', '__floordiv__', '__format__', '__ge__', '__getattribute__', 
'__getnewargs__', '__gt__', '__hash__', '__index__', '__init__', '__int__', 
'__invert__', '__le__', '__lshift__', '__lt__', '__mod__', '__mul__', 
'__ne__', '__neg__', '__new__', '__or__', '__pos__', '__pow__', '__radd__', 
'__rand__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', 
'__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__round__', 
'__rpow__', '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', 
'__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', 
'__truediv__', '__trunc__', '__xor__', 'bit_length', 'conjugate', 'denominator', 
'from_bytes', 'imag', 'numerator', 'real', 'to_bytes']


>>> class PizzaTalk:
... 	pass
... 

>>> type(PizzaTalk)
<class 'type'>

 
>>> dir(PizzaTalk)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', 
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', 
'__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', 
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', 
'__str__', '__subclasshook__', '__weakref__']

A maioria das pessoas aprende OOP com outras linguagens

 

Python tem peculiaridades - OOP Pythonica

class Parser:

    """ private variable """
    __count_iter = 0
    
    def __init__(self, tokens):
        """ Contructor method """
        self.__tokens = tokens
    
    def report(self):
        """ Public method """
        self.__build_report()
        self._parser()

    def __build_report(self):
        """ Private method """
        print(self.__count_iter)

    def _parser(self):
        """ Proteced method """
        print(self.__tokens)
        
parser = Parser(['def', ':'])
parser.report()  

 

tipagem dinamica mas não fraca

!= Java Script ou PHP

 

>>> 7 + "7"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'int' and 'str'

Python não tem sobrecarga de métodos mas tem sobrecarga de operadores e passagem flexível de argumentos

class PizzaTalk:
	id = 0
	def __eq__(self, other):
		return self.id == other.id

	def __len__(self):
		return 20

        def __add__(self, other):
                pass


p1 = PizzaTalk()
p1.id = 5

p2 = PizzaTalk()
p2.id = 6

p3 = p1 + p2

print(p1 == p2)
>>> False

print(len(p1))
>>> 20
some_func(fargs, *args, **kwargs)

Python não tem interface mas tem classes abstratas e herança multipla

https://www.python.org/dev/peps/pep-3119/

Mixin

class PizzaCalabresa:
	def pagar(self):
		print("Calabresa")

class PizzaStrogonoff:
	def pagar(self):
		print("Strogonoff")

class PizzaQuatroQueijos():
	def pagar(self):
		print("Quatro Queijos")

def pagamento(instance):
	instance.pagar()

pagamento(PizzaCalabresa())
pagamento(PizzaStrogonoff())
pagamento(PizzaQuatroQueijos())

Propriedades

Getter e Setter é doença - use propriedades

 

As vezes uma variável pública já é o suficiente

class Token:
    def __init__(self):
        self.__name = 'unknown' 

    @property
    def name(self):
        return self.__name

    @name.setter
    def name(self, value):
        if value != '':
            raise BlankToken('Token.name')

        self.__name = value


token = Token()
token.name = 'keyword'
print(token.name)

As vezes você pode usar uma função em um módulo.

 

 

Métodos estáticos

 

class Scanning:

    @staticmethod
    def print_token(token):
        print(token)

    @classmethod
    def print_token_class(cls, token):
    	print(cls, token)

Scanning.print_token('number')
>>> number

Scanning.print_token_class('comment')
>>> <class '__main__.Scanning'> comment

Dicas

Inicializando listas e strings

 
my_list = [""] * 10

['', '', '', '', '', '', '', '', '', '']


my_string = 'O' * 10

OOOOOOOOOO
my_list = [1, 2, 3, 4]
>>> my_list[-1]
4

Índices negativos

 

Operadores ternários

 
is_pizza = 'true' if (event == "Pizza") else 'false'
fat = True
fitness = ("skinny", "fat")[fat]
print("Ali is ", fitness)
>>> Ali is fat
condition = True

number = 2 if condition else 1

number = (1, 2)[condition]
def difference(x, y):
    return x - y

difference(5, 2)
3

difference(x=5, y=2)
3

difference(5, y=2)
3

difference(y=2, x=5)
3

Argumentos nomeados

def print_names(*args):
	print(args)

print_names('John', 'Don', 'Bull')

>>> ('John', 'Don', 'Bull')

Keyword arguments

 
def report(**kwargs):
    print(kwargs)

report(name="John", age=14, is_activated=True)

>>> {'is_activated': True, 'age': 14, 'name': 'John'}
def process(method, *middleware, **header):
    print(method)
    print(middleware)
    print(header)

process("POST", "filter", "auth", agent="My Machine", time_out=100)
>>> POST
>>> ('filter', 'auth')
>>> {'time_out': 100, 'agent': 'My Machine'}
def get_type_token(self, token):

    def is_integer():
        return re.match("^[-+]?\d+$", token) is not None

    def is_float():
        return re.match("^[-+]?\d+\.\d+?$", token) is not None

    if is_integer(token):
        return 'integer'
    elif is_float(token):
        return 'float'

Closures Functions

 

Retorno múltiplo 

 
def divide(x, y):
    quotient = x/y
    remainder = x % y
    return quotient, remainder  

q, r = divide(22, 7)

q, _ = divide(22, 7)
def getImageData(filename):
  ...
  return size, (format, version, compression), (width,height)


size, type, dimensions = getImageData('python.png')

_, type, _ = getImageData('python.png')

format, version, compression = type
name, method, trace = 'called', 'call', True

Formatação de strings

 

https://docs.python.org/3/library/string.html#string-formatting

"How to write {} code that works".format("shit") 
>>> 'How to write shit code that works'

"{0}, your code is {1} your argument is {1}".format("John", "shit")
>>> 'John, your code is shit your argument is shit'               

"My code is {wtf}".format(wtf="beautiful") 
>>> 'My code is beautiful'

class PizzaTech:
	name = "Strogonoff"

pizza = PizzaTech()
"We go to eat a {0.name} pizza".format(pizza)    
>>> 'We go to eat a Strogonoff pizza'

Docstring Conventions

def example_method(self, param1, param2):
    """Class methods are similar to regular functions.

    Note:
        Do not include the `self` parameter in the ``Args`` section.

    Args:
        param1: The first parameter.
        param2: The second parameter.

    Returns:
        True if successful, False otherwise.
    """

print(example_method.__doc__)
python -i module.py

>>> help(example_method)

Desafio

http://hotsites.folha.com.br/2015/03/31/selecao/

Perguntas

Referências

https://www.youtube.com/watch?v=BwAF7ke7Px0&i

http://book.pythontips.com/en/latest/

http://python-notes.curiousefficiency.org/en/latest/python3/index.html

Dicas, truques e boas práticas para programadores Python - I

By Johni Douglas Marangon

Dicas, truques e boas práticas para programadores Python - I

Talk apresentada no 5o Pizza Talk

  • 1,278