{
"metadata": {
"name": "Capitulo18_Classes"
},
"nbformat": 3,
"nbformat_minor": 0,
"worksheets": [
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"[Python para Desenvolvedores](http://ricardoduarte.github.io/python-para-desenvolvedores/#conteudo)\n",
"===================================\n",
"2ª edi\u00e7\u00e3o, revisada e ampliada\n",
"-----------------------------------\n",
"\n",
"Cap\u00edtulo 18: Classes\n",
"=============================\n",
"_____________________________\n",
"Objetos s\u00e3o abstra\u00e7\u00f5es computacionais que representam entidades, com suas qualidades (atributos) e a\u00e7\u00f5es (m\u00e9todos) que estas podem realizar. A classe \u00e9 a estrutura b\u00e1sica do paradigma de orienta\u00e7\u00e3o a objetos, que representa o tipo do objeto, um modelo a partir do qual os objetos ser\u00e3o criados.\n",
"\n",
"![Exemplo de classes](files/bpypd_diags14.png)\n",
"\n",
"Por exemplo, a classe *Canino* descreve as caracter\u00edsticas e a\u00e7\u00f5es dos caninos em geral, enquanto o objeto *Bandit* representa um canino em particular.\n",
"\n",
"Os atributos s\u00e3o estruturas de dados que armazenam informa\u00e7\u00f5es sobre o objeto e os m\u00e9todos s\u00e3o fun\u00e7\u00f5es associadas ao objeto, que descrevem como o objeto se comporta.\n",
"\n",
"No Python, novos objetos s\u00e3o criados a partir das classes atrav\u00e9s de atribui\u00e7\u00e3o. O objeto \u00e9 uma inst\u00e2ncia da classe, que possui caracter\u00edsticas pr\u00f3prias. Quando um novo objeto \u00e9 criado, o construtor da classe \u00e9 executado. Em Python, o construtor \u00e9 um m\u00e9todo especial, chamado `__new__()`. Ap\u00f3s a chamada ao construtor, o m\u00e9todo `__init__()` \u00e9 chamado para inicializar a nova inst\u00e2ncia.\n",
"\n",
"Um objeto continua existindo na mem\u00f3ria enquanto existir pelo menos uma refer\u00eancia a ele. O interpretador Python possui um recurso chamado coletor de lixo (*Garbage Collector*) que limpa da mem\u00f3ria objetos sem refer\u00eancias. Quando o objeto \u00e9 apagado, o m\u00e9todo especial `__done__()` \u00e9 evocado. Fun\u00e7\u00f5es ligadas ao coletor de lixo podem ser encontradas no m\u00f3dulo *gc*.\n",
"\n",
"![Classe e Objeto](files/bpypd_diags15.png)\n",
"\n",
"Em Python:\n",
"\n",
"+ Tudo \u00e9 objeto, mesmo os tipos b\u00e1sicos, como n\u00fameros inteiros.\n",
"+ Tipos e classes s\u00e3o unificados.\n",
"+ Os operadores s\u00e3o na verdade chamadas para m\u00e9todos especiais.\n",
"+ As classes s\u00e3o abertas (menos para os tipos *builtins*).\n",
"\n",
"M\u00e9todos especiais s\u00e3o identificados por nomes no padr\u00e3o `__metodo__()` (dois sublinhados no in\u00edcio e no final do nome) e definem como os objetos derivados da classe se comportar\u00e3o em situa\u00e7\u00f5es particulares, como em sobrecarga de operadores.\n",
"\n",
"No Python, existem dois tipos de classes, chamadas *old style* e *new style*. As classes *new style* s\u00e3o derivadas da classe *object* e podem utilizar recursos novos das classes do Python, como *properties* e *metaclasses*. As *properties* s\u00e3o atributos calculados em tempo de execu\u00e7\u00e3o atrav\u00e9s de m\u00e9todos, enquanto as metaclasses s\u00e3o classes que geram classes, com isso permitem personalizar o comportamento das classes. As classes *old style* s\u00e3o uma heran\u00e7a das vers\u00f5es antigas do Python, mantidas para garantir compatibilidade com c\u00f3digo legado.\n",
"\n",
"Sintaxe:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"class Classe(supcl1, supcl2):\n",
" \"\"\"\n",
" Isto \u00e9 uma classe\n",
" \"\"\"\n",
" clsvar = []\n",
"\n",
" def __init__(self, args):\n",
" \"\"\"\n",
" Inicializador da classe\n",
" \"\"\"\n",
" \n",
"\n",
" def __done__(self):\n",
" \"\"\"\n",
" Destrutor da classe\n",
" \"\"\"\n",
" \n",
"\n",
" def metodo(self, params):\n",
" \"\"\"\n",
" M\u00e9todo de objeto\n",
" \"\"\"\n",
" \n",
"\n",
" @classmethod\n",
" def cls_metodo(cls, params):\n",
" \"\"\"\n",
" M\u00e9todo de classe\n",
" \"\"\"\n",
" \n",
"\n",
" @staticmethod\n",
" def est_metodo(params):\n",
" \"\"\"\n",
" M\u00e9todo est\u00e1tico\n",
" \"\"\"\n",
" \n",
"\n",
"\n",
"obj = Classe()\n",
"obj.metodo()\n",
"\n",
"Classe.cls_metodo()\n",
"Classe.est_metodo()"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"M\u00e9todos de objeto podem usar atributos e outros m\u00e9todos do objeto. A vari\u00e1vel *self*, que representa o objeto e tamb\u00e9m precisa ser passado de forma expl\u00edcita. O nome *self* \u00e9 uma conven\u00e7\u00e3o, assim como *cls*, podendo ser trocado por outro nome qualquer, por\u00e9m \u00e9 considerada como boa pr\u00e1tica manter o nome.\n",
"\n",
"M\u00e9todos de classe podem usar apenas atributos e outros m\u00e9todos de classe. O argumento cls representa a classe em si, precisa ser passado explicitamente como primeiro par\u00e2metro do m\u00e9todo.\n",
"\n",
"M\u00e9todos est\u00e1ticos s\u00e3o aqueles que n\u00e3o tem liga\u00e7\u00e3o com atributos do objeto ou da classe. Funcionam como as fun\u00e7\u00f5es comuns.\n",
"\n",
"Exemplo de classe:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"class Cell(object):\n",
" \"\"\"\n",
" Classe para c\u00e9lulas de planilha\n",
" \"\"\"\n",
"\n",
" def __init__(self, formula='\"\"', format='%s'):\n",
" \"\"\"\n",
" Inicializa a c\u00e9lula\n",
" \"\"\"\n",
"\n",
" self.formula = formula\n",
" self.format = format\n",
"\n",
" def __repr__(self):\n",
" \"\"\"\n",
" Retorna a representa\u00e7\u00e3o em string da c\u00e9lula\n",
" \"\"\"\n",
"\n",
" return self.format % eval(self.formula)\n",
"\n",
"\n",
"print Cell('123**2')\n",
"print Cell('23*2+2')\n",
"print Cell('abs(-1.45 / 0.3)', '%2.3f')"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"15129\n",
"48\n",
"4.833\n"
]
}
],
"prompt_number": 2
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"O m\u00e9todo `__repr__()` \u00e9 usado internamente pelo comando `print` para obter uma representa\u00e7\u00e3o do objeto em forma de texto.\n",
"\n",
"Em Python, n\u00e3o existem vari\u00e1veis e m\u00e9todos privados (que s\u00f3 podem ser acessados a partir do pr\u00f3prio objeto). Ao inv\u00e9s disso, \u00e9 usada uma conven\u00e7\u00e3o, usar um nome que comece com sublinhado (_), deve ser considerado parte da implementa\u00e7\u00e3o interna do objeto e sujeito a mudan\u00e7as sem aviso pr\u00e9vio. Al\u00e9m disso, a linguagem oferece uma funcionalidade chamada *Name Mangling*, que acrescenta na frente de nomes que iniciam com dois sublinhados (__), um sublinhado e o nome da classe.\n",
"\n",
"Exemplo:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"class Calc:\n",
"\n",
" def __init__(self, formula, **vars):\n",
"\n",
" self.formula = formula\n",
" self.vars = vars\n",
"\n",
" self.__recalc()\n",
" \n",
" def __recalc(self):\n",
"\n",
" self.__res = eval(self.formula, self.vars)\n",
"\n",
" def __repr__(self):\n",
"\n",
" self.__recalc()\n",
" return str(self.__res)\n",
"\n",
"\n",
"formula = '2*x + 3*y + z**2'\n",
"calc = Calc(formula, x=2, y=3, z=1)\n",
"\n",
"print 'f\u00f3rmula:', calc.formula\n",
"print 'x =', calc.vars['x'],'-> calc =', calc\n",
"calc.vars['x'] = 4\n",
"print 'x =', calc.vars['x'],'-> calc =', calc\n",
"print dir(calc)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"f\u00f3rmula: 2*x + 3*y + z**2\n",
"x = 2 -> calc = 14\n",
"x = 4 -> calc = 18\n",
"['_Calc__recalc', '_Calc__res', '__doc__', '__init__', '__module__', '__repr__', 'formula', 'vars']\n"
]
}
],
"prompt_number": 3
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"O m\u00e9todo `__recalc()` aparece como `_Calc__recalc()` e o atributo `__res` como ` _Calc__res` para fora do objeto.\n",
"\n",
"Classes abertas\n",
"---------------\n",
"No Python, as classes que n\u00e3o s\u00e3o *builtins* podem ser alteradas em tempo de execu\u00e7\u00e3o, devido a natureza din\u00e2mica da linguagem. \u00c9 poss\u00edvel acrescentar m\u00e9todos e atributos novos, por exemplo. A mesma l\u00f3gica se aplica aos objetos.\n",
"\n",
"Exemplo de como acrescentar um novo m\u00e9todo:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"class User(object):\n",
" \"\"\"Uma classe bem simples.\n",
" \"\"\"\n",
" def __init__(self, name):\n",
" \"\"\"Inicializa a classe, atribuindo um nome\n",
" \"\"\"\n",
" self.name = name\n",
"\n",
"\n",
"# Um novo m\u00e9todo para a classe\n",
"def set_password(self, password):\n",
" \"\"\"Troca a senha\n",
" \"\"\"\n",
" self.password = password\n",
"\n",
"print 'Classe original:', dir(User)\n",
"\n",
"# O novo m\u00e9todo \u00e9 inserido na classe\n",
"User.set_password = set_password\n",
"print 'Classe modificada:', dir(User)\n",
"\n",
"user = User('guest')\n",
"user.set_password('guest')\n",
"\n",
"print 'Objeto:', dir(user)\n",
"print 'Senha:', user.password"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Classe original: ['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']\n",
"Classe modificada: ['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'set_password']\n",
"Objeto: ['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'name', 'password', 'set_password']\n",
"Senha: guest\n"
]
}
],
"prompt_number": 4
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"A classe modificada passou a ter um novo m\u00e9todo: `set_password()`."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [],
"language": "python",
"metadata": {},
"outputs": [
{
"html": [
"\n",
""
],
"output_type": "pyout",
"prompt_number": 1,
"text": [
""
]
}
],
"prompt_number": 1
}
],
"metadata": {}
}
]
}