py_introducao_funcoes.html 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. <!--
  2. Introdução à Programação - 2017 - Prof. Leoônidas de Oliveira Brandão
  3. Introdução ao uso de funções em Python: variáveis locais, globais e aninhamento de funções
  4. LInE (Laboratory of Informatics in Education) - http://www.usp.br/line
  5. IME - USP
  6. Material didático
  7. Pode usar livrevemente este material para fins não comerciais, devendo sempre fazer referência à autoria.
  8. Sugestões/apontamento são bem vindos: leo@ime.usp.br (favor indicar no assunto "material de introducao 'a programacao")
  9. Prof. Leônidas de Oliveira Brandão
  10. http://www.ime.usp.br/~leo
  11. http://line.ime.usp.br
  12. http://www.matemtica.br
  13. -->
  14. <meta http-equiv='Content-Type' content='text/html; charset=UTF-8'>
  15. <meta name='keywords' content='mac0122, material, professores, leonidas de oliveira brandao'>
  16. <link rel='stylesheet' type='text/css' href='css_img_js_conf/all.css'>
  17. <link rel='stylesheet' type='text/css' href='css_img_js_conf/line_introducao_programacao.css'>
  18. <script src="css_img_js_conf/defineLInE.js"></script> <!-- para referencias 'a documentos internos -->
  19. <div class="pagina">
  20. <p class="secao">Introdução ao uso de funções em Python: variáveis locais, globais e aninhamento de funções</p>
  21. <p>
  22. Nesta seção apresento um conceito mais "sutil" de programação, para entendê-lo é essencial que você copie os códigos apresentados,
  23. "cole" em seu editor preferido e os teste até que esteja tudo claro.
  24. Experimente alterar os exemplos e criar outros: grave-os e os <i>rode</i>.
  25. <b style="color:#0000aa">Para prender programação é preciso programar!</b>
  26. </p>
  27. <p class="subsubsecao">Cuidado com a sintaxe de função (erro de recorrência não desejada)</p>
  28. <p>
  29. Um erro que as vezes ocorre é usar de modo equivocado o conceito de <i>devolução</i> do resultado, provocando uma
  30. recorrência infinita.
  31. 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
  32. de memória é reservado, logo, em algum tempo o seu computador
  33. <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
  34. indicando algo como <b style="color:#aa0000;" title="RuntimeError: maximum recursion depth exceeded">recursão excedeu profundidade máxima</b>.
  35. O código abaixo ilustra esse engano, experimente copiá-lo e colá-lo em seu editor preferido e rode-o.
  36. </p>
  37. <p>
  38. <center><div class="codigo"><pre><verm>def</verm> fat (n) :
  39. f = 1; i = 2;
  40. while (i<=n) :
  41. f *= i;
  42. i += 1;
  43. return fat(n); <cyan># Erro aqui! RuntimeError: maximum recursion depth exceeded</cyan>
  44. <verd>print</verd>(fat(5));</pre>
  45. </div><br/>
  46. <i>Cód. 1. Exemplo de engano implicando em recorrência "infinita"</i>.
  47. </center>
  48. </p>
  49. <p>
  50. Para corrigir o engano do código 1, troque a linha de <i>devolução</i> por <tt>return f;</tt>.
  51. Isso eliminará as recorrências.
  52. Por outro lado, é possível implementar uma versão correta e recursiva,
  53. veja este
  54. <a href="#" onclick="trocaPagina('introducao_recursividade.html')" title="examinar texto sobre funções recorrentes">texto sobre recursividade</a>.
  55. </p>
  56. <p class="subsubsecao">Sobre o aninhamento de funções na linguagem <i>Python</i></p>
  57. <p>
  58. Em várias linguagens de programação, <i>Python</i> em particular, é possível declarar função dentro de função (<b>aninhar</b>).
  59. Por exemplo, dentro de uma função de nome <i>funcao2</i>, pode-se declarar outra função de nome <i>funcao3</i>.
  60. O resultado é que, dentro da primeira função, pode-se invocar a segunda, mas em nenhum outro local do código seria possível
  61. invocar esssa função <i>funcao3</i>.
  62. </p>
  63. <p>
  64. 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.
  65. Pois em caso contrário, você poderia invocar a função interna em outros contextos.
  66. 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>.
  67. </p>
  68. <p>
  69. 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>:
  70. <i>C<sub>n,k</sub> = n!/(k!(n-k)!)</i>.
  71. 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
  72. deixe essa dependência clara, definindo uma função de nome <i>combinacao</i> e, dentro dela, declarar a função
  73. <i>fatorial</i>. Vide exemplo 1.
  74. </p>
  75. <p>
  76. Porém, como anteriormente comentado, como a função <i>fatorial</i> tem potencial de aplicação mais amplo, ela ficaria melhor se declarada
  77. <b style="color:#0000aa">fora</b> da função <i>combinacao</i>
  78. (vide a crítica a esse organização de código logo após o exemplo 1).
  79. </p>
  80. <div class="exemplo"><i>Exemplo 1</i>. Declaração aninhada de funções.
  81. </div><!-- class="exemplo" -->
  82. <div class="codigo"><pre><verm>def</verm> combinacao (n, k) : <cyan># combinacao de n, k-a-k</cyan>
  83. <verm>def</verm> fatorial (n) : <cyan># fatorial de n (supondo n natural)</cyan>
  84. fat = 1;
  85. for i in range(2, n+1) :
  86. fat *= i;
  87. return fat;
  88. return fatorial(n) / (fatorial(k)*fatorial(n-k));
  89. <verm>def</verm> main () :
  90. n = 5; k = 3;
  91. <verd>print</verd>("Combinacao %d, %d-a-%d = %d" % (n, k, k, combinacao(n,k)));
  92. <cyan># Problema de declarar 'fatorial()' dentro de 'combinacao()': a linha abaixo daria erro!</cyan>
  93. <cyan># Erro: NameError: global name 'fatorial' is not defined</cyan>
  94. <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>
  95. main();</pre>
  96. </div>
  97. <p>
  98. Note que o código acima apresenta a linha comentada
  99. <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>.
  100. A razão é que ela resultaria erro, pois a função <i>fatorial</i> foi declarada dentro da função <i>combinacao</i>
  101. e portanto só pode ser usando (invocada) dentro dessa segunda!
  102. </p>
  103. <p>
  104. Uma vez que o uso do cálculo de fatorial é muito comum e pensando que o código acima seria parte de um maior,
  105. então provavelmente o desenho de código usado não é bom, pois implicaria em precisarmos definir outra função <i>fatorial</i>,
  106. essa fora do contexto da função <i>combinacao</i>.
  107. Nesse sentido, poderia ser melhor usar o código (pensando que ele seja o início de um sistema maior) do
  108. exemplo a seguir.
  109. </p>
  110. <div class="exemplo"><i>Exemplo 2</i>. Declaração de funções sem aninhamento.
  111. </div><!-- class="exemplo" -->
  112. <div class="codigo"><pre><verm>def</verm> fatorial (n) : <cyan># fatorial de n (supondo n natural)</cyan>
  113. fat = 1;
  114. for i in range(2, n+1) :
  115. fat *= i;
  116. return fat;
  117. <verm>def</verm> combinacao (n, k) : <cyan># combinacao de n, k-a-k</cyan>
  118. return fatorial(n) / (fatorial(k)*fatorial(n-k));
  119. <verm>def</verm> main () :
  120. n = 5; k = 3;
  121. <verd>print</verd>("Combinacao %d, %d-a-%d = %d" % (n, k, k, combinacao(n,k)));
  122. <cyan># Note que agora pode-se invocar 'fatorial()' dentro da 'main'</cyan>
  123. <verd>print</verd>("fat(0)=%d, fat(1)=%d, fat(2)=%d, fat(3)=%d" % (fatorial(0), fatorial(1), fatorial(2), fatorial(3)));
  124. main();</pre>
  125. </div>
  126. <a name="variaveis">
  127. <p class="subsubsecao">Variáveis globais e locais</p>
  128. </a>
  129. <p>
  130. Outro conceito importante relacionado com funções é o de declaração de variáveis.
  131. Assim, uma variável é <b>local</b> se declarada dentro de uma função qualquer, quer dizer,
  132. essa variável será "conhecida" (poderá ser usada) apenas dentro dessa função.
  133. Por exemplo, no <i>exemplo 2</i> acima, a variável <i>fat</i> é conhecida apenas dentro da função
  134. <i>fatorial</i>, portanto seu uso deve-se restringir a esse contexto.
  135. </p>
  136. <p>
  137. Por outro lado, pode-se usar o mesmo nome para variáveis que estão em contextos distintos.
  138. Por exemplo, no código do <i>exemplo 1</i>, se fosse necessário poderíamos usar o nome de variável
  139. local <i>i</i> dentro da função <i>combinacao</i> e não haveria qualquer colisão com a variável
  140. <i>i</i> de <i>fatorial</i>.
  141. </p>
  142. <p>
  143. Entretanto é necessário um critério que elimine <i>ambiguidades</i>, isto é, que seja possível identificar
  144. unicamente cada uma das variáries. Para isso usa-se o <b>princípio da proximidade</b> (ou da <b>localidade</b>),
  145. quer dizer, ao usar uma variável considera-se como sua declarção aquela mais próxima.
  146. Por isso, que poderiamos usar <i>i</i> tanto em <i>combinacao</i>, quanto em <i>fatorial</i>,
  147. </p>
  148. <center>
  149. <p>
  150. <img src="img/funcoes_var_locais.png" title="imagem ilustrando principio da localidade para variáveis"/>
  151. <br/>
  152. <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>
  153. </p>
  154. </center>
  155. <p>
  156. Já uma variável <b>global</b> pode ser acessada em qualquer ponto do código.
  157. Mas por essa mesma razão deve evitada, sendo necessária apenas para casos excepcionais,
  158. sempre com um nome significativo, que evite qualquer confusão.
  159. </p>
  160. <p>
  161. Em <i>Python</i> existem dois modos para se declarar uma variável <b>global</b>, ou seja, uma variável
  162. que pode ser acessada em qualquer ponto do código (em qualquer função).
  163. Ela pode estar no código "principal"
  164. (quer dizer não estar dentro de qualquer função) ou sendo declarada dentro de uma função usando
  165. a diretiva especial <b>global</b>, como ilustrado no próximo exemplo.
  166. </p>
  167. <div class="exemplo"><i>Exemplo 3</i>. Declaração de variável global.
  168. </div><!-- class="exemplo" -->
  169. <div class="codigo"><pre>var_global1 = "essa variavel e' uma global (1)";
  170. <verm>def</verm> funcao1 () :
  171. <verd>print</verd>("funcao1: var_global1 = %s" % var_global1);
  172. <verm>def</verm> funcao2 () :
  173. global var_global2; <cyan># define 'var_global2' como global </cyan>
  174. var_global2 = "essa variavel e' outra global (2)"; <cyan># atribui um primeiro valor a 'var_global2'</cyan>
  175. <verd>print</verd>("funcao2: var_global1 = %s" % var_global1);
  176. <verd>print</verd>("funcao2: var_global2 = %s" % var_global2);
  177. <verm>def</verm> main () :
  178. <verd>print</verd>("main : var_global1 = %s" % var_global1);
  179. #Erro: <verd>print</verd>("main : var_global2 = %s" % var_global2); <cyan># NAO pode usar essa linha pois 'var_global2' ainda NAO foi definida</cyan>
  180. funcao1();
  181. funcao2();
  182. <verd>print</verd>("main : var_global2 = %s" % var_global2); <cyan># NAO pode usar essa linha pois 'var_global2' ainda NAO foi definida</cyan>
  183. main();</pre>
  184. </div>
  185. <p class="subsubsecao">Aninhando funções e variáveis locais e globais</p>
  186. <p>
  187. Deve-se notar que é possível aninhar tantas funções quantas forem necessárias e o mesmo para variáveis locais.
  188. O exemplo abaixo ilustra esses aninhamentos e o princípio da proximidade.
  189. Examine-o com atenção, copie-o em seu computador, utilizando um interpretador <i>Python</i>
  190. e altere seu código até que esteja certo de ter assimilado os conceitos.
  191. </p>
  192. <div class="exemplo"><i>Exemplo 4</i>. Declaração de variáveis locais, usando globais e aninhamento de funções.
  193. </div><!-- class="exemplo" -->
  194. <div class="codigo"><pre>glob1 = "glob1: variavel global, conhecida em qualquer local";
  195. <verm>def</verm> funcao1 () :
  196. loc1 = "loc1: conhecida apenas dentro da funcao 'funcao1'";
  197. glob1 = "funcao1.glob1: declarada dentro de 'funcao1' => uma variavel local `a funcao 'funcao1'"; <!-- " -->
  198. <verd>print</verd>("funcao1: loc1 = %s" % loc1); <cyan># note que: pode haver m</cyan>
  199. <verd>print</verd>("funcao1: glob1 = %s\n" % glob1);
  200. <verm>def</verm> funcao2 (param1) :
  201. <verm>def</verm> funcao3 () : <cyan># essa funcao so' e' conhecida dentro de 'funcao2'!</cyan>
  202. loc1 = "loc1: conhecida apenas dentro da funcao 'funcao3' - NAO sou a 'funcao1.loc1' e nem a 'funcao2.loc1'!";
  203. glob1 = "funcao3.glob1: declarada dentro de 'funcao3' => var. local `a funcao 'funcao3' - NAO e' global 'glob1' e nem 'funcao1.glob1'!";
  204. <verd>print</verd>("funcao3: loc1 = %s" % loc1); <cyan># note que: e' local com outra com esse nome; "principio do mais proximo" em acao!</cyan>
  205. <verd>print</verd>("funcao3: loc2 = %s" % loc2); <cyan># note que: e' local `a funcao 'funcao2' - variavel declarada fora de funcao3!</cyan>
  206. <verd>print</verd>("funcao3: glob1 = %s" % glob1);
  207. global glob2;
  208. glob2 = "glob2: variavel global, conhecida em qualquer local (mas declarada em 'funcao2')"; <cyan># mas depois desse comando ser executado!</cyan>
  209. loc1 = "loc1: conhecida apenas dentro da funcao 'funcao2 - NAO sou a 'funcao1.loc1'!'";
  210. loc2 = "loc2: conhecida apenas dentro da funcao 'funcao2'";
  211. <verd>print</verd>("funcao2: param1 = %s" % param1);
  212. <verd>print</verd>("funcao2: loc1 = %s" % loc1); <cyan># note que: e' local com outra com esse nome; "principio do mais proximo" em acao!</cyan>
  213. <verd>print</verd>("funcao2: loc2 = %s" % loc2); <cyan># note que: e' local</cyan>
  214. <verd>print</verd>("funcao2: glob1 = %s" % glob1);
  215. <verd>print</verd>("funcao2: chama funcao3\n");
  216. funcao3();
  217. <verd>print</verd>("funcao2: chama funcao1\n");
  218. funcao1();
  219. <verm>def</verm> funcao4 () :
  220. <verd>print</verd>("funcao4: glob2 = %s" % glob2);
  221. <verm>def</verm> main () :
  222. loc1 = "loc1: conhecida apenas dentro da funcao 'main'";
  223. <verd>print</verd>("main : loc1 = %s" % loc1); <cyan># note que: e' local com outra com esse nome; "principio do mais proximo" em acao!</cyan>
  224. <verd>print</verd>("main : glob1 = %s" % glob1);
  225. <cyan># A linha abaixo NAO pode ser usada, pois apesar de glob2 ser declarada como global (usando a diretiva 'global')</cyan>
  226. <cyan># isso e' feito apenas dentro da funcao 'funcao2', entao ela so' ficara' disponivel apos 'funcao2' ser executada!</cyan>
  227. <cyan># Se tirar o comentario da linha abaixo, resultaria o erro: NameError: global name 'glob2' is not defined</cyan>
  228. <cyan># <verd>print</verd>("main : glob2 = %s" % glob2);</cyan>
  229. <verd>print</verd>("main : chama funcao1\n");
  230. funcao1();
  231. <verd>print</verd>("main : chama funcao2\n");
  232. funcao2("parametro efetivo passado para a funcao 'funcao2'");
  233. <cyan># Atencao: como a funcao 'funcao3' foi declarada dentro da funcao 'funcao2', entao ela so' pode se invocada em 'funcao2'</cyan>
  234. <cyan># Por exemplo, a linha abaixo resultaria no erro: NameError: global name 'funcao3' is not defined</cyan>
  235. <cyan># funcao3();</cyan>
  236. <cyan># Mas nesse ponto a global 'glob2' ja' foi definida</cyan>
  237. <verd>print</verd>("main : glob2 = %s" % glob2);
  238. <verd>print</verd>("main : chama funcao4\n");
  239. funcao4(); <cyan># note que 'funcao4' tambem pode usar a global 'glob2' (declarada dentro da 'funcao2'</cyan>
  240. main();</pre>
  241. </div>
  242. <p>
  243. <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/>
  244. <a href="http://www.ime.usp.br/~leo" target="_blank" title="seguir para a página do LInE">http://line.ime.usp.br</a>
  245. </p>
  246. <p class="rodape">
  247. <b>Alterações</b>:<br/>
  248. 2020/08/09: formato, revisão geral;<br/>
  249. 2020/05/12: versão inicial<br/>
  250. </p>
  251. </div>