6. Funções

6.1. Script [fonc_01]: âmbito das variáveis
O script [fonc_01] mostra exemplos de âmbito das variáveis entre funções:
Resultados
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/fonctions/fonc_01.py
f1[i,j]=[1,10]
f2[i,j]=[2,20]
f3[i,j]=[1,30]
[i,j]=[2,0]
Process finished with exit code 0
Notas:
- O script demonstra a utilização da variável i, declarada como global nas funções f1 e f2. Neste caso, o programa principal e as funções f1 e f2 partilham a mesma variável i.
6.2. Script [fonc_02]: âmbito da variável
O script [fonc_03] baseia-se no script [fonc_02] e mostra como evitar a utilização de variáveis globais:
Comentários:
- linhas 2, 12: em vez de ser declarada global, a variável [i] é passada como parâmetro para as funções f1 e f2;
- linhas 9, 19: as funções f1 e f2 devolvem a variável [i] modificada ao programa principal. O programa principal recupera-a nas linhas 36 e 37;
Resultados
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/fonctions/fonc_02.py
f1[i,j]=[1,10]
f2[i,j]=[2,20]
f3[i,j]=[1,30]
[i,j]=[2,0]
Process finished with exit code 0
6.3. Script [fonc_03]: âmbito das variáveis
O script [fonc_03] demonstra uma peculiaridade das variáveis utilizadas tanto dentro de uma função como no código que a chama, dependendo se a variável é utilizada apenas para leitura dentro da função ou não.
Notas
- linha 34: o código principal define uma variável [i];
- linhas 1–5: a função f1 também utiliza uma variável [i] sem lhe atribuir um valor. Trata-se de uma leitura da variável [i]. Neste caso, a variável [i] utilizada é a do código de chamada, na linha 34;
- linhas 8–18: a função f2 também utiliza uma variável [i], mas atribui-lhe um valor na linha 16. Atribuir um valor à variável [i] em f2 torna automaticamente [i] uma variável local da função [f2]. Esta função, portanto, «oculta» a variável [i] do código de chamada;
- linha 14: a operação de escrita na variável local [i] falhará porque esta não tem valor quando a linha 14 é alcançada. Obtém o seu valor na linha 16. Ocorrerá uma exceção. Por este motivo, a linha 14 foi colocada dentro de um bloco try/catch;
- linhas 21–29: a função f3 faz o mesmo que a função f2, mas define a sua variável local [i] mais cedo;
Resultados
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/fonctions/fonc_03.py
[f1] i=10
[f1] j=20
[main] i=10, j=20
[f2] erreur=local variable 'i' referenced before assignment
[main] i=10
[f3] i=7
[main] i=10
Process finished with exit code 0
6.4. Script [fonc_04]: modo de passagem de parâmetros
O script é o seguinte:
Resultados
Notas:
- Tudo é um objeto em Python. Alguns objetos são chamados de «imutáveis»: não podem ser modificados. É o caso dos números, das cadeias de caracteres e das tuplas. Quando os objetos Python são passados como argumentos para funções, são as suas referências que são passadas, a menos que esses objetos sejam «imutáveis», caso em que é o valor do objeto que é passado;
- As funções f1 (linha 2) e f2 (linha 7) destinam-se a ilustrar a passagem de um parâmetro de saída. Pretendemos que o parâmetro real de uma função seja modificado pela função;
- Linhas 2–3: A função f1 modifica o seu parâmetro formal a. Queremos saber se o parâmetro real também será modificado;
- linhas 14–15: o parâmetro real é x = 1. A linha 2 dos resultados mostra que o parâmetro real não é modificado. Assim, o parâmetro real x e o parâmetro formal a são dois objetos diferentes;
- linhas 8–10: a função f2 modifica os seus parâmetros formais a e b e devolve-os como resultados;
- linhas 17–18: os parâmetros reais (x, y) são passados para f2, e o resultado de f2 é atribuído a (x, y). A linha 3 dos resultados mostra que os parâmetros reais (x, y) foram modificados.
Concluímos que, quando os objetos «imutáveis» são parâmetros de saída, devem fazer parte dos resultados devolvidos pela função.
6.5. Script [fonc_05]: Ordem das funções num script
O script [fonc_05] mostra que uma função não pode ser chamada se não tiver sido encontrada anteriormente no código:
Notas
- A linha 2 causará um erro porque utiliza a função f2, que ainda não foi definida no script;
Resultados
6.6. Script [fonc_06]: Ordem das funções num script
O script [fonc_06] mostra que o que se aplica ao código de chamada não se aplica às funções:
Notas
- linha 3: a função [f2] utiliza a função [f1] definida mais adiante no script. No entanto, isto não causa um erro. Podemos, portanto, concluir que a ordem em que as funções são definidas num script Python não importa;
Resultados
6.7. Script [fonc_07]: Utilização de módulos
O script [fonc_07] demonstra como isolar funções num módulo.

Isolamos funções reutilizáveis num módulo. Em vez de as mover de um script para outro:
- colocamo-las num ficheiro separado que declaramos de uma forma específica;
- os scripts que necessitam dessas funções «importam» o módulo que as contém;
O script [fonctions_module_01] é o seguinte:
Existem várias formas de garantir que as funções no script [fonctions_module_01] possam ser referenciadas por outros scripts. Estes métodos diferem consoante o script seja ou não executado no [PyCharm].
No [PyCharm], os módulos importados são procurados em pastas específicas chamadas [Root Sources]. Existem duas formas de tornar uma pasta uma [Root Source]:

- em [4], a pasta mudou de cor;
Após esta operação, a pasta [funções/módulos] é reconhecida como uma pasta de origem. Pode então escrever num script:
Para importar/utilizar a função f2 definida no módulo [functions_module_01.py].
![]() |
Outro método consiste em utilizar as propriedades do projeto:
- acima, a sequência [1-6] permite que a pasta [shared] seja utilizada como pasta para armazenar módulos a importar;
Por enquanto, não declararemos nenhuma pasta como [Raiz das Fontes] além da raiz do projeto:

Depois de feito isto, podemos escrever o seguinte script [fonc-07]:
- Linha 2: Importamos o objeto [sys] para que possamos usar o seu atributo [path] na linha 5, que fornece o que é conhecido como [Python Path]: uma lista de diretórios que serão pesquisados em busca de módulos importados;
- linha 6: importamos a função f2 do módulo [fonctions_module_01]. Para referir-nos a este módulo, usamos o caminho que vai da raiz do projeto até ao módulo. Com o PyCharm, a raiz do projeto está sempre incluída nas pastas pesquisadas quando se procura um módulo importado num script. Esta pasta faz, portanto, parte do [Python Path] do projeto. É isto que a linha 5 nos permitirá verificar;
- Linha 6: Se tivéssemos de descrever o caminho desde a raiz do projeto até à pasta [fonctions_module_01], escreveríamos [fonctions/shared/fonctions_module_01]. No caminho de um módulo, o / é substituído por um ponto. Escrevemos, portanto, [fonctions.modules.fonctions_module_01];
- Após a linha 6, a função f2 é definida. Utilizamo-la na linha 8;
Resultados
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/fonctions/fonc_07.py
Python path=['C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\fonctions', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\fonctions\\shared', 'C:\\myprograms\\Python38\\python38.zip', 'C:\\myprograms\\Python38\\DLLs', 'C:\\myprograms\\Python38\\lib', 'C:\\myprograms\\Python38', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\venv', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\venv\\lib\\site-packages']
310
Process finished with exit code 0
Acima:
- destacado a verde, podemos ver que a raiz do projeto faz parte do [Python Path];
- destacado a amarelo, podemos ver que a pasta que contém o script executado também faz parte do [Python Path];
- os outros elementos do [Python Path] provêm diretamente da pasta de instalação do Python;
O que acontece quando não usamos o PyCharm para executar [fonc-07]?


- em [1], executamos o script [fonc-07]. Estamos localizados na pasta [functions];
- Em [2], vemos que o diretório de execução faz parte do [Python Path]. É sempre assim. Também podemos ver que o diretório raiz [C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020] não faz parte do [Python Path];
- em [3], o interpretador Python informa que não consegue encontrar o módulo [fonctions];
Para encontrar o módulo importado [fonctions.shared.fonctions_module_01], o interpretador Python procura nas pastas do [Python Path] por uma subpasta chamada [fonctions]. Não consegue encontrá-la em lado nenhum. Isto acontece porque a subpasta [functions] está localizada na pasta [C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020], que não faz parte do [Python Path].
O script [fonc-08] fornece uma possível solução para este problema.
6.8. Script [fonc_08]: Adicionar pastas ao [Python Path]
É possível modificar o [Python Path] programaticamente, conforme mostrado no script [fonc-08]:
Notas
- linha 4: a variável especial [__file__] é o nome do script que está a ser executado. Dependendo do contexto de execução, este nome pode ser absoluto (PyCharm) ou relativo (consola). A função [os.path.abspath] devolve o caminho absoluto do ficheiro cujo nome lhe é passado. A função [os.path.dirname] devolve o caminho absoluto do diretório que contém o ficheiro cujo nome lhe é passado;
- Linha 10: [sys.path] é uma lista que contém os nomes dos diretórios a serem pesquisados quando se procura um módulo. Adicionamos a raiz do projeto definida na linha 4 a esta lista;
- exibimos o [Python Path] antes (linha 8) e depois (linha 12) da modificação;
- linha 15: importamos o módulo [fonctions_module_01], que contém a função f2;
A execução no PyCharm produz os seguintes resultados:
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/fonctions/fonc_08.py
Python path avant=['C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\fonctions', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\fonctions\\shared', 'C:\\myprograms\\Python38\\python38.zip', 'C:\\myprograms\\Python38\\DLLs', 'C:\\myprograms\\Python38\\lib', 'C:\\myprograms\\Python38', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\venv', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\venv\\lib\\site-packages']
Python path après=['C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\fonctions', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\fonctions\\shared', 'C:\\myprograms\\Python38\\python38.zip', 'C:\\myprograms\\Python38\\DLLs', 'C:\\myprograms\\Python38\\lib', 'C:\\myprograms\\Python38', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\venv', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\venv\\lib\\site-packages', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\fonctions/shared']
310
Process finished with exit code 0
- linha 3: vemos que a pasta [shared] aparece duas vezes no [Python Path]. Podemos evitar isso, mas não causa nenhum problema neste caso;
- linha 4: a função f2 foi executada com sucesso;
Agora vamos executar [fonc-08] num terminal:
(venv) C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\fonctions>python fonc_08.py
Python path avant=['C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\fonctions', 'C:\\myprograms\\Python38\\python38.zip', 'C:\\myprograms\\Python38\\DLLs', 'C:\\myprograms\\Python38\\lib', 'C:\\myprograms\\Python38', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\venv', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\venv\\lib\\site-packages']
Python path après=['C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\fonctions', 'C:\\myprograms\\Python38\\python38.zip', 'C:\\myprograms\\Python38\\DLLs', 'C:\\myprograms\\Python38\\lib', 'C:\\myprograms\\Python38', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\venv', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\venv\\lib\\site-packages', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\fonctions/shared']
310
- linha 2: tal como antes, a pasta [shared] não está no [Python Path];
- linha 3: agora está;
- linha 4: a função f2 foi encontrada;
6.9. Script [fonc_09]: declaração dos tipos dos parâmetros
O script [fonc_09] mostra que é possível declarar o tipo dos parâmetros de uma função, bem como o do resultado. No entanto, esta declaração é útil apenas para documentar a função. O interpretador Python não verifica se os parâmetros reais da função são do tipo esperado. Contudo, o PyCharm assinala inconsistências de tipo entre parâmetros reais e formais. Só por esta razão, as declarações de tipo são indispensáveis.
O script é o seguinte:
Notas:
- Linha 5: Declaramos que o parâmetro formal [param] é do tipo [int] e que o tipo de retorno da função também é [int];
- linha 11: o parâmetro real da função [show] é do tipo correto;
- linha 12: o parâmetro real da função [show] não é do tipo correto;
Resultados
- linha 10: o tipo do parâmetro [param] é [str]. Quando esta mensagem aparece, já introduzimos o código da função [show]. O interpretador Python aceitou, portanto, que o parâmetro real da função [show] é do tipo [str];
- A linha 7 do código desencadeia a exceção apresentada nas linhas 4–10 dos resultados;
No entanto, o PyCharm indica que existe um problema:

Em [1], o PyCharm destacou a chamada incorreta.
6.10. Script [fonc_10]: parâmetros nomeados
Para passar parâmetros a uma função, pode utilizar os nomes dos seus parâmetros formais. Neste caso, não é necessário seguir a ordem dos parâmetros formais:
Notas
- linha 2: a função f tem dois parâmetros formais, x e y;
- linha 7: ao chamar a função f, pode utilizar os nomes dos parâmetros formais. Esta prática pode ser útil em pelo menos dois casos:
- a função tem muitos parâmetros, a maioria dos quais com valores por defeito. Ao chamar a função, a técnica descrita acima permite-lhe inicializar apenas os parâmetros para os quais não pretende utilizar o valor por defeito;
- se os parâmetros formais tiverem nomes significativos, então a utilização de parâmetros nomeados na chamada da função melhora a legibilidade do código;
Resultados
6.11. Script [fonc_11]: função recursiva
O script [fonc_11] é um exemplo de uma função recursiva (que se chama a si própria):
Comentários
- linhas 1-9: a função factorial;
- linha 9: a função [fatorial] chama a si própria;
- linhas 5-6: uma função recursiva deve parar sempre que uma condição for satisfeita; caso contrário, temos uma recursão infinita;
Resultados
6.12. Script [fonc_12]: função recursiva
A função [fonc_12] fornece mais detalhes sobre como funciona a recursão:
Comentários
- linha 5: continuamos a concentrar-nos na função fatorial. Adicionamos-lhe o parâmetro [j];
- linha 12: a variável j é incrementada regularmente a cada cálculo do fatorial. Exibimos o seu valor antes (linha 12) e depois (linha 16) da recursão (linha 15);
Resultados
- linhas 2–8: vemos que o valor de [j] aumenta enquanto a recursão continua, até que seja satisfeita a condição em que a recursão pára. A partir desse ponto, o retorno das chamadas à função [fact] ocorre na ordem inversa das chamadas;
- linhas 10–16: estas exibições refletem os retornos sucessivos da chamada factorial. A variável [j] volta ao seu valor inicial de 1;
