| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306 | 
							- <!--
 
-  Introdução à Programação - 2017 - Prof. Leoônidas de Oliveira Brandão
 
-  Introdução ao uso de funções em Python: variáveis locais, globais e aninhamento de funções
 
-  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">
 
- <p class="secao">Introdução ao uso de funções em Python: variáveis locais, globais e aninhamento de funções</p>
 
- <p>
 
-   Nesta seção apresento um conceito mais "sutil" de programação, para entendê-lo é essencial que você copie os códigos apresentados,
 
-   "cole" em seu editor preferido e os teste até que esteja tudo claro.
 
-   Experimente alterar os exemplos e criar outros: grave-os e os <i>rode</i>.
 
-   <b style="color:#0000aa">Para prender programação é preciso programar!</b>
 
- </p>
 
- <p class="subsubsecao">Cuidado com a sintaxe de função (erro de recorrência não desejada)</p>
 
- <p>
 
-   Um erro que as vezes ocorre é usar de modo equivocado o conceito de <i>devolução</i> do resultado, provocando uma
 
-   recorrência infinita.
 
-   Como a cada chamada da função todas suas variáveis locais precisam ser alocadas na memória, a cada chamada um novo espaço
 
-   de memória é reservado, logo, em algum tempo o seu computador
 
-   <b style="color:#aa0000;" title="não terá mais espaço disponível">não mais "aguentará"</b> e lançará uma mensagem de erro
 
-   indicando algo como <b style="color:#aa0000;" title="RuntimeError: maximum recursion depth exceeded">recursão excedeu profundidade máxima</b>.
 
-   O código abaixo ilustra esse engano, experimente copiá-lo e colá-lo em seu editor preferido e rode-o.
 
- </p>
 
- <p>
 
- <center><div class="codigo"><pre><verm>def</verm> fat (n) :
 
-   f = 1; i = 2;
 
-   while (i<=n) :
 
-     f *= i;
 
-     i += 1;
 
-   return fat(n); <cyan># Erro aqui! RuntimeError: maximum recursion depth exceeded</cyan>
 
- <verd>print</verd>(fat(5));</pre>
 
- </div><br/>
 
-  <i>Cód. 1. Exemplo de engano implicando em recorrência "infinita"</i>.
 
-  </center>
 
- </p>
 
- <p>
 
-   Para corrigir o engano do código 1, troque a linha de <i>devolução</i> por <tt>return f;</tt>.
 
-   Isso eliminará as recorrências.
 
-   Por outro lado, é possível implementar uma versão correta e recursiva,
 
-   veja este 
 
-   <a href="#" onclick="trocaPagina('introducao_recursividade.html')" title="examinar texto sobre funções recorrentes">texto sobre recursividade</a>.
 
- </p>
 
- <p class="subsubsecao">Sobre o aninhamento de funções na linguagem <i>Python</i></p>
 
- <p>
 
-   Em várias linguagens de programação, <i>Python</i> em particular, é possível declarar função dentro de função (<b>aninhar</b>).
 
-   Por exemplo, dentro de uma função de nome <i>funcao2</i>, pode-se declarar outra função de nome <i>funcao3</i>.
 
-   O resultado é que, dentro da primeira função, pode-se invocar a segunda, mas em nenhum outro local do código seria possível
 
-   invocar esssa função <i>funcao3</i>.
 
- </p>
 
- <p>
 
-   Mas vale destacar que esse recurso só é efetivamente útil se a função interna (<i>funcao3</i>) só fizer sentido dentro da função que a contém.
 
-   Pois em caso contrário, você poderia invocar a função interna em outros contextos.
 
-   Um exemplo dessa situação é ilustrado no parágrafo seguinte, a função <i>fatorial</i> poderia ficar melhor se declarada fora da função <i>combinacao</i>.
 
- </p>
 
- <p>
 
-   Um exemplo simples de função contendo outra função, poderia ser o caso do cálculo da combinação de <i>n</i>, tomados <i>k</i>-a-<i>k</i>:
 
-   <i>C<sub>n,k</sub> = n!/(k!(n-k)!)</i>.
 
-   Como para o calculo de <i>C<sub>n,k</sub></i> é necessário invocar o cálculo do fatorial 3 vezes, podemos desejar fazer um implementação que
 
-   deixe essa dependência clara, definindo uma função de nome <i>combinacao</i> e, dentro dela, declarar a função
 
-   <i>fatorial</i>. Vide exemplo 1.
 
- </p>
 
- <p>
 
-   Porém, como anteriormente comentado, como a função <i>fatorial</i> tem potencial de aplicação mais amplo, ela ficaria melhor se declarada
 
-   <b style="color:#0000aa">fora</b> da função <i>combinacao</i>
 
-   (vide a crítica a esse organização de código logo após o exemplo 1).
 
- </p>
 
- <div class="exemplo"><i>Exemplo 1</i>. Declaração aninhada de funções.
 
- </div><!-- class="exemplo" -->
 
- <div class="codigo"><pre><verm>def</verm> combinacao (n, k) : <cyan># combinacao de n, k-a-k</cyan>
 
-   <verm>def</verm> fatorial (n) : <cyan># fatorial de n (supondo n natural)</cyan>
 
-     fat = 1;
 
-     for i in range(2, n+1) :
 
-       fat *= i;
 
-     return fat;
 
-   return fatorial(n) / (fatorial(k)*fatorial(n-k));
 
- <verm>def</verm> main () :
 
-   n = 5; k = 3;
 
-   <verd>print</verd>("Combinacao %d, %d-a-%d = %d" % (n, k, k, combinacao(n,k)));
 
-   <cyan># Problema de declarar 'fatorial()' dentro de 'combinacao()': a linha abaixo daria erro!</cyan>
 
-   <cyan># Erro: NameError: global name 'fatorial' is not defined</cyan>
 
-   <cyan># <verd>print</verd>("fat(0)=%d, fat(1)=%d, fat(2)=%d, fat(3)=%d" % (fatorial(0), fatorial(1), fatorial(2), fatorial(3)));</cyan>
 
- main();</pre>
 
- </div>
 
- <p> 
 
-   Note que o código acima apresenta a linha comentada
 
-   <tt><verd>print</verd>("fat(0)=%d, fat(1)=%d, fat(2)=%d, fat(3)=%d" % (fatorial(0), fatorial(1), fatorial(2), fatorial(3)));</tt>.
 
-   A razão é que ela resultaria erro, pois a função <i>fatorial</i> foi declarada dentro da função <i>combinacao</i>
 
-   e portanto só pode ser usando (invocada) dentro dessa segunda!
 
- </p>
 
- <p>
 
-   Uma vez que o uso do cálculo de fatorial é muito comum e pensando que o código acima seria parte de um maior,
 
-   então provavelmente o desenho de código usado não é bom, pois implicaria em precisarmos definir outra função <i>fatorial</i>,
 
-   essa fora do contexto da função <i>combinacao</i>.
 
-   Nesse sentido, poderia ser melhor usar o código (pensando que ele seja o início de um sistema maior) do
 
-   exemplo a seguir.
 
- </p>
 
- <div class="exemplo"><i>Exemplo 2</i>. Declaração de funções sem aninhamento.
 
- </div><!-- class="exemplo" -->
 
- <div class="codigo"><pre><verm>def</verm> fatorial (n) : <cyan># fatorial de n (supondo n natural)</cyan>
 
-     fat = 1;
 
-     for i in range(2, n+1) :
 
-       fat *= i;
 
-     return fat;
 
- <verm>def</verm> combinacao (n, k) : <cyan># combinacao de n, k-a-k</cyan>
 
-   return fatorial(n) / (fatorial(k)*fatorial(n-k));
 
- <verm>def</verm> main () :
 
-   n = 5; k = 3;
 
-   <verd>print</verd>("Combinacao %d, %d-a-%d = %d" % (n, k, k, combinacao(n,k)));
 
-   <cyan># Note que agora pode-se invocar 'fatorial()' dentro da 'main'</cyan>
 
-   <verd>print</verd>("fat(0)=%d, fat(1)=%d, fat(2)=%d, fat(3)=%d" % (fatorial(0), fatorial(1), fatorial(2), fatorial(3)));
 
- main();</pre>
 
- </div>
 
- <a name="variaveis">
 
- <p class="subsubsecao">Variáveis globais e locais</p>
 
- </a>  
 
- <p>
 
-   Outro conceito importante relacionado com funções é o de declaração de variáveis.
 
-   Assim, uma variável é <b>local</b> se declarada dentro de uma função qualquer, quer dizer,
 
-   essa variável será "conhecida" (poderá ser usada) apenas dentro dessa função.
 
-   Por exemplo, no <i>exemplo 2</i> acima, a variável <i>fat</i> é conhecida apenas dentro da função
 
-   <i>fatorial</i>, portanto seu uso deve-se restringir a esse contexto.
 
- </p>
 
- <p>
 
-   Por outro lado, pode-se usar o mesmo nome para variáveis que estão em contextos distintos.
 
-   Por exemplo, no código do <i>exemplo 1</i>, se fosse necessário poderíamos usar o nome de variável
 
-   local <i>i</i> dentro da função <i>combinacao</i> e não haveria qualquer colisão com a variável
 
-   <i>i</i> de <i>fatorial</i>.
 
- </p>
 
- <p>
 
-   Entretanto é necessário um critério que elimine <i>ambiguidades</i>, isto é, que seja possível identificar
 
-   unicamente cada uma das variáries. Para isso usa-se o <b>princípio da proximidade</b> (ou da <b>localidade</b>),
 
-   quer dizer, ao usar uma variável considera-se como sua declarção aquela mais próxima.
 
-   Por isso, que poderiamos usar <i>i</i> tanto em <i>combinacao</i>, quanto em <i>fatorial</i>,
 
- </p>
 
- <center>
 
-  <p>
 
-   <img src="img/funcoes_var_locais.png" title="imagem ilustrando principio da localidade para variáveis"/>
 
-   <br/>
 
-   <i>Fig. 1. Princípio da <i>localidade</i> para variáveis: <tt>var2</tt> e <tt>var1</tt> são aquelas declaradas dentro da <tt>funcao2</tt>.</i>
 
-  </p>
 
- </center>
 
- <p>
 
-   Já uma variável <b>global</b> pode ser acessada em qualquer ponto do código.
 
-   Mas por essa mesma razão deve evitada, sendo necessária apenas para casos excepcionais,
 
-   sempre com um nome significativo, que evite qualquer confusão.
 
- </p>
 
- <p>
 
-   Em <i>Python</i> existem dois modos para se declarar uma variável <b>global</b>, ou seja, uma variável
 
-   que pode ser acessada em qualquer ponto do código (em qualquer função).
 
-   Ela pode estar no código "principal"
 
-   (quer dizer não estar dentro de qualquer função) ou sendo declarada dentro de uma função usando
 
-   a diretiva especial <b>global</b>, como ilustrado no próximo exemplo.
 
- </p>
 
- <div class="exemplo"><i>Exemplo 3</i>. Declaração de variável global.
 
- </div><!-- class="exemplo" -->
 
- <div class="codigo"><pre>var_global1 = "essa variavel e' uma global (1)";
 
- <verm>def</verm> funcao1 () :
 
-   <verd>print</verd>("funcao1: var_global1 = %s" % var_global1);
 
- <verm>def</verm> funcao2 () :
 
-   global var_global2; <cyan># define 'var_global2' como global </cyan>
 
-   var_global2 = "essa variavel e' outra global (2)"; <cyan># atribui um primeiro valor a 'var_global2'</cyan>
 
-   <verd>print</verd>("funcao2: var_global1 = %s" % var_global1);
 
-   <verd>print</verd>("funcao2: var_global2 = %s" % var_global2);
 
- <verm>def</verm> main () :
 
-   <verd>print</verd>("main   : var_global1 = %s" % var_global1);
 
-   #Erro: <verd>print</verd>("main   : var_global2 = %s" % var_global2); <cyan># NAO pode usar essa linha pois 'var_global2' ainda NAO foi definida</cyan>
 
-   funcao1();
 
-   funcao2();
 
-   <verd>print</verd>("main   : var_global2 = %s" % var_global2); <cyan># NAO pode usar essa linha pois 'var_global2' ainda NAO foi definida</cyan>
 
- main();</pre>
 
- </div>
 
- <p class="subsubsecao">Aninhando funções e variáveis locais e globais</p>
 
- <p>
 
-   Deve-se notar que é possível aninhar tantas funções quantas forem necessárias e o mesmo para variáveis locais.
 
-   O exemplo abaixo ilustra esses aninhamentos e o princípio da proximidade.
 
-   Examine-o com atenção, copie-o em seu computador, utilizando um interpretador <i>Python</i>
 
-   e altere seu código até que esteja certo de ter assimilado os conceitos.
 
- </p>
 
- <div class="exemplo"><i>Exemplo 4</i>. Declaração de variáveis locais, usando globais e aninhamento de funções.
 
- </div><!-- class="exemplo" -->
 
- <div class="codigo"><pre>glob1 = "glob1: variavel global, conhecida em qualquer local";
 
- <verm>def</verm> funcao1 () :
 
-   loc1 = "loc1: conhecida apenas dentro da funcao 'funcao1'";
 
-   glob1 = "funcao1.glob1: declarada dentro de 'funcao1' => uma variavel local `a funcao 'funcao1'"; <!-- " -->
 
-   <verd>print</verd>("funcao1: loc1 = %s" % loc1); <cyan># note que: pode haver m</cyan>
 
-   <verd>print</verd>("funcao1: glob1 = %s\n" % glob1);
 
- <verm>def</verm> funcao2 (param1) :
 
-   <verm>def</verm> funcao3 () : <cyan># essa funcao so' e' conhecida dentro de 'funcao2'!</cyan>
 
-     loc1 = "loc1: conhecida apenas dentro da funcao 'funcao3' - NAO sou a 'funcao1.loc1' e nem a 'funcao2.loc1'!";
 
-     glob1 = "funcao3.glob1: declarada dentro de 'funcao3' => var. local `a funcao 'funcao3' - NAO e' global 'glob1' e nem 'funcao1.glob1'!";
 
-     <verd>print</verd>("funcao3: loc1 = %s" % loc1); <cyan># note que: e' local com outra com esse nome; "principio do mais proximo" em acao!</cyan>
 
-     <verd>print</verd>("funcao3: loc2 = %s" % loc2); <cyan># note que: e' local `a funcao 'funcao2' - variavel declarada fora de funcao3!</cyan>
 
-     <verd>print</verd>("funcao3: glob1 = %s" % glob1);
 
-   global glob2;
 
-   glob2 = "glob2: variavel global, conhecida em qualquer local (mas declarada em 'funcao2')"; <cyan># mas depois desse comando ser executado!</cyan>
 
-   loc1 = "loc1: conhecida apenas dentro da funcao 'funcao2 - NAO sou a 'funcao1.loc1'!'";
 
-   loc2 = "loc2: conhecida apenas dentro da funcao 'funcao2'";
 
-   <verd>print</verd>("funcao2: param1 = %s" % param1);
 
-   <verd>print</verd>("funcao2: loc1 = %s" % loc1); <cyan># note que: e' local com outra com esse nome; "principio do mais proximo" em acao!</cyan>
 
-   <verd>print</verd>("funcao2: loc2 = %s" % loc2); <cyan># note que: e' local</cyan>
 
-   <verd>print</verd>("funcao2: glob1 = %s" % glob1);
 
-   <verd>print</verd>("funcao2: chama funcao3\n");
 
-   funcao3();
 
-   <verd>print</verd>("funcao2: chama funcao1\n");
 
-   funcao1();
 
- <verm>def</verm> funcao4 () :
 
-   <verd>print</verd>("funcao4: glob2 = %s" % glob2);
 
- <verm>def</verm> main () :
 
-   loc1 = "loc1: conhecida apenas dentro da funcao 'main'";
 
-   <verd>print</verd>("main   : loc1 = %s" % loc1); <cyan># note que: e' local com outra com esse nome; "principio do mais proximo" em acao!</cyan>
 
-   <verd>print</verd>("main   : glob1 = %s" % glob1);
 
-   <cyan># A linha abaixo NAO pode ser usada, pois apesar de glob2 ser declarada como global (usando a diretiva 'global')</cyan>
 
-   <cyan># isso e' feito apenas dentro da funcao 'funcao2', entao ela so' ficara' disponivel apos 'funcao2' ser executada!</cyan>
 
-   <cyan># Se tirar o comentario da linha abaixo, resultaria o erro: NameError: global name 'glob2' is not defined</cyan>
 
-   <cyan># <verd>print</verd>("main   : glob2 = %s" % glob2);</cyan>
 
-   <verd>print</verd>("main   : chama funcao1\n");
 
-   funcao1();
 
-   <verd>print</verd>("main   : chama funcao2\n");
 
-   funcao2("parametro efetivo passado para a funcao 'funcao2'");
 
-   <cyan># Atencao: como a funcao 'funcao3' foi declarada dentro da funcao 'funcao2', entao ela so' pode se invocada em 'funcao2'</cyan>
 
-   <cyan># Por exemplo, a linha abaixo resultaria no erro: NameError: global name 'funcao3' is not defined</cyan>
 
-   <cyan># funcao3();</cyan>
 
-   <cyan># Mas nesse ponto a global 'glob2' ja' foi definida</cyan>
 
-   <verd>print</verd>("main   : glob2 = %s" % glob2);
 
-   <verd>print</verd>("main   : chama funcao4\n");
 
-   funcao4(); <cyan># note que 'funcao4' tambem pode usar a global 'glob2' (declarada dentro da 'funcao2'</cyan>
 
- main();</pre>
 
- </div>
 
- <p>
 
-  <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/09: formato, revisão geral;<br/>
 
- 2020/05/12: versão inicial<br/>
 
- </p>
 
- </div>
 
 
  |