{ "cells": [ { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "Tipos de Dados e Estruturas de Dados\n", "==============================\n", "\n", "O que é um tipo de dado?\n", "----------------\n", "\n", "A linguagem Python reconhece diferentes tipos de dados. Para encontrar o tipo de uma variável, use a função `type()`: " ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "45\n", "45\n" ] }, { "data": { "text/plain": [ "(str, int)" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = '45'\n", "b = 45\n", "\n", "int(a)+b\n", "\n", "print(a)\n", "print(b)\n", "type(a),type(b)\n" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "str" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "b = 'Isto é uma string'\n", "type(b)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Devo me lembrar que um número complexo é composto de uma parte real e um a parte imaginária. Em Python, eu escrevo um NC assim:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "complex" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "c = 2 + 1j\n", "type(c)" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "list" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d = [1, 3, 56]\n", "type(d)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Números\n", "-------\n", "\n", "##### Informação adicional\n", "\n", "- Introdução informal aos números. [Python tutorial, seção 3.1.1](http://docs.python.org/tutorial/introduction.html#using-python-as-a-calculator)\n", "\n", "- Python Library Reference: visão geral formal de tipos numéricos, \n", "\n", "- Pense em Python, [Seção 2.1](http://penseallen.github.io/PensePython2e/02-vars-expr-instr.html)\n", "\n", "Os tipos de dados predefinidos são números inteiros, ponto flutuante e ponto flutuante complexos.\n", "\n", "### Inteiros\n", "\n", "Se precisarmos converter uma *string* contendo um número inteiro para um inteiro, podemos usar a função `int()`:" ] }, { "cell_type": "code", "execution_count": 22, "metadata": { "collapsed": true }, "outputs": [], "source": [ "a = '34' # a é uma string contendo os caracteres 3 e 4\n", "x = int(a) # x é um número inteiro" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A função `int()` também converterá números em ponto flutuante para inteiros:" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "7" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "int(7.0)" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "7" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "int(7.9)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note que `int` truncará qualquer parte não inteira de um número em ponto flutuante. Para arredondar um número em ponto flutuante para inteiro, use o comando `round()`:" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "8" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "round(7.9)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Limites de Inteiro\n", "\n", "Inteiros em Python 3 são ilimitados; o interpretador Python automaticamente atribuirá tanta memória quanto necessária à medida que os números ficarem maiores. Isto significa que calculamos números muito grandes sem passos especiais." ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "70934557307860443711736098025989133248003781773149967193603515625" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "35**42" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Em muitas outras linguagens de programação, tais como C e FORTRAN, inteiros ocupam um tamanho fixo de 4 bytes, permitindo $2^{32}$ valores diferentes, mas tipos diferentes estão disponíveis com diferentes tamanhos. Para números que cabem dentro desses limites, os cálculos podem ser mais rápidos, mas você pode ter de verificar que os números não excedam os limites. Calcular um número além dos limites é o mesmo que incorrer em *overflow de inteiro*, e pode produzir resultados estranhos.\n", "\n", "Mesmo em Python, precisamos estar cientes disto quando usamos o NumPy. O NumPy usa inteiros com um tamanho fixo porque ele armazena muitos deles juntos e precisa calculá-los eficientemente. A documentação sobre [tipos de dados do NumPy](http://docs.scipy.org/doc/numpy/user/basics.types.html) inclui uma gama de tipos inteiros denominados pelo tamanho deles. Então, `int16`, por exemplo, é um inteiro de 16 bits, com $2^{16}$ valores possíveis. \n", "\n", "Inteiros podem também ser do tipo *signed*, quando permitem valores positivos ou negativos, ou do tipo *unsigned*, quando permitem apenas valores positivos. Por exemplo:\n", "\n", "* `uint16` (*unsigned*) varia de 0 a $2^{16}-1$\n", "* `int16` (*signed*) varia de $-2^{15}$ a $2^{15}-1$" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Números em Ponto Flutuante\n", "\n", "Uma string contendo um número em ponto flutuante pode ser convertida em um ponto flututante usando o comando `float()`:" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "35.342" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = '35.342'\n", "b = float(a)\n", "b" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "float" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(b)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Números Complexos \n", "\n", "A linguagem Python (assim como Fortran e Matlab) possui números complexos predefinidos. Aqui estão alguns exemplos sobre como usá-los:" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(1+3j)" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = 1 + 3j\n", "x" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3.1622776601683795" ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ "abs(x) # calcula o valor absoluto " ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3.0" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x.imag" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1.0" ] }, "execution_count": 34, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x.real" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(-8+6j)" ] }, "execution_count": 35, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x * x" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(10+0j)" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x * x.conjugate()" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(3+9j)" ] }, "execution_count": 37, "metadata": {}, "output_type": "execute_result" } ], "source": [ "3 * x" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note que se você desejar executar operações mais complicadas (tais como calcular a raiz quadrada, etc.) você terá que usar o módulo `cmath` (Complex MATHematics):" ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(1.442615274452683+1.0397782600555705j)" ] }, "execution_count": 39, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import cmath\n", "\n", "cmath.sqrt(x)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Funções aplicáveis a todos os tipos de números\n", "\n", "A função `abs()` retorna o valor absoluto (módulo) de um número:" ] }, { "cell_type": "code", "execution_count": 50, "metadata": { "collapsed": true }, "outputs": [], "source": [ "a = -45.463\n", "abs(a)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note que `abs()` também funciona para números complexos (veja acima).\n", "\n", "Sequencias\n", "---------\n", "\n", "Sequencias de caracteres (`string`), listas (`lists`) e tuplas (`tuples`) são *sequencias*. Elas podem ser *indexadas* e *fatiadas* da mesma maneira.\n", "\n", "Tuplas e *strings* são “imutáveis” (*immutable*). Basicamente, isto significa que não podemos alterar elementos individuais dentro da tupla, nem alterar caracteres individuais dentro de uma *string*, ao passo que listas são \"mutáveis\" (*mutable*), ou seja, podemos alterar seus elementos.\n", "\n", "As sequencias compartilham as seguintes operações:\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "
`a[i]`retorna o *i*-ésimo elemento de `a`
`a[i:j]`retorna elementos de *i* até *j* − 1
`len(a)`retorna o número de elementos na sequencia
`min(a)`retorna o menor valor na sequencia
`max(a)`retorna o maior valor na sequencia
`x in a`retorna verdadeiro (`True`) se `x` for um elemento de `a`
`a + b`concatena `a` e `b`
`n * a`cria `n` cópias da sequencia `a`
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Tipo de Sequencia 1: String\n", "\n", "##### Informação adicional\n", "\n", "- Introdução às strings, [Python tutorial 3.1.2](http://docs.python.org/tutorial/introduction.html#strings)\n", "\n", "Uma *string* (imutável) pode ser definida usando aspas simples:" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "a = 'Hello World'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "aspas duplas:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "a = \"Hello World\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "ou aspas triplas da mesma espécie" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "a = \"\"\"Hello World\"\"\"\n", "a = '''Hello World'''" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "O tipo de uma *string* é `str` e uma *string* vazia é dada por `\"\"`:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "a = \"Hello World\"\n", "type(a)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "b = \"\"\n", "type(b)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "type(\"Hello World\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "type(\"\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "O número de caracteres em uma *string* (isto é, seu *comprimento*) pode ser obtido usando a função `len()`:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "10" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = \"Hello Moon\"\n", "len(a)" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = 'teste'\n", "len(a)" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "11" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "len('outro teste')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Você pode combinar (“concatenar”) duas *strings* usando o operador `+`:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "'Hello ' + 'World'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "*Strings* possuem um número de métodos úteis, incluindo, por exemplo `upper()`, que retorna a *string* em maiúsculas:" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'ESTA É UMA SENTENÇA DE TESTE.'" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = \"Esta é uma sentença de teste.\"\n", "a.upper()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Uma lista de métodos disponíveis para *strings* pode ser encontrada na documentação de referência. Se um *prompt* Python estiver disponível, deve-se usar as funções `dir` e `help` para recuperar esta informação, i.e. `dir()` fornece a lista de métodos; `help` pode ser usada para aprender sobre cada método. \n", "\n", "Um método particularmente útil é `split()`, o qual converte uma string em uma lista de strings:" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['Esta', 'é', 'uma', 'sentenca', 'de', 'teste.']" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = \"Esta é uma sentenca de teste.\"\n", "a.split()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "O método `split()` separará a string onde ele encontrar um *espaço em branco*. Um espaço em branco signifca qualquer caracter que é impresso como um espaço em branco, tais como um espaço, vários espaços ou uma indentação de parágrafo (tab). \n", "\n", "Se um caracter separador for passaado como argumento para o método `split()`, uma string pode ser dividida em diferentes partes. Suponha que, por exemplo, queiramos obter uma lista de sentenças completas:" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['O cão está com fome',\n", " ' O gato está entendiado',\n", " ' A cobra está acordada',\n", " '']" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = \"O cão está com fome. O gato está entendiado. A cobra está acordada.\"\n", "a.split(\".\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "O método oposto a `split` é `join`, o qual pode ser usado como segue:" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['O cão está com fome',\n", " ' O gato está entendiado',\n", " ' A cobra está acordada',\n", " '']" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = \"O cão está com fome. O gato está entendiado. A cobra está acordada.\"\n", "s = a.split('.')\n", "s" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'O cão está com fome. O gato está entendiado. A cobra está acordada.'" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "\".\".join(s)" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'O cão está com fome PARE O gato está entendiado PARE A cobra está acordada PARE'" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "\" PARE\".join(s)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Tipo de sequencia 2 : Lista\n", "\n", "##### Informação adicional\n", "\n", "- Introdução a Listas, [Python tutorial, seção 3.1.4](http://docs.python.org/tutorial/introduction.html#lists)\n", "\n", "Uma lista é uma sequencia de objetos. Os objetos podem ser de qualquer tipo. Por exemplo, inteiros:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "a = [34, 12, 54]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "ou *strings*:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "a = ['cão', 'gato', 'rato']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Uma lista vazia é contruída com `[]`:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "a = []" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "O tipo é `list`:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "type(a)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "type([])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Assim como *strings*, o número de elementos em uma lista pode ser obtido usando a função `len()`:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "a = ['cão', 'gato', 'rato']\n", "len(a)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Também é possível *misturar* diferentes tipos de dados em uma mesma lista:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "a = [123, 'pato', -42, 17, 0, 'elefante']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Em Python, uma lista é um objeto. Portanto, é possível que uma lista contenhaoutras listas (porque uma lista guarda uma sequencia de objetos):" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "a = [1, 4, 56, [5, 3, 1], 300, 400]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Você pode combinar (“concatenar”) duas listas usando o operator `+`:" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[3, 4, 5, 34, 35, 100]" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "[3, 4, 5] + [34, 35, 100]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Ou você pode adicionar um objeto ao fim de uma lista usando o método `append()`:" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[34, 56, 23, 42]" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = [34, 56, 23]\n", "a.append(42)\n", "a" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Você pode deletar um objeto a partir de uma lista chamando o método `remove()` e passando o objeto a ser deletado. Por exemplo:" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[34, 23, 42]" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = [34, 56, 23, 42]\n", "a.remove(56)\n", "a" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### O comando range()\n", "\n", "Um tipo especial de lista é frequentemente requerido (na maioria das vezes, junto com laços `for`) e, portanto, existe um comando para gerar essa lista: o comando `range(n)` gera inteiros começando de 0 e indo até n, exclusive (n não entra). Aqui estão alguns exemplos:" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[0, 1, 2]" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "list(range(3))" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "list(range(10))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Este comando é frequentemente usando com laços `for`. Por exemplo, para imprimir os números 02,12,22,32,…,102, o seguinte programa pode ser usado:" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0\n", "1\n", "4\n", "9\n", "16\n", "25\n", "36\n", "49\n", "64\n", "81\n", "100\n" ] } ], "source": [ "for i in range(11):\n", " print(i ** 2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "O comando `range` toma um parâmetro opcional para ser o início da sequencia de inteiros (start) e outro parâmetro opcional para o tamanho do passo. Isto é frequentemente escrito como `range([start],stop,[step])`, onde os argumentos entre colchetes (*i.e.* start e step) são opcionais. Aqui estão alguns exemplos:" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[3, 4, 5, 6, 7, 8, 9]" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "list(range(3, 10)) # start=3" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[3, 5, 7, 9]" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "list(range(3, 10, 2)) # start=3, step=2" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "list(range(10, 0, -1)) # start=10,step=-1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Por que estamos invocando `list(range())`?\n", "\n", "Em Python 3, `range()` gera os números sob demanda. Quando você usa `range()` em um laço `for`, isto é mais eficiente \n", "porque ele não utiliza memória com uma lista de números. Passando-o para `list()`, nós o forçamos a gerar todos os seus números, assim vendo o que ele faz.\n", "\n", "Para obter o mesmo comportamento eficiente em Python 2, use `xrange()` em vez de `range()`." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Tipo de Sequencia 3: Tuplas\n", "\n", "Uma tupla (*tuple*) é uma sequencia (imutável) de objetos. Tuplas são muito similares em comportamento a listas com a exceção de que não podem ser modificadas (i.e. são imutáveis).\n", "\n", "Por exemplo, os objetos em uma sequencia podem ser de qualquer tipo:" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(12, 13, 'cão')" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = (12, 13, 'cão')\n", "a" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "12" ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a[0]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Os parênteses não são necessários para definir uma tupla: apenas uma sequencia de objetos separadas por vírgulas é suficiente para definir uma tupla:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "a = 100, 200, 'pato'\n", "a" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "embora seja boa prática de programação incluir os parênteses onde eles ajudam a mostrar que uma tupla está definida.\n", "Tuplas podem também ser usadas para fazer duas atribuições ao mesmo tempo:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "x, y = 10, 20\n", "x" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "y" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Isto pode ser usado para fazer um *swap* dos objetos. Por exemplo," ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2" ] }, "execution_count": 34, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = 1\n", "y = 2\n", "x, y = y, x\n", "x" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1" ] }, "execution_count": 35, "metadata": {}, "output_type": "execute_result" } ], "source": [ "y" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A tupla vazia é dada por `()`" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "t = ()\n", "len(t)" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "tuple" ] }, "execution_count": 37, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(t)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A notação para uma tupla contendo um valor pode parecer um pouco estranha, em princípio:" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "tuple" ] }, "execution_count": 38, "metadata": {}, "output_type": "execute_result" } ], "source": [ "t = (42,)\n", "type(t)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "len(t)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A vírgula adicional é necessária para distinguir `(42,)` de `(42)`, em que, no segundo caso, os parênteses seriam interpretados como um operador de precedência: `(42)` simplifica-se para `42`, que é apenas um número:" ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "int" ] }, "execution_count": 39, "metadata": {}, "output_type": "execute_result" } ], "source": [ "t = (42)\n", "type(t)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Este exemplo mostra a imutabilidade de uma tupla:" ] }, { "cell_type": "code", "execution_count": 42, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "12" ] }, "execution_count": 42, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = (12, 13, 'cão')\n", "a[0]" ] }, { "cell_type": "code", "execution_count": 41, "metadata": {}, "outputs": [ { "ename": "TypeError", "evalue": "'tuple' object does not support item assignment", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0ma\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m1\u001b[0m \u001b[0;31m# tenta-se alterar o primeiro elemento da tupla de 12 para 1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mTypeError\u001b[0m: 'tuple' object does not support item assignment" ] } ], "source": [ "a[0] = 1 # tenta-se alterar o primeiro elemento da tupla de 12 para 1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A imutabilidade é a principal diferença entre uma tupla e uma lista, que é mutável. Devemos usar tuplas quando não quisermos que o conteúdo seja alterado.\n", "\n", "Note que as funções em Python que retornam mais do que um valor, os retornam em tuplas (isto faz sentido porque você não deseja que estes valores sejam alterados).\n", "\n", "### Indexando sequencias\n", "\n", "##### Informação adicional\n", "\n", "- Introdução a *strings* e indexação: [Python tutorial, seção 3.1.2](http://docs.python.org/tutorial/introduction.html#strings), a seção relevante está começando depois que as strings foram apresentadas.\n", "\n", "Objetos individuais em listas podem ser acessados usando o índice do objeto e colchetes (`[` e `]`):" ] }, { "cell_type": "code", "execution_count": 43, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'cão'" ] }, "execution_count": 43, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = ['cão', 'gato', 'rato']\n", "a[0]" ] }, { "cell_type": "code", "execution_count": 44, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'gato'" ] }, "execution_count": 44, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a[1]" ] }, { "cell_type": "code", "execution_count": 45, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'rato'" ] }, "execution_count": 45, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a[2]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note que em Python (assim como em C, mas diferentemente de Fortran e Matlab), o *índice começa a contar a partir de zero!*\n", "\n", "Python fornece um atalho bastante útil para recuperar o último elemento em uma lista: para isto, usa-se o índice “-1”, onde o sinal de menos indica que é um elemento *do final* da lista. Semelhantemente, o índice “-2” retornará o penúltimo elemento:" ] }, { "cell_type": "code", "execution_count": 46, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'rato'" ] }, "execution_count": 46, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = ['cão', 'gato', 'rato']\n", "a[-1]" ] }, { "cell_type": "code", "execution_count": 47, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'gato'" ] }, "execution_count": 47, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a[-2]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Se você preferir, você pode pensar no índice `a[-1]` como uma notação compacta para `a[len(a) - 1]`.\n", "\n", "Lembre-se que *strings* (assim como listas) também são um tipo de sequencia e podem ser indexadas da mesma maneira:" ] }, { "cell_type": "code", "execution_count": 48, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'H'" ] }, "execution_count": 48, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = \"Hello World!\" \n", "a[0]" ] }, { "cell_type": "code", "execution_count": 49, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'e'" ] }, "execution_count": 49, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a[1]" ] }, { "cell_type": "code", "execution_count": 50, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'d'" ] }, "execution_count": 50, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a[10]" ] }, { "cell_type": "code", "execution_count": 51, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'!'" ] }, "execution_count": 51, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a[-1]" ] }, { "cell_type": "code", "execution_count": 52, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'d'" ] }, "execution_count": 52, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a[-2]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Fatiando sequencias\n", "\n", "##### Informação adicional\n", "\n", "- Introdução a *strings*, indexação e fatiamento no [Python tutorial, seção 3.1.2](http://docs.python.org/tutorial/introduction.html#strings)\n", "\n", "O fatiamento (*slicing*) de sequencias pode ser usado para recuperar mais do que um elemento. Por exemplo:" ] }, { "cell_type": "code", "execution_count": 53, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'Hel'" ] }, "execution_count": 53, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = \"Hello World!\"\n", "a[0:3]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Escrevendo `a[0:3]`, buscamos os 3 primeiros elementos começando do índice 0. Semelhantemente:" ] }, { "cell_type": "code", "execution_count": 54, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'ell'" ] }, "execution_count": 54, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a[1:4]" ] }, { "cell_type": "code", "execution_count": 55, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'He'" ] }, "execution_count": 55, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a[0:2]" ] }, { "cell_type": "code", "execution_count": 56, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'Hello '" ] }, "execution_count": 56, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a[0:6]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Podemos usar índices negativos para nos referirmos ao fim da sequencia:" ] }, { "cell_type": "code", "execution_count": 62, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'Hello World'" ] }, "execution_count": 62, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a[0:-1]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Também é possível ignorar índices do início ou fim da sequencia, assim retornando todos os elementos exceto os ignorados. Aqui estão alguns exemplos para tornar isto mais claro:" ] }, { "cell_type": "code", "execution_count": 63, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'Hello'" ] }, "execution_count": 63, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = \"Hello World!\"\n", "a[:5]" ] }, { "cell_type": "code", "execution_count": 64, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "' World!'" ] }, "execution_count": 64, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a[5:]" ] }, { "cell_type": "code", "execution_count": 65, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'d!'" ] }, "execution_count": 65, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a[-2:]" ] }, { "cell_type": "code", "execution_count": 66, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'Hello World!'" ] }, "execution_count": 66, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a[:]\n", "b = a" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note que `a[:]` gerará uma *cópia* de `a`. O uso de índices no fatiamento é feito por pessoas experientes em contagem intuitiva. Se você se sentir desconfortável com o fatiamento, dê uma olhada nesta citação do [Python tutorial (seção 3.1.2)](http://docs.python.org/tutorial/introduction.html#strings):\n", "\n", "> A melhor maneira de lembrar como as fatias funcionam é pensar como se os índices apontassem entre os caracteres, com a aresta esquerda do primeiro caracter numerada de 0. Então, a aresta direita do último caracter de uma *string* de 5 caracteres tem índice 5. Por exemplo:\n", ">\n", "> +---+---+---+---+---+ \n", "> | H | e | l | l | o |\n", "> +---+---+---+---+---+ \n", "> 0 1 2 3 4 5 <-- use para INDEXAÇÃO\n", "> -5 -4 -3 -2 -1 <-- use para INDEXAÇÃO a partir do final\n", ">\n", "> A primeira linha de números fornece a posição dos índices de fatiamento 0...5 na string; a segunda linha fornece os índices negativos correspondentes. A fatia de i até j consiste de todos os caracteres entre as arestas rotuladas de i e j, respectivamente.\n", "\n", "Assim, o ponto importante é que para o fatiamento (*slicing*), devemos pensar os índices como se apontassem entre os caracteres.\n", "\n", "Para indexação (*indexing*), é melhor pensar como se os índices apontassem para os caracteres. Aqui está um pequeno resumo gráfico dessas regras:\n", "\n", " 0 1 2 3 4 <-- use para INDEXAÇÃO\n", " -5 -4 -3 -2 -1 <-- use para INDEXAÇÃO a partir do final\n", " +---+---+---+---+---+ \n", " | H | e | l | l | o |\n", " +---+---+---+---+---+ \n", " 0 1 2 3 4 5 <-- use para FATIAMENTO\n", " -5 -4 -3 -2 -1 <-- use para FATIAMENTO a partir do final\n", " " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Se você não estiver certo sobre qual é o índice correto, é sempre uma boa técnica brincar um pouco com um pequeno exemplo no *prompt* do Python para testar as coisas antes e/ou durante a escrita de seus programas.\n", "\n", "### Dicionários\n", "\n", "Dicionários são também chamados de “arrays associativos” ou \"tabelas hash\" (“hash tables”). Dicionários são conjuntos *não-ordenados* de pares *palavra-chave/valor* (*key/value*).\n", "\n", "Um dicionário vazio pode ser criado usando chaves:" ] }, { "cell_type": "code", "execution_count": 68, "metadata": { "collapsed": true }, "outputs": [], "source": [ "d = {}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Pares palavra-chave/valor podem ser adicionados como:" ] }, { "cell_type": "code", "execution_count": 69, "metadata": {}, "outputs": [], "source": [ "d['hoje'] = '22 graus C' # 'hoje' é a palavra-chave" ] }, { "cell_type": "code", "execution_count": 70, "metadata": { "collapsed": true }, "outputs": [], "source": [ "d['ontem'] = '19 graus C'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`d.keys()` retorna uma lista de todas as palavras-chave:" ] }, { "cell_type": "code", "execution_count": 71, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "dict_keys(['hoje', 'ontem'])" ] }, "execution_count": 71, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d.keys()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Podemos recuperar valores usando a palavra-chave como índice:" ] }, { "cell_type": "code", "execution_count": 72, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'22 graus C'" ] }, "execution_count": 72, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d['hoje']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Outras maneiras de preencher um dicionário se os dados são conhecidos no momento da criação são:" ] }, { "cell_type": "code", "execution_count": 73, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{2: 4, 3: 9, 4: 16, 5: 25}" ] }, "execution_count": 73, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d2 = {2:4, 3:9, 4:16, 5:25}\n", "d2" ] }, { "cell_type": "code", "execution_count": 74, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'a': 1, 'b': 2, 'c': 3}" ] }, "execution_count": 74, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d3 = dict(a=1, b=2, c=3)\n", "d3" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A função `dict()` cria um dicionário vazio.\n", "\n", "Outros métodos úteis de dicionário incluem `values()`, `items()` e `get()`. Você pode usar `in` para verificar a presença de valores." ] }, { "cell_type": "code", "execution_count": 75, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "dict_values(['22 graus C', '19 graus C'])" ] }, "execution_count": 75, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d.values()" ] }, { "cell_type": "code", "execution_count": 76, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "dict_items([('hoje', '22 graus C'), ('ontem', '19 graus C')])" ] }, "execution_count": 76, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d.items()" ] }, { "cell_type": "code", "execution_count": 77, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'22 graus C'" ] }, "execution_count": 77, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d.get('hoje','desconhecido')" ] }, { "cell_type": "code", "execution_count": 80, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'desconhecido'" ] }, "execution_count": 80, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d.get('amanhã','desconhecido')" ] }, { "cell_type": "code", "execution_count": 81, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 81, "metadata": {}, "output_type": "execute_result" } ], "source": [ "'hoje' in d" ] }, { "cell_type": "code", "execution_count": 82, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 82, "metadata": {}, "output_type": "execute_result" } ], "source": [ "'amanhã' in d" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "O método `get(key,default)` fornecerá o valor para uma dada `key` se essa palavra-chave existir, caso contrário ela retornará o objeto `default`. Aqui está um exemplo mais complexo:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "order = {} # cria um dicionário vazio\n", "\n", "#adiciona pedidos à medida que chegam \n", "order['Pedro'] = 'Uma lata de cerveja'\n", "order['Paulo'] = 'Um suco de laranja'\n", "order['Maria'] = 'Uma lata de agua tônica'\n", "\n", "#entrega pedidos no bar\n", "for person in order.keys():\n", " print(person, \"solicita\", order[person])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Algumas tecnicalidades adicionais:\n", "\n", "- A palavra-chave pode ser qualquer objeto Python (imutável). Nisto incluem:\n", "\n", " - números\n", "\n", " - strings\n", "\n", " - tuplas.\n", "\n", "- dicionários são muito rápidos na recuperação de valores (uma vez dada a palavra-chave)\n", "\n", "Um outro exemplo para demonstrar a vantagem de se usar dicionários em vez de pares de listas:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "dic = {} # cria dicionário vazio\n", "\n", "dic[\"Helio\"] = \"sala 1033\" # preenche dicionário\n", "dic[\"Anderson C\"] = \"sala 1031\" # \"Anderson C\" é a chave\n", "dic[\"Kennedy\"] = \"sala 1027\" # \"sala 1027\" é o valor\n", "\n", "for key in dic.keys():\n", " print(key, \"trabalha na\", dic[key])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Sem o dicionário:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "pessoas = [\"Helio\",\"Anderson C\",\"Kennedy\"]\n", "salas = [\"sala 1033\",\"sala 1031\",\"sala 1027\"]\n", "\n", "# possivel inconsistencia aqui visto que temos duas listas\n", "if not len( pessoas ) == len( salas ):\n", " raise RuntimeError(\"pessoas e salas diferem em comprimento\")\n", "\n", "for i in range( len( salas ) ):\n", " print(pessoas[i],\"trabalha na\",salas[i])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Passando argumentos para funções\n", "------------------------------\n", "\n", "Esta seção contém algumas ideias mais avançadas e faz uso de conceitos que serão somente apresentados mais tarde neste texto. A seção pode ser mais facilmente acessível em um estágio posterior.\n", "\n", "Quando objetos são passados para uma função, o Python sempre passa (o valor da) referência do objeto para a função. Efetivamente, isto significa chamar a função *por referência*, embora nos refiramos a isto como chamar por *valor* (da referência).\n", "\n", "Revisaremos a passagem de argumentos por valor e por referência antes de discutirmos outras situação em Python com maiores detalhes.\n", "\n", "### Passagem de argumento por valor\n", "\n", "Pode-se esperar que, se passarmos um objeto por valor para uma função, as modificações desse valor dentro da função não afetarão o objeto (porque não passamos o objeto em si, mas apenas seu valor, que é uma cópia). Aqui está um exemplo desse comportamento (em C):\n", "\n", "```c\n", "#include \n", "\n", "void pass_by_value(int m) {\n", " printf(\"in pass_by_value: received m=%d\\n\",m);\n", " m=42;\n", " printf(\"in pass_by_value: changed to m=%d\\n\",m);\n", "}\n", "\n", "int main(void) {\n", " int global_m = 1;\n", " printf(\"global_m=%d\\n\",global_m);\n", " pass_by_value(global_m);\n", " printf(\"global_m=%d\\n\",global_m);\n", " return 0;\n", "}\n", "```\n", "\n", "juntamente com a saída correspondente:\n", "\n", " global_m=1\n", " in pass_by_value: received m=1\n", " in pass_by_value: changed to m=42\n", " global_m=1\n", "\n", "\n", "O valor `1` da variável global `global_m` não é modificado quando a função `pass_by_value` altera seu argumento de entrada para 42." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Passagem de argumento por referência\n", "\n", "Chamar uma função por referência, por outro lado, significa que o objeto fornecido a uma função é uma referência ao objeto. Isso significa que a função verá o mesmo objeto que no código de chamada (porque eles estão referenciando o mesmo objeto: podemos pensar na referência como um ponteiro para o local na memória onde o objeto está localizado). Qualquer alteração que atue sobre o objeto dentro da função, será visível no objeto no nível de chamada (porque a função realmente opera no mesmo objeto, e não em uma cópia dele).\n", "\n", "Aqui está um exemplo que mostra isso usando ponteiros em C:\n", "\n", "```c\n", "#include \n", "\n", "void pass_by_reference(int *m) {\n", " printf(\"in pass_by_reference: received m=%d\\n\",*m);\n", " *m=42;\n", " printf(\"in pass_by_reference: changed to m=%d\\n\",*m);\n", "}\n", "\n", "int main(void) {\n", " int global_m = 1;\n", " printf(\"global_m=%d\\n\",global_m);\n", " pass_by_reference(&global_m);\n", " printf(\"global_m=%d\\n\",global_m);\n", " return 0;\n", "}\n", "```\n", "\n", "juntamente com a saída correspondente:\n", "\n", " global_m=1\n", " in pass_by_reference: received m=1\n", " in pass_by_reference: changed to m=42\n", " global_m=42" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "O C++ fornece a capacidade de passar argumentos como referências adicionando um \"&\" à frente do nome do argumento na definição da função:\n", "\n", "\n", "```cpp\n", "#include \n", "\n", "void pass_by_reference(int &m) {\n", " printf(\"in pass_by_reference: received m=%d\\n\",m);\n", " m=42;\n", " printf(\"in pass_by_reference: changed to m=%d\\n\",m);\n", "}\n", "\n", "int main(void) {\n", " int global_m = 1;\n", " printf(\"global_m=%d\\n\",global_m);\n", " pass_by_reference(global_m);\n", " printf(\"global_m=%d\\n\",global_m);\n", " return 0;\n", "}\n", "```\n", "\n", "juntamente com a saída correspondente:\n", "\n", " global_m=1\n", " in pass_by_reference: received m=1\n", " in pass_by_reference: changed to m=42\n", " global_m=42" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Passagem de argumento em Python\n", "\n", "Em Python, os objetos são passados como o valor de uma referência (ponteiro) para o objeto. Dependendo da forma como a referência é usada na função e, dependendo do tipo de objeto que ele referencia, isso pode resultar em um comportamento de \"passagem por referência\" (onde qualquer alteração no objeto recebido como argumento de função é imediatamente refletida no nível de chamada).\n", "\n", "Aqui estão três exemplos para discutir isso. Começamos passando uma lista para uma função que itera através de todos os elementos na sequência e dobra o valor de cada elemento:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def double_the_values(l):\n", " print(\"in double_the_values: l = %s\" % l)\n", " for i in range(len(l)):\n", " l[i] = l[i] * 2\n", " print(\"in double_the_values: changed l to l = %s\" % l)\n", "\n", "l_global = [0, 1, 2, 3, 10]\n", "print(\"In main: s=%s\" % l_global)\n", "double_the_values(l_global)\n", "print(\"In main: s=%s\" % l_global)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A variável `l` é uma referência ao objeto lista. A linha `l[i] = l[i] * 2` avalia primeiro o lado direito e lê o elemento com o índice `i`, depois multiplica por dois. Uma referência a este novo objeto é então armazenada no objeto lista `l` na posição com o índice `i`. Por isso, modificamos o objeto lista, que é referenciado através de `l`.\n", "\n", "A referência ao objeto lista nunca muda: a linha `l[i] = l[i] * 2` muda os elementos `l[i]` da lista `l` mas nunca a referência `l` para a lista. Assim, tanto a função como o nível de chamada estão operando no mesmo objeto através das referências `l` e` global_l`, respectivamente.\n", "\n", "Em contraste, aqui está um exemplo que não modifica os elementos da lista dentro da função, o que produz esta saída:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def double_the_list(l):\n", " print(\"in double_the_list: l = %s\" % l)\n", " l = l + l\n", " print(\"in double_the_list: changed l to l = %s\" % l)\n", "\n", "l_global = \"Hello\"\n", "print(\"In main: l=%s\" % l_global)\n", "double_the_list(l_global)\n", "print(\"In main: l=%s\" % l_global)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "O que acontece aqui é que, durante a avaliação de `l = l + l`, um novo objeto é criado que contém ` l + l`, e que, em seguida, vinculamos o nome `l` a ele. No processo, perdemos as referências à lista `l` que foi passada à função (e, portanto, não alteramos a lista passada à função).\n", "\n", "Finalmente, vejamos o que essa saída produz:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def double_the_value(l):\n", " print(\"in double_the_value: l = %s\" % l)\n", " l = 2 * l\n", " print(\"in double_the_values: changed l to l = %s\" % l)\n", "\n", "l_global = 42\n", "print(\"In main: s=%s\" % l_global)\n", "double_the_value(l_global)\n", "print(\"In main: s=%s\" % l_global)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Neste exemplo, também duplicamos o valor (de 42 a 84) dentro da função. No entanto, quando vinculamos o objeto 84 ao nome `l` (que é a linha `l = l * 2`), criamos um novo objeto (84), e nós vinculamos o novo objeto a `l`. No processo, perdemos a referência ao objeto 42 dentro da função. Isso não afeta o próprio objeto 42, nem a referência `l_global` para ele.\n", "\n", "Em resumo, o comportamento em Python de passar argumentos para uma função pode parecer variável (se o visualizarmos a partir do ponto de vista de _passagem por valor_ versus _passagem por referência_). No entanto, ele é sempre feito como uma chamada por valor, onde o valor é uma referência ao objeto em questão, e o comportamento pode ser explicado pelo mesmo raciocínio em todos os casos." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Considerações de desempenho\n", "\n", "As chamadas de função por valor requerem a cópia do valor antes de ele ser passado à função. Sob o ponto de vista de desempenho (tempo de execução e requisitos de memória), isso pode ser um processo caro se o valor for grande. (Imagine que o valor é um objeto `numpy.array` que pode ser de vários Megabytes ou Gigabytes de tamanho.)\n", "\n", "Geralmente se preferem chamadas por referência para objetos grandes, pois neste caso apenas um ponteiro para os objetos é passado, independentemente do tamanho real do objeto e, portanto, isso geralmente é mais rápido do que a chamada por valor.\n", "\n", "A abordagem em Python de (efetivamente) chamar por referência é, portanto, eficiente. No entanto, precisamos ter cuidado para que nossa função não modifique os dados que ela receber quando isso não é desejado.\n", "\n", "### Modificação de dados por desatenção\n", "\n", "Geralmente, uma função não deve modificar os dados passados como entrada para ela.\n", "\n", "Por exemplo, o código a seguir demonstra a tentativa de determinar o valor máximo de uma lista, e uma modificação - desatenta - da lista no processo:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def mymax(s): # demonstrando efeito colateral\n", " if len(s) == 0:\n", " raise ValueError('mymax() arg is an empty sequence')\n", " elif len(s) == 1:\n", " return s[0]\n", " else:\n", " for i in range(1, len(s)):\n", " if s[i] < s[i - 1]:\n", " s[i] = s[i - 1]\n", " return s[len(s) - 1]\n", "\n", "s = [-45, 3, 6, 2, -1]\n", "print(\"in main before caling mymax(s): s=%s\" % s)\n", "print(\"mymax(s)=%s\" % mymax(s))\n", "print(\"in main after calling mymax(s): s=%s\" % s)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "O usuário da função `mymax()` não esperaria que o argumento de entrada fosse modificado quando a função fosse executada. Em geral, devemos evitar isso. Existem várias maneiras de encontrar melhores soluções para o problema dado:\n", "\n", "- Neste caso particular, poderíamos usar a função predefinida `max()` para obter o valor máximo de uma sequência.\n", "\n", "- Se sentirmos que precisamos nos ater ao armazenamento de valores temporários dentro da lista \\[isso na verdade não é necessário\\], podemos criar uma cópia da lista de entrada `s` primeiro e, em seguida, proceder com o algoritmo (veja adiante sobre cópia de objetos).\n", "\n", "- Escolha outro algoritmo, o qual use uma variável temporária extra ao invés de abusar da lista para isso. Por exemplo:\n", "\n", "- Podemos passar uma tupla (em vez de uma lista) para a função: uma tupla é *imutável* e, portanto, nunca pode ser modificada (isso resultaria em uma exceção sendo gerada quando a função tentasse escrever nos elementos da tupla).\n", "\n", "### Copiando objetos\n", "\n", "Python fornece a função `id()`, a qual retorna um número inteiro que é exclusivo para cada objeto. (Na implementação atual do CPython, este é o endereço da memória.) Podemos usá-la para identificar se dois objetos são iguais.\n", "\n", "Para copiar um objeto cujo tipo é uma sequência (incluindo listas), podemos fatiá-lo, i.e. se `a` for uma lista, então `a[:]` retornará uma cópia de `a`. Aqui está uma demonstração:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "a = list(range(10))\n", "a" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "b = a\n", "b[0] = 42\n", "a # alterando-se b, altera-se a" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "id(a)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "id(b)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "c = a[:] \n", "id(c) # c é um objeto diferente" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "c[0] = 100 \n", "a # altera-se c, mas a permanece inalterado" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A biblioteca padrão em Python fornece o módulo `copy`, o qual provê funções de cópia que podem ser usadas para criar cópias de objetos. Poderíamos ter usado `import copy; c = copy.deepcopy(a)` em vez de `c = a[:]`.\n", "\n", "Igualdade e Identidade\n", "------------------------------\n", "\n", "Uma questão relacionada diz respeito à igualdade de objetos.\n", "\n", "### Igualdade\n", "\n", "Os operadores `<`, `>`, `==`, `>=`, `<=`, e `!=` comparam os *valores* de dois objetis. Os objetos não precisam ter o mesmo tipo. Por exemplo:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "a = 1.0; b = 1\n", "type(a)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "type(b)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "a == b" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Então, o operador `==` verifica se os valores de dois objetos são iguais.\n", "\n", "### Identidade/Semelhança\n", "\n", "Para verificar se dois objetos `a` e `b` são os mesmos (i.e. se `a` e `b` fazem referência ao mesmo local na memória), podemos usar o operator `is` (continuação do exemplo anterior):" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "a is b" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Certamente, eles são diferentes aqui, já que não são do mesmo tipo.\n", "\n", "Também podemos lançar mão da função `id` que, de acordo com a documentação da versão Python 2.7: \"*Retorna a identidade de um objeto, única entre objetos existindo simultaneamente. (Dica: é o endereço do objeto na memória.)*\"" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "id(a)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "id(b)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "que mostra que `a` e `b` são armazenados em diferentes locais na memória.\n", "\n", "### Exemplo: Igualdade e identidade\n", "\n", "Fechamos com um exemplo envolvendo listas:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "x = [0, 1, 2]\n", "y = x\n", "x == y" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "x is y" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "id(x)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "id(y)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Aqui, `x` e `y` são referências ao mesmo endereço na memória. Eles são idênticos e o operador `is` confirma isso. O ponto importante a lembrar é que a linha 2 (`y = x`) cria uma nova referência `y` para a mesma lista da qual `x` já é uma referência.\n", "\n", "Consequentemente, podemos alterar os elementos de `x` que `y` mudará simultaneamente, pois `x` e `y` se referem ao mesmo objeto:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "x" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "y" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "x is y" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "x[0] = 100\n", "y" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "x" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Em contraste, se usarmos `z = x [:]` (em vez de `z = x`) para criar um novo objeto `z`, então a operação de fatiamento `x[:]` criará uma cópia da lista `x`, e a nova referência `z` apontará para esta cópia. O *valor* de `x` e `z` será o mesmo, mas `x` e `z` não serão o mesmo objeto (eles não serão idênticos):" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "x" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "z = x[:] # cria cópia de x antes de atribui-lo a z\n", "z == x # mesmo valor" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "z is x # nao sao o mesmo objeto" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "id(z) # confirmacao pela id()" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "id(x)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "x" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "z" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Consequentemente, podemos alterar `x` sem que `z` seja alterado. Por exemplo (continuação):" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "x[0] = 42\n", "x" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "z" ] } ], "metadata": { "kernelspec": { "display_name": "Python 2", "language": "python", "name": "python2" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.1" } }, "nbformat": 4, "nbformat_minor": 1 }