<!-- Introdução à Programação - 2017 - Prof. Leoônidas de Oliveira Brandão Introdução aos vetores em Python @url: ./codigos/varias_entradas_saidas.py LInE (Laboratory of Informatics in Education) - http://www.usp.br/line IME - USP Material didático Pode usar livrevemente este material para fins não comerciais, devendo sempre fazer referência à autoria. Sugestões/apontamento são bem vindos: leo@ime.usp.br (favor indicar no assunto "material de introducao 'a programacao") Prof. Leônidas de Oliveira Brandão http://www.ime.usp.br/~leo http://line.ime.usp.br http://www.matemtica.br --> <meta http-equiv='Content-Type' content='text/html; charset=UTF-8'> <meta name='keywords' content='mac0122, material, professores, leonidas de oliveira brandao'> <link rel='stylesheet' type='text/css' href='css_img_js_conf/all.css'> <link rel='stylesheet' type='text/css' href='css_img_js_conf/line_introducao_programacao.css'> <script src="css_img_js_conf/defineLInE.js"></script> <!-- para referencias 'a documentos internos --> <div class="pagina"> <!-- <center><p>[ <a href="#" title=""></a> | <a href="#memoria" title=""></a> ]</p> </center> --> <p class="secao">Introdução aos vetores em <i>Python</i></p> <p> Como estudado no <a href="#" onclick="trocaPagina('introducao_vetores.html')" title="introducao_vetores.html">texto a respeito do conceito de vetores</a>, um vetor é uma sequência de dados ocupando posições consecutivas de memória e por isso existe uma ordem natural (o primeiro elemento, o segundo e assim por diante). A grande vantagem de usar vetor é poder trabalhar com um grande número de variáveis utilizando um único nome (para a variável). Para isso existe uma sintaxe especial para pegar elementos do vetor em posições específicas (como o primeiro elemento ou o décimo elemento). </p> <p> A linguagem <i>Python</i> encapsula bastante o conceito de vetor, agregando funcionalidades e por isso geralmente o material didático sobre <i>vetores</i> em <i>Python</i> utiliza o nome <i>lista</i>. </p> <bloco1>Neste texto: <a class="" title="como ler varios dados entradas com unico ENTER" href="#entradas_saidas">entradas e saídas</a>; <a class="" title="definir e imprimir um vetor" href="#define">definir/imprimir vetor</a>; <a class="" title="definir e imprimir string" href="#string">definir "string"</a>; <a class="" title="sobre referencia e copia de vetores" href="#referencia">referência a listas</a>; <a class="" title="definir e imprimir uma matriz" href="#matriz">definir/imprimir matriz</a>. </bloco1> <br/> <!-- secao --> <a name="entradas_saidas"> <p class="secao">1. Como ler vários dados de uma só vez</p> </a> <p> Em <i>Python</i> entrar vários dados de uma só vez não é tão trivial, é preciso processamento para recuperar os valores, para isso é preciso ler a entrada toda como uma <i>cadeia de caracteres</i> (<i>string</i>). Mais ainda, no <i>Python 2</i> existe uma função especial para isso, a <tt>raw_input</tt>, que no <i>Python 3</i> sumiu! </p> <p> O truque básico é ler como <i>string</i>, quebrar em itens (usando os separadores, geralmente espaço em branco) e por fim converter para o tipo desejado. Por exemplo, para ler dois valores, o primeiro sendo inteiro e o seguindo flutuante, podemos fazer: <br/> <center> <i>Tab. 1. Exemplos de técnicas para ler vários dados com um único <i>ENTER</i> em <i>Python</i>.</i> <table style="border: 1px solid black;"> <tr style="border: 1px solid black;"><td><i>Python 2</i></td> <td> </td> <td><i>Python 3</i></td></tr> <tr> <td><tt style="font-size: 0.8em;">linha = raw_input();<br/> itens = linha.split();<br/> n, val = int(itens[0]), float(itens[1]);<br/> <verm>print</verm>("n=%d, val=%f" % (n,val));</td><td> </td> <td><tt style="font-size: 0.8em;">linha = input();<br/> itens = linha.split();<br/> n, val = int(itens[0]), float(itens[1]);<br/> <verm>print</verm>("n=%d, val=%f" % (n,val));</td></tr> </table></center> </p> <p> Note que usamos um formatador especial <tt>%d</tt> para valores inteiros e <tt>%f</tt> para ponto flutuante. </p> <p> No exemplo acima precisamos converter o primeiro item para inteiro e o segundo para <i>flutuante</i>. Entretanto se todos itens forem de mesmo tipo, existe uma função que realiza automática o laço percorrendo todos os elementos e convertendo um a uma, é o mapeamento <tt>map</tt>, como ilustrado abaixo. Experimente o código com um única linha de entrada de dados: <tt>0.0 1.0 1.5 2.0 3.0 3.5 <ENTER></tt>. <br/> <center> <i>Tab. 2. Exemplos de técnicas para ler vários dados "reais" com um único <i>ENTER</i> em <i>Python</i>.</i> <table style="border: 1px solid black;"> <tr style="border: 1px solid black;"><td><i>Python 2</i></td> <td> </td> <td><i>Python 3</i></td></tr> <tr> <td><tt style="font-size: 0.8em;">linha = raw_input();<br/> itens = linha.split();<br/> vetor = map(float, itens); <cyan># Erro se tentar: map(int, itens)</cyan><br/> tam = len(vetor);<br/> for i in range(tam) :<br/> <verm>print</verm>("%2d | %4.1f" % (i,vetor[i]));</td><td> </td> <td><tt style="font-size: 0.8em;">linha = input(); itens = linha.split();<br/> vetor = map(float, itens); <cyan># Erro se tentar: map(int, itens)</cyan><br/> tam = len(vetor);<br/> for i in range(tam) :<br/> <verm>print</verm>("%2d | %4.1f" % (i,vetor[i]));</td></tr> </table></center> </p> <p> Note que os formatadores <tt>%d</tt> e <tt>%f</tt> foram usado com parâmetros, <tt>%2d</tt> e <tt>%4.1f</tt>. O primeiro indica que devemos ajutar 2 posições à direita e o segundo ajustar 4 posições à direito e usar apenas 1 casa decimal. Estes formatadores permitem saídas mais interessantes, em particular a construção de tabelas. </p> <p> Pegue <a href="codigos/varias_entradas_saidas.py" title="um exemplo para testar">este código</a> exemplo e "brinque" com ele, altere os formatadores, troque "float" por "int", veja a mensagem de erro, acerte-a. Teste até estar seguro de ter entendido o <tt>raw_input</tt>, o <tt>split</tt>, o <tt>map</tt> e os formatadores <tt>%d</tt> e <tt>%f</tt>. </p> <!-- secao --> <a name="define"> <p class="secao">2. Defininido e imprimindo uma lista</p> </a> <p> Pode-se construir uma lista em <i>Python</i> fornecendo todos seus elementos, como em: <tt>vet = [21, 22, 23, 24];</tt> (o finalizador <tt>;</tt> só é obrigatório se tiver mais de um comando na mesma linha). </p> <p> Pode-se também construtir uma lista em <i>Python</i> de modo interativo, agragando novo elemento a cada passo usando a função comando <tt>append(.)</tt>, como em: <tt>vet.append(10+i);</tt>, que anexa o elemento de valor <tt>10+i</tt> à lista. </p> <p> No exemplo a seguir construimos uma lista com <i>n</i> (usando o valor fixo <i>10</i> no código) elementos, iniciando no <i>10+i</i> e seguindo até o <i>10+n-1</i>. Nesse exemplo ilustramos o uso de iterador (<i>in</i>) e o anexador de novo elemento em lista (<i>append</i>). </p> <div class="exemplo"><i>Exemplo 1</i>. Construir uma lista e imprimir seus elementos. </div><!-- class="exemplo" --> <div class="codigo"> <pre># Python2 para 'print' sem pular linha : <verm>print</verm>("*" , end = ""); from __future__ import print_function n = 10; # Definir vetor/lista com: (10,11,12,13,...10+n-1) vet = []; <cyan># define um vetor vazio</cyan> for i in range(0, n, 1) : <cyan># ou mais simples neste caso "for i in range(n)"</cyan> vet.append(10+i); <cyan># anexe mais um elemento `a lista</cyan> <cyan># Imprime o vetor/lista de uma so' vez (na mesma linha)</cyan> <verm>print</verm>("\nO vetor: ", end=""); <cyan># informe o que vira impresso a seguir (na mesma linha devido ao parametro end=""</cyan> <verm>print</verm>(vet); # Imprimir vet em linha unica na forma "( 0, 0) ( 1, 1)..." <verm>print</verm>("\nNovamente o vetor impresso de 2 modos: "); <cyan># informe o que vira impresso a seguir (e "quebre" a linha)</cyan> i = 0; for item in vet : <cyan># "item in vet" e' um iterador, item comeca em vet[0], depois vet[1] e assim por diante</cyan> <verm>print</verm>("(%2d, %2d) " % (item, vet[i]), end=""); i += 1; <verm>print</verm>(); <cyan># quebre a linha</cyan></pre> </div><!-- class="codigo" --> <!-- secao --> <a name="string"> <p class="secao">3. Defininido uma <i>cadeia de caracteres</i> ("string")</p> </a> <p> Em <i>Python</i> é possível definir um vetor com caracteres, formando uma palavra, ou seja, uma <i>cadeia de caracteres</i>, que abreviadamente é denominada "<i>string</i>". Para isso pode-se fazer uma atribuição como constante ou ler os dados como palavra. Isso é ilustrado no exemplo abaixo. </p> <div class="exemplo"><i>Exemplo 2</i>. Trabalhando com "strings". Uma "string" fixa e digitar uma frase, imprimindo o número de caracteres nela. </div><!-- class="exemplo" --> <div class="codigo"> <pre># Definir "string" string = "0123456789abcdefghih"; <cyan># (1)</cyan> # Imprimir cada caractere da string com seu codigo ASCII <verm>print</verm>("\nImprime caracteres e seus codigos ASCII na forma de tabela\nColuna 1 => caractere; coluna 2 => seu codigo ASCII"); for char in string : <cyan># iterador</cyan> <verm>print</verm>("%20c : %3d" % (char, ord(char))); <cyan># funcao ord(.) devolve codigo ASCII do caractere parametro</cyan> <verm>print</verm>(); <cyan># quebre a linha</cyan> # Agora um entrada de dados via teclado e pegando uma frase como "string" (o ENTER finaliza a frase) <verm>print</verm>("Digite uma frase e tecle ENTER/CR"); string = raw_input(); <cyan># no Python 2 e' obrigatorio usar a funcao 'raw_input' (que tambem funciona no 3)</cyan> <verm>print</verm>("Foi digitada uma frase com %d caracteres: %s" % (len(string), string)); # Observacao: se definiu um vetor como "string" como em (1) acima, NAO e' possivel alterar a "string", por exemplo, # o comando abaixo resulta erro "TypeError: 'str' object does not support item assignment" # string[2] = '*'; <cyan># isso resultaria erro! experimente</cyan></pre> </div><!-- class="codigo" --> <!-- secao --> <a name="referencia"> <p class="secao">4. Sobre copiar ou referenciar um vetor/lista</p> </a> <p> Ao declarar uma <i>lista/tupla</i>, significa que associamos um nome de variável à uma sequência de posições de memória, sendo que cada item pode ter um tamanho distinto dos demais, como em <tt>l = [1,[2],"tres"];</tt>. Uma diferença essencial entre <i>lista</i> (como <tt>l = [1,2,3];</tt>) e <i>tupla</i> (como <tt>l = (1,2,3);</tt>) é que uma <i>lista</i> é <i>mutável</i> (<i>que pode ser altedo</i>) e <i>tupla</i> é <i>imutável</i> (impossível de alterar algum elemento). <center> <img src="img/int_vet_apontador_menor.png" title="representacao de vetor em memoria com indicacao de endereco ocupado"/> </center> </p> <p> Por exemplo, ao declarar a <i>tupla</i> com <tt>v = (1,2,3);</tt>, além do espaćo com informaćões sobre a <i>tupla</i>, são reservadas 3 posições de memória, uma para cada elemento da <i>tupla</i>. Deve-se destacar que usar um comando do tipo <tt>aux = v;</tt>, seja <i>v</i> uma lista ou uma <i>tupla</i>, <i>não implica em copiar</i> <i>v</i>, mas sim ter uma nova referência para <i>v</i>. Assim, no caso de <i>lista</i>, que portanto pode ser alterada, ao usar os comandos<br/> <tt>v = [1,2,3]; aux = v; aux[2] = -1; <verm>print</verm>(v);</tt><br/> será impresso na tela: <tt>[1, 2, -1]</tt>, ou seja, o elemento da posićão 2 de <i>v</i> foi alterado para <i>-1</i>. </p> <p> Mas existe uma funćão em uma biblioteca <i>Python</i> que copia listas genéricas (<tt>copy</tt>). No exemplo a seguir ilustramos como fazer copia de <i>listas</i> ou <i>tuplas</i>. </p> <div class="exemplo"><i>Exemplo 3</i>. Construindo um vetor e imprimindo seus elementos via um apontador. </div><!-- class="exemplo" --> <div class="codigo"> <pre>import copy <cyan># para funcao 'copy(.)'</cyan> <verm>def</verm> copiar (lst_tpl) : <cyan># funcao para copiar elementos de lista/tupla gerando lista nova</cyan> lista = []; for item in lst_tpl : lista.append(item); return lista; lista = [1,2,[3]]; <cyan># define lista com 3 elementos, sendo o terceiro uma lista com 1 elemento</cyan> aux = lista; aux[2] = -1; <cyan># alterou lista[2]</cyan> <verm>print</verm>("Lista: lista = %s" % lista); lista = [1,2,[3]]; <cyan># lista</cyan> <verm>print</verm>("Lista: lista = %s" % lista); aux1 = copy.copy(lista); <cyan># copiar com funcao "copy(.)" de biblioteca "copy"</cyan> aux2 = list(lista); <cyan># copiar com gerar de lista "list(.)"</cyan> aux3 = copiar(lista); <cyan># copiar com funcao local "copiar(.)"</cyan> aux1[2] = -1; <cyan># NAO alterou lista[2]</cyan> aux2[2] = -1; <cyan># NAO alterou lista[2]</cyan> aux3[2] = -1; <cyan># NAO alterou lista[2]</cyan> <verm>print</verm>("aux1=%s, lista=%s" % (aux1, lista)); <verm>print</verm>("aux2=%s, lista=%s" % (aux2, lista)); <verm>print</verm>("aux3=%s, lista=%s" % (aux3, lista)); tupla = [1,2,[3]]; <cyan># tupla</cyan> <verm>print</verm>("Tupla: tupla = %s" % tupla); aux1 = copy.copy(tupla); <cyan># usar funcao 'copy' de biblioteca 'copy'</cyan> aux2 = list(tupla); aux3 = copiar(tupla); <verm>print</verm>("aux1=%s, tupla=%s" % (aux1, tupla)); <verm>print</verm>("aux2=%s, tupla=%s" % (aux2, tupla)); <verm>print</verm>("aux3=%s, tupla=%s" % (aux3, tupla));</pre> </div><!-- class="codigo" --> <p> Experimente! Esse código produz como saída as seguintes linhas: <div class="exemplo"><i>Saídas do exemplo 3</i>. </div><!-- class="exemplo" --> <div class="codigo"> <pre>Lista: lista = [1, 2, -1] Lista: lista = [1, 2, [3]] aux1=[1, 2, -1], lista=[1, 2, [3]] aux2=[1, 2, -1], lista=[1, 2, [3]] aux3=[1, 2, -1], lista=[1, 2, [3]] Tupla: tupla = [1, 2, [3]] aux1=[1, 2, [3]], tupla=[1, 2, [3]] aux2=[1, 2, [3]], tupla=[1, 2, [3]] aux3=[1, 2, [3]], tupla=[1, 2, [3]]</pre> </div><!-- class="codigo" --> </p> <!-- secao --> <a name="matriz"> <p class="secao">5. Defininido matriz como lista de lista</p> </a> <p> Uma vez que um vetor/lista é armazenado consecutivamente na memória, então podemos armazenar vários vetores também consecutivamente para obter algo que represente (e seja tratado como) <i>matriz</i>. Como na imagem abaixo, em que cada alocamos <i>nl</i> vetores consecutivos na memória, cada vetor com <i>nc</i> posições de memória, desde <tt>vet[0]</tt> até <tt>vet[nc-1]</tt>. Assim, podemos ver este agregado de dados como uma matriz <tt>mat[][]</tt>, cuja primeira linha é o primeiro vetor e assim por diante. Isso está ilustrado na imagem abaixo. <center> <img src="img/int_vet_vet_representacao.png" title="representacao matriz e como fica em memoria como vetor de vetor"/> </center> </p> <p> Desse modo obtemos uma estrutura com dois índices que pode ser manipulada como uma matriz (como em <i>mat[i][j]</i>). No exemplo abaixo ilustramos isso de dois modos, imprimindo as linhas da matriz e mostrando que pode-se passar como parâmetro uma linha de matriz para uma função que tenha como <i>parâmetro formal</i> um vetor. </p> <div class="exemplo"><i>Exemplo 3</i>. Construindo matriz como vetor de vetor e ilustrando que cada linha dela é um vetor, podendo portanto ser usado para chamar uma função que tem como parâmetro um vetor. </div><!-- class="exemplo" --> <div class="codigo"> <pre><cyan># Vetor de vetor ou matriz</cyan> # Definir vetor/lista com: (0,1,2,3,...n-1) nl = 3; nc = 4; mat = []; <cyan># define um vetor vazio</cyan> for i in range(0, nl, 1) : <cyan># ou mais simples neste caso "for i in range(n)"</cyan> linha = []; <cyan># define um vetor vazio</cyan> for j in range(0, nc, 1) : <cyan># ou mais simples neste caso "for i in range(n)"</cyan> linha.append(i*n+j); mat.append(linha); <cyan># anexe nova linha `a matriz 'mat'</cyan> # Imprime o vetor/lista de uma so' vez (na mesma linha) <verm>print</verm>("\nA matriz: ", end=""); <cyan># informe o que vira impresso a seguir (na mesma linha devido ao parametro end=""</cyan> <verm>print</verm>(mat); # Pegando o primeiro e segundo elemento da terceira linha de mat: mat[2][1] prim = mat[2][0]; seg = mat[2][1]; <cyan># pegar primeiro e segundo elemento da linha mat[2]</cyan> <verm>print</verm>("O primeiro e segundo elemento da terceira linha da matriz: %d e %d" % (prim, seg)); <verm>print</verm>("Linhas da matriz: 0=%s ; 1=%s ; 2=%s" % (mat[0], mat[1], mat[2])); <cyan># cada linha e' um vetor!</cyan> # <verm>print</verm>(mat[0]); <verm>print</verm>(mat[1]); <verm>print</verm>(mat[2]); # Verifique que cada linha da matriz e' de fato um vetor # Usar a funcao 'somalinha(...)' que soma elementos em vetor for i in range(0, nl) : <verm>print</verm>("Soma da linha %2d = %3d" % (i, somalinha(mat[i])));</pre> </div><!-- class="codigo" --> <!-- secao --> <a name="cuidados"> <p class="secao">6. Cuidados com referencias (ou apelidos)</p> </a> <p> Vocês devem tomar muito cuidado com atribuições envolvendo listas, pois na verdade <b style="color:#aa0000;">não</b> ocorre uma cópia, mas comentado na seção 4. Por exemplo, estude e teste em seu computador a sequência de comandos a seguir. <div class="codigo"><pre>>>> a = [1, 2, 3]; >>> b = a; >>> b[2] = -9; >>> print(a) [1, 2, -9]</pre> <i>Cód. 1. Exemplo de uso de atribuição com listas, equivalente a referência, não cópia. </div> </p> <p> Entretanto o <i>Python</i> oferece um mecanismo que efetivamente realiza uma cópia de cada um dos elementos, portanto envolve um <i>laço</i> de tamanho igual ao número de elementos da lista. Isso é feito usando algo como <tt>[inicio:fim]</tt>, sendo <i>inicio</i> a posição iniciar a partir da qual deseja copiar e <i>fim</i> o último elemento. <br/>Atenção ao <i>fim</i>, não é posição, mas sim número do elemento, então se <i>fim=3</i>, irá copia até o terceiro elemento. Por exemplo, algo como <tt>b = a[4:3];</tt> resultaria em lista vazia, pois o terceiro elemento está antes do elemento da posição <i>4</i>. <div class="codigo"><pre>>>> a = [0, "um", 2, 3, 4, 5, 6, 7, 8]; >>> v1 = a[4:3]; v2 = a[0:3]; print(v1, v2); ([], [0, 'um', 2])</pre> <i>Cód. 2. Exemplo truque para cópiar vários elementos. </div> </p> <p class="autoria"> <a href="https://www.ime.usp.br/~leo" target="_blank" title="seguir para a pagina do prof. Leônidas">Leônidas de Oliveira Brandão</a><br/> <a href="http://www.ime.usp.br/~leo" target="_blank" title="seguir para a página do LInE">http://line.ime.usp.br</a> </p> <p class="rodape"> <b>Alterações</b>:<br/> 2020/08/12: novo formato, pequenas revisões<br/> sexta, 08 May 2020, 21:00<br/> segunda, 03 May 2018, 16:00 </p> </div>