{ "metadata": { "name": "" }, "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 27: Persist\u00eancia\n", "=============================\n", "_____________________________\n", "Persist\u00eancia pode ser definida como a manuten\u00e7\u00e3o do estado de uma estrutura de dados entre execu\u00e7\u00f5es de uma aplica\u00e7\u00e3o. A persist\u00eancia libera o desenvolvedor de escrever c\u00f3digo explicitamente para armazenar e recuperar estruturas de dados em arquivos e ajuda a manter o foco na l\u00f3gica da aplica\u00e7\u00e3o.\n", "\n", "Serializa\u00e7\u00e3o\n", "------------\n", "A forma mais simples e direta de persist\u00eancia \u00e9 chamada de serializa\u00e7\u00e3o e consiste em gravar em disco uma imagem (*dump*) do objeto, que pode ser recarregada (*load*) posteriormente. No Python, a serializa\u00e7\u00e3o \u00e9 implementada de v\u00e1rias formas, sendo que a mais comum \u00e9 atrav\u00e9s do m\u00f3dulo chamado *pickle*.\n", "\n", "Exemplo de serializa\u00e7\u00e3o:\n", "\n", "+ O programa tenta recuperar o dicion\u00e1rio `setup` usando o objeto do arquivo `setup.pkl`.\n", "+ Se conseguir, imprime o dicion\u00e1rio.\n", "+ Se n\u00e3o conseguir, cria um `setup` *default* e salva em `setup.pkl`." ] }, { "cell_type": "code", "collapsed": false, "input": [ "import pickle\n", "\n", "try:\n", " setup = pickle.load(file('setup.pkl'))\n", " print setup\n", "\n", "except:\n", " setup = {'timeout': 10,\n", " 'server': '10.0.0.1',\n", " 'port': 80\n", " }\n", " pickle.dump(setup, file('setup.pkl', 'w'))" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "{'port': 80, 'timeout': 10, 'server': '10.0.0.1'}\n" ] } ], "prompt_number": 2 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Na primeira execu\u00e7\u00e3o, ele cria o arquivo. Nas posteriores, a sa\u00edda \u00e9 a mesma mostrada acima.\n", "\n", "Entre os m\u00f3dulos da biblioteca padr\u00e3o est\u00e3o dispon\u00edveis outros m\u00f3dulos persist\u00eancia, tais como:\n", "\n", "+ *cPickle*: vers\u00e3o mais eficiente de *pickle*, por\u00e9m n\u00e3o pode ter subclasses.\n", "+ *shelve*: fornece uma classe de objetos persistentes similares ao dicion\u00e1rio.\n", "\n", "Existem *frameworks* em Python de terceiros que oferecem formas de persist\u00eancia com recursos mais avan\u00e7ados, como o ZODB.\n", "\n", "Todas essas formas de persist\u00eancia armazenam dados em formas bin\u00e1rias, que n\u00e3o s\u00e3o diretamente leg\u00edveis por seres humanos.\n", "\n", "Para armazenar dados em forma de texto, existem m\u00f3dulos para Python para ler e gravar estruturas de dados em formatos:\n", "\n", "+ [JSON](http://json.org/) (JavaScript Object Notation).\n", "+ [YAML](http://yaml.org/) (YAML Ain't a Markup Language).\n", "+ [XML](http://www.w3.org/XML/) (Extensible Markup Language).\n", "\n", "ZODB\n", "----\n", "*Zope Object Database* (ZODB) \u00e9 um banco de dados orientado a objeto que oferece uma forma de persist\u00eancia quase transparente para aplica\u00e7\u00f5es escritas em Python e foi projetado para ter pouco impacto no c\u00f3digo da aplica\u00e7\u00e3o.\n", "\n", "ZODB suporta transa\u00e7\u00f5es, controle de vers\u00e3o de objetos e pode ser conectado a outros backends atrav\u00e9s do *Zope Enterprise Objects* (ZEO), permitindo inclusive a cria\u00e7\u00e3o de aplica\u00e7\u00f5es distribu\u00eddas em diversas m\u00e1quinas conectadas por rede.\n", "\n", "O ZODB \u00e9 um componente integrante do [Zope](http://www.zope.org/), que \u00e9 um servidor de aplica\u00e7\u00f5es desenvolvido em Python, muito usado em *Content Management Systems* (CMS).\n", "\n", "![Estrutura do ZODB](files/bpypd_diags19.png)\n", "\n", "Componentes do ZODB:\n", "\n", "+ *Database*: permite que a aplica\u00e7\u00e3o fa\u00e7a conex\u00f5es (interfaces para acesso aos objetos).\n", "+ *Transaction*: interface que permite tornar as altera\u00e7\u00f5es permanentes.\n", "+ *Persistence* : fornece a classe base Persistent.\n", "+ *Storage*: gerencia a representa\u00e7\u00e3o persistente em disco.\n", "+ *ZEO*: compartilhamento de objeto entre diferentes processos e m\u00e1quinas.\n", "\n", "Exemplo de uso do ZODB:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "from ZODB import FileStorage, DB\n", "import transaction\n", "\n", "# Definindo o armazenamento do banco\n", "storage = FileStorage.FileStorage('people.fs')\n", "db = DB(storage)\n", "\n", "# Conectando\n", "conn = db.open()\n", "\n", "# Refer\u00eancia para a raiz da \u00e1rvore\n", "root = conn.root()\n", "\n", "# Um registro persistente\n", "root['singer'] = 'Kate Bush'\n", "\n", "# Efetuando a altera\u00e7\u00e3o\n", "transaction.commit()\n", "print root['singer'] # Kate Bush\n", "\n", "# Mudando um item\n", "root['singer'] = 'Tori Amos'\n", "print root['singer'] # Tori Amos\n", "\n", "# Abortando...\n", "transaction.abort()\n", "\n", "# O item voltou ao que era antes da transa\u00e7\u00e3o\n", "print root['singer'] # Kate Bush" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Kate Bush\n", "Tori Amos\n", "Kate Bush\n" ] } ], "prompt_number": 1 }, { "cell_type": "markdown", "metadata": {}, "source": [ "O ZODB tem algumas limita\u00e7\u00f5es que devem ser levadas em conta durante o projeto da aplica\u00e7\u00e3o:\n", "\n", "+ Os objetos precisam ser \u201cserializ\u00e1veis\u201d para serem armazenados.\n", "+ Objetos mut\u00e1veis requerem cuidados especiais.\n", "\n", "Objetos \u201cserializ\u00e1veis\u201d s\u00e3o aqueles objetos que podem ser convertidos e recuperados pelo *Pickle*. Entres os objetos que n\u00e3o podem ser processados pelo *Pickle*, est\u00e3o aqueles implementados em m\u00f3dulos escritos em C, por exemplo.\n", "\n", "YAML\n", "----\n", "YAML \u00e9 um formato de serializa\u00e7\u00e3o de dados para texto que representa os dados como combina\u00e7\u00f5es de listas, dicion\u00e1rios e valores escalares. Tem como principal caracter\u00edstica ser leg\u00edvel por humanos.\n", "\n", "O projeto do YAML foi muito influenciado pela sintaxe do Python e outras linguagens din\u00e2micas. Entre outras estruturas, a especifica\u00e7\u00e3o do YAML define que:\n", "\n", "+ Os blocos s\u00e3o marcados por endenta\u00e7\u00e3o.\n", "+ Listas s\u00e3o delimitadas por colchetes ou indicadas por tra\u00e7o.\n", "+ Chaves de dicion\u00e1rio s\u00e3o seguidas de dois pontos.\n", "\n", "Listas podem ser representadas assim:\n", "\n", " - Azul\n", " - Branco\n", " - Vermelho\n", "\n", "Ou\n", "\n", " [azul, branco, vermelho]\n", "\n", "Dicion\u00e1rios s\u00e3o representados como:\n", "\n", " cor: Branco\n", " nome: Bandit\n", " raca: Labrador\n", "\n", "[PyYAML](http://pyyaml.org/) \u00e9 um m\u00f3dulo de rotinas para gerar e processar YAML no Python.\n", "\n", "Exemplo de convers\u00e3o para YAML:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "import yaml\n", "\n", "progs = {'Inglaterra':\n", " {'Yes': ['Close To The Edge', 'Fragile'],\n", " 'Genesis': ['Foxtrot', 'The Nursery Crime'],\n", " 'King Crimson': ['Red', 'Discipline']},\n", " 'Alemanha':\n", " {'Kraftwerk': ['Radioactivity', 'Trans Europe Express']}\n", " }\n", "\n", "print yaml.dump(progs)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Alemanha:\n", " Kraftwerk: [Radioactivity, Trans Europe Express]\n", "Inglaterra:\n", " Genesis: [Foxtrot, The Nursery Crime]\n", " King Crimson: [Red, Discipline]\n", " 'Yes': [Close To The Edge, Fragile]\n", "\n" ] } ], "prompt_number": 2 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Exemplo de leitura de YAML. Arquivo de entrada `prefs.yaml`:\n", "\n", " - musica: rock\n", " - cachorro:\n", " cor: Branco\n", " nome: Bandit\n", " raca: Labrador\n", " - outros:\n", " instrumento: baixo\n", " linguagem: [python, ruby]\n", " comida: carne\n", "\n", "C\u00f3digo em Python:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "import pprint\n", "import yaml\n", "\n", "# yaml.load() pode receber um arquivo aberto\n", "# como argumento\n", "yml = yaml.load(file('prefs.yaml'))\n", "\n", "# pprint.pprint() mostra a estrutura de dados\n", "# de uma forma mais organizada do que\n", "# o print convencional\n", "pprint.pprint(yml)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[{'musica': 'rock'},\n", " {'cachorro': {'cor': 'Branco', 'nome': 'Bandit', 'raca': 'Labrador'}},\n", " {'outros': {'comida': 'carne',\n", " 'instrumento': 'baixo',\n", " 'linguagem': ['python', 'ruby']}}]\n" ] } ], "prompt_number": 3 }, { "cell_type": "markdown", "metadata": {}, "source": [ "YAML \u00e9 muito pr\u00e1tico para ser usado em arquivos de configura\u00e7\u00e3o e outros casos onde os dados podem ser manipulados diretamente por pessoas.\n", "\n", "JSON\n", "----\n", "A partir vers\u00e3o 2.6, foi incorporado a biblioteca do Python um m\u00f3dulo de suporte ao JSON (*JavaScript Object Notation*). O formato apresenta muitas similaridades com o YAML e tem o mesmo prop\u00f3sito.\n", "\n", "Exemplo:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "import json\n", "\n", "desktop = {'arquitetura': 'pc', 'cpus': 2, 'hds': [520, 270]}\n", "\n", "print json.dumps(desktop)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "{\"hds\": [520, 270], \"arquitetura\": \"pc\", \"cpus\": 2}\n" ] } ], "prompt_number": 4 }, { "cell_type": "markdown", "metadata": {}, "source": [ "O JSON usa a sintaxe do JavaScript para representar os dados e \u00e9 suportado em v\u00e1rias linguagens." ] }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [ { "html": [ "\n", "" ], "output_type": "pyout", "prompt_number": 1, "text": [ "" ] } ], "prompt_number": 1 } ], "metadata": {} } ] }