P r o d u t i v i d a d e p e l a c o n s i s t ê n c i a OBJETOS PYTHÔNICOS Como aproveitar o Python Data Model para construir APIs idiomáticas e fáceis de usar
PYTHON FLUENTE Fluent Python (O’Reilly, 2015) Python Fluente (Novatec, 2015) 流暢的 Python (Gotop, 2016) 2
Sometimes you need a blank template. 3
CONSISTÊNCIA Um conceito relativo 4
CONSISTENTE EM RELAÇÃO A … ? Python é consistente? len(texto) # string len(pesos) # array de floats len(nomes) # lista E Java? texto.length() // String pesos.length // array de floats nomes.size() // ArrayList 5
THE ZEN OF PYTHON, BY TIM PETERS Beautiful is better than ugly. Explicit is better than implicit. Simple is better than complex. Complex is better than complicated. Flat is better than nested. Sparse is better than dense. Readability counts. Special cases aren't special enough to break the rules. Although practicality beats purity. Errors should never pass silently. Unless explicitly silenced. In the face of ambiguity, refuse the temptation to guess. There should be one-- and preferably only one --obvious way to do it. Although that way may not be obvious at first unless you're Dutch. Now is better than never. Although never is often better than *right* now. If the implementation is hard to explain, it's a bad idea. If the implementation is easy to explain, it may be a good idea. Namespaces are one honking great idea -- let's do more of those! 6
INCONSISTÊNCIA PRÁTICA Java optou por implementar array.length como um atributo para evitar invocações de métodos… pesos.length // array de floats 7
CONSISTÊNCIA PRAGMÁTICA Python implementou len() como uma função built-in pelo mesmo motivo — evitar invocações de métodos: len(texto) # string len(pesos) # array de floats len(nomes) # lista Para os tipos built-in (implementados em C), len(x) devolve o valor de um campo em uma struct que descreve o objeto. Só acontece uma invocação de método quando o tipo é implementado em Python (user-de fi ned type). 8
CONSISTÊNCIA: TIPO DEFINIDO EM PYTHON Classes implementadas em Python podem ser consistentes com os tipos built-in e suportar len() , abs() , == , iteração… >>> v1 = Vector([3, 4]) >>> len(v1) 2 >>> abs(v1) 5.0 >>> v1 == Vector((3.0, 4.0)) True >>> x, y = v1 >>> x, y (3.0, 4.0) >>> list(v1) [3.0, 4.0] 9
THE PYTHON DATA MODEL O modelo de objetos da linguagem 10
OBJECT MODEL Modelo de objeto ou “protocolo de meta-objetos”: Interfaces-padrão de todos os objetos que formam os programas em uma linguagem: • funções • classes • instâncias • módulos • etc… 11
PYTHON DATA MODEL O modelo de objetos de Python; sua API mais fundamental. De fi ne métodos especiais com nomes no formato __dunder__ class Vector : typecode = 'd' def __init__(self, components): self._components = array(self.typecode, components) def __len__(self): return len(self._components) def __iter__(self): return iter(self._components) def __abs__(self): return math.sqrt(sum(x * x for x in self)) 12
COMO FUNCIONAM OS MÉTODOS ESPECIAIS Métodos especiais são invocados principalmente pelo interpretador Python, e não por você! Lembra a programação com um framework: implementamos métodos para o framework invocar. THE HOLLYWOOD PRINCIPLE: DON’T CALL US, WE’LL CALL YOU! 13
COMO FUNCIONAM OS MÉTODOS ESPECIAIS Métodos especiais são invocados em contextos sintáticos especiais: • expressões aritméticas e lógicas — i.e. sobrecarga de operadores • conversão para str (ex: print(x) ) • conversão para bool em contextos booleanos if , while , and , or , not • acesso a atributos ( o.x ), inclusive atributos dinâmicos • emulação de coleções: o[k] , k in o , len(o) • iteração ( for ) • context managers ( with ) • metaprogração: descritores, metaclasses 14
NOSSO EXEMPLO Um classe vetor para matemática aplicada 15
VETOR EUCLIDEANO y >>> v1 = Vector([2, 4]) Vetor(4, 5) >>> v2 = Vector([2, 1]) Vetor(2, 4) >>> v1 + v2 Vector([4.0, 5.0]) Vetor(2, 1) x Este é apenas um exemplo didático! Se você precisa lidar com vetores na vida real, use a biblioteca NumPy ! 16
VETOR EUCLIDEANO from array import array import math class Vector : typecode = 'd' def __init__(self, components): self._components = array(self.typecode, components) def __len__(self): return len(self._components) def __iter__(self): return iter(self._components) def __abs__(self): return math.sqrt(sum(x * x for x in self)) def __eq__(self, other): return (len(self) == len(other) and all(a == b for a, b in zip(self, other))) 17
>>> v1 = Vector([3, 4]) VETOR EUCLIDEANO >>> len(v1) 2 >>> abs(v1) 5.0 from array import array >>> v1 == Vector((3.0, 4.0)) import math True >>> x, y = v1 >>> x, y class Vector : (3.0, 4.0) typecode = 'd' >>> list(v1) [3.0, 4.0] def __init__(self, components): self._components = array(self.typecode, components) def __len__(self): return len(self._components) def __iter__(self): return iter(self._components) def __abs__(self): return math.sqrt(sum(x * x for x in self)) def __eq__(self, other): return (len(self) == len(other) and all(a == b for a, b in zip(self, other))) 18
ALGUNS DOS MÉTODOS ESPECIAIS __len__ >>> len('abc') 3 >>> v1 = Vector([3, 4]) Número de itens da sequência ou coleção >>> len(v1) 2 __iter__ >>> x, y = v1 >>> x, y Interface Iterable : devolve um Iterator (3.0, 4.0) >>> list(v1) [3.0, 4.0] __abs__ >>> abs(3+4j) Implementa abs() : valor absoluto de um valor numérico 5.0 >>> abs(v1) 5.0 __eq__ >>> v1 == Vector((3.0, 4.0)) Sobrecarga do operador == True 19
REPRESENTAÇÕES TEXTUAIS Algo além de toString() 20
Recommend
More recommend