4 Funções
Funções são blocos de código que resolvem tarefas específicas. Pense em função como uma “máquina”: você envia uma entrada, ela processa e devolve uma saída. Elas nos ajudam a organizar programas grandes em partes menores, reutilizáveis e mais fáceis de testar.
4.1 Definindo e invocando funções
Uma função é criada com def, recebe um nome, pode receber parâmetros e pode retornar um valor. Sintaxe:
def nome_da_funcao(parametro):
# bloco da função
return valorExemplos Práticos:
Placa quadrada (quadrado.py): Crie um programa com uma função calcular_area_placa_quadrada que receba o lado de uma placa quadrada e retorne a área dela. No programa principal, defina o lado de três peças (sensor, tampa e base), chame a função para cada uma e exiba as áreas. Considere que as medidas são válidas e positivas.
def calcular_area_placa_quadrada(lado):
return lado * lado
lado_sensor = 0.25
lado_tampa = 0.4
lado_base = 1.2
print(f"Area da placa do sensor: {calcular_area_placa_quadrada(lado_sensor)} m2")
print(f"Area da tampa: {calcular_area_placa_quadrada(lado_tampa)} m2")
print(f"Area da base: {calcular_area_placa_quadrada(lado_base)} m2")Exemplo de execução:
Area da placa do sensor: 0.0625 m2
Area da tampa: 0.16000000000000003 m2
Area da base: 1.44 m2
A palavra def cria uma função. Nas linhas 1 e 2, calcular_area_placa_quadrada é o nome da função, lado é o parâmetro, isto é, a variável que recebe o valor enviado na chamada, e o return devolve o resultado para quem chamou. Definir a função não executa nada: o programa principal começa na linha 3.
Nas linhas 6 a 8, a mesma função é chamada três vezes, cada vez com um argumento diferente. Na linha 6, por exemplo, o parâmetro lado recebe 0.25, a função devolve 0.0625 e esse valor aparece no texto exibido. A função é escrita uma vez e reutilizada sempre que necessário.
Identificação do operador (saudacao_com_nome.py): Crie um programa que leia o nome de um operador e exiba a mensagem “Operador montar_identificacao_operador, que recebe o nome e retorna a frase pronta.
Exemplo de execução:
Digite o nome do operador: Ana
Operador Ana liberado para iniciar a medicao.
O programa separa as três etapas de um programa: a entrada (leitura do nome), o processamento (a função monta a frase) e a saída (exibição da mensagem). A função não lê nem exibe nada; ela recebe o nome e devolve o texto pronto, que fica guardado em mensagem.
O parâmetro nome e a variável nome da linha 3 têm o mesmo nome, mas são variáveis diferentes. Na chamada da linha 4, o valor da variável do programa principal é copiado para o parâmetro da função.
Ordem das chamadas (trace_chamadas.py): Crie um programa, sem entrada do usuário, que simule uma rotina de inspeção.
- A função
iniciar_testeexibe uma mensagem de início e retorna a temperatura fixa 28.5. - A função
avaliar_temperaturarecebe a temperatura, exibe a leitura e retorna “Faixa segura” se ela for menor ou igual a 30 ou “Faixa de alerta” em caso contrário. - O programa principal exibe uma abertura, chama as duas funções em ordem, mostra o resultado da avaliação e encerra a rotina.
Antes de executar, tente prever a saída linha a linha.
def iniciar_teste():
print("Iniciando teste de temperatura...")
return 28.5
def avaliar_temperatura(temperatura):
print(f"Leitura recebida: {temperatura} C")
if temperatura <= 30:
return "Faixa segura"
return "Faixa de alerta"
print("Abrindo rotina de inspecao")
temperatura_medida = iniciar_teste()
status = avaliar_temperatura(temperatura_medida)
print(f"Resultado da avaliacao: {status}")
print("Encerrando rotina")Exemplo de execução:
Abrindo rotina de inspecao
Iniciando teste de temperatura...
Leitura recebida: 28.5 C
Resultado da avaliacao: Faixa segura
Encerrando rotina
A execução começa na linha 9, já que os blocos def apenas definem as funções. Cada chamada desvia a execução para dentro da função, que roda até encontrar um return e devolve o valor para a linha que a chamou. Na linha 10, iniciar_teste() exibe sua mensagem e devolve 28.5, que fica em temperatura_medida. Na linha 11, esse valor é enviado para avaliar_temperatura.
Dentro de avaliar_temperatura, o return da linha 7 encerra a função imediatamente, por isso a linha 8 só executaria para temperaturas acima de 30. Antes de executar o programa, tente prever as cinco linhas da saída e a ordem em que elas aparecem.
4.2 Parâmetros e argumentos
Parâmetros são as variáveis que a função declara. Argumentos são os valores que passamos na chamada. O código da função não muda — só mudam os dados que ela recebe.
Exemplos Práticos:
Área do piso (area_retangulo.py): Crie um programa que leia o comprimento e a largura de um piso retangular em metros (números decimais) e exiba a área. O cálculo deve ficar em uma função calcular_area_piso, que recebe as duas medidas e retorna comprimento * largura. Considere que as medidas são válidas e positivas.
Exemplo de execução:
Digite o comprimento do piso em metros: 5
Digite a largura do piso em metros: 4
Area do piso: 20.0 m2
A função tem dois parâmetros, separados por vírgula. Na chamada da linha 5, os argumentos são associados aos parâmetros pela posição: o primeiro valor vai para comprimento e o segundo vai para largura. O valor devolvido fica em area e é exibido na última linha.
Consumo de energia (teste_argumentos.py): Crie um programa com uma função calcular_consumo_energia que receba a potência de um equipamento em kW e o tempo de uso em horas e retorne o consumo em kWh (potencia * horas). O programa calcula primeiro o consumo de três equipamentos com valores fixos e, em seguida, lê a potência e as horas de um novo equipamento e exibe o consumo estimado. Considere que os valores digitados são válidos e não negativos.
def calcular_consumo_energia(potencia_kw, horas):
return potencia_kw * horas
print(f"Bomba A em 3 h: {calcular_consumo_energia(2.5, 3)} kWh")
print(f"Bomba B em 6 h: {calcular_consumo_energia(4.0, 6)} kWh")
print(f"Ventilador em 8 h: {calcular_consumo_energia(0.8, 8)} kWh")
potencia = float(input("Digite a potencia do equipamento em kW: "))
horas = float(input("Digite o tempo de uso em horas: "))
consumo = calcular_consumo_energia(potencia, horas)
print(f"Consumo estimado: {consumo} kWh")Exemplo de execução:
Bomba A em 3 h: 7.5 kWh
Bomba B em 6 h: 24.0 kWh
Ventilador em 8 h: 6.4 kWh
Digite a potencia do equipamento em kW: 1.5
Digite o tempo de uso em horas: 4
Consumo estimado: 6.0 kWh
A mesma função atende a todas as chamadas do programa. Nas linhas 3 a 5, os argumentos são valores escritos diretamente no código; na linha 8, são as variáveis com os dados lidos do usuário. A função não precisa saber de onde vêm os valores: o código dela é sempre o mesmo, e só mudam os dados que ela recebe a cada chamada.
Lote de sensores (calcular_preco_final.py): Crie um programa que leia a quantidade de sensores de um lote (inteiro), o preço unitário (decimal) e o desconto do fornecedor em porcentagem (decimal, por exemplo 5 para 5%) e exiba o custo final. Uma função calcular_preco_final recebe os três valores, calcula o subtotal, calcula o desconto sobre o subtotal e retorna o subtotal menos o desconto.
def calcular_preco_final(quantidade, preco_unitario, desconto_percentual):
subtotal = quantidade * preco_unitario
desconto = subtotal * (desconto_percentual / 100)
return subtotal - desconto
quantidade = int(input("Quantidade de sensores no lote: "))
preco = float(input("Preco unitario de cada sensor: R$ "))
desconto = float(input("Desconto negociado com o fornecedor (%): "))
total = calcular_preco_final(quantidade, preco, desconto)
print(f"Custo final do lote: R$ {total}")Exemplo de execução:
Quantidade de sensores no lote: 10
Preco unitario de cada sensor: R$ 25
Desconto negociado com o fornecedor (%): 5
Custo final do lote: R$ 237.5
A função agrupa todo o cálculo e recebe os três dados como parâmetros. Ela calcula o subtotal, depois o valor do desconto e devolve a diferença. A divisão por 100 transforma a porcentagem digitada, como 5, na fração 0.05.
As variáveis subtotal e desconto, criadas dentro da função, existem apenas enquanto ela executa. A variável desconto da linha 7 é outra, do programa principal, e guarda a porcentagem digitada. Na linha 8, os três argumentos são passados na mesma ordem dos parâmetros.
4.3 Retorno com return e composição de funções
Quando uma função retorna um valor, podemos usar esse retorno como entrada de outra função. Isso se chama composição: a saída de uma função vira entrada da próxima.
Exemplos Práticos:
Volume do tanque (composicao_simples.py): Crie um programa, sem entrada do usuário, com duas funções: calcular_area_base, que recebe comprimento e largura e retorna a área da base, e calcular_volume_tanque, que recebe a área da base e a altura e retorna o volume. Calcule o volume de um tanque de 3.0 m por 2.0 m com 1.5 m de altura, usando o retorno da primeira função como argumento da segunda.
Exemplo de execução:
Volume do tanque: 9.0 m3
Na linha 5, o resultado de uma função é usado como argumento de outra, o que chamamos de composição. O Python resolve primeiro a chamada interna, calcular_area_base(3.0, 2.0), que devolve 6.0. Esse valor passa a ser o primeiro argumento da chamada externa, que fica equivalente a calcular_volume_tanque(6.0, 1.5) e devolve o volume 9.0.
Volume bombeado (rastreamento_composicao.py): Crie um programa que leia a vazão de uma bomba em litros por minuto (decimal) e exiba o volume bombeado em um turno de 8 horas, em metros cúbicos. Use três funções: calcular_volume_por_hora (multiplica por 60), calcular_volume_por_turno (multiplica por 8) e converter_litros_para_m3 (divide por 1000), compostas em uma única expressão. Considere que a vazão é válida e positiva.
def calcular_volume_por_hora(vazao_litros_minuto):
return vazao_litros_minuto * 60
def calcular_volume_por_turno(volume_hora):
return volume_hora * 8
def converter_litros_para_m3(volume_litros):
return volume_litros / 1000
vazao = float(input("Digite a vazao da bomba em litros por minuto: "))
resultado = converter_litros_para_m3(
calcular_volume_por_turno(calcular_volume_por_hora(vazao))
)
print(f"Volume bombeado em um turno: {resultado} m3")Exemplo de execução:
Digite a vazao da bomba em litros por minuto: 50
Volume bombeado em um turno: 24.0 m3
Cada função faz uma única conversão: de litros por minuto para litros por hora, de hora para um turno de 8 horas e de litros para metros cúbicos. As três são compostas em uma única instrução, dividida em várias linhas apenas para facilitar a leitura.
Para rastrear essa instrução, leia de dentro para fora. Com uma vazão de 50 L/min, a função mais interna devolve 3000 litros por hora, a do meio devolve 24000 litros por turno e a mais externa converte esse volume em 24.0 m³.
Orçamento de materiais (composicao_encadeada.py): Crie um programa, sem entrada do usuário, que calcule o orçamento de 850 kg de material a R$ 6,40 por kg. Use três funções: calcular_subtotal_materiais (massa vezes preço por kg), aplicar_margem_perda (acréscimo de 8%) e formatar_orcamento (devolve a frase pronta para exibição). Componha as três funções em uma única expressão.
def calcular_subtotal_materiais(massa_kg, preco_por_kg):
return massa_kg * preco_por_kg
def aplicar_margem_perda(subtotal):
return subtotal * 1.08
def formatar_orcamento(valor_final):
return f"Orcamento estimado do lote: R$ {valor_final}"
print(formatar_orcamento(aplicar_margem_perda(calcular_subtotal_materiais(850, 6.4))))Exemplo de execução:
Orcamento estimado do lote: R$ 5875.200000000001
Toda a lógica do programa principal está na linha 7, em que cada função recebe o retorno da anterior. A mais interna calcula o subtotal, a do meio acrescenta 8% de perda (multiplicar por 1.08 é o mesmo que somar 8% ao valor) e a mais externa monta o texto final.
A última função devolve um texto, e não um número, por isso o print pode exibir diretamente o resultado da composição. Repare que o valor pode aparecer com muitas casas decimais, como 5875.200000000001, por causa da forma como o computador representa números decimais.
4.4 Decisão e repetição dentro de funções
Funções podem conter if, elif, else e laços. Em vez de espalhar regras no script principal, colocamos a lógica dentro de funções bem nomeadas. O programa principal diz o que fazer; a função diz como fazer.
Exemplos Práticos:
Temperatura do equipamento (classificar_nota.py): Crie um programa que leia a temperatura de um equipamento em °C (decimal) e exiba a classificação retornada por uma função classificar_temperatura: “Operacao normal” se a temperatura for menor ou igual a 80 e “Acima do limite” em caso contrário.
Execução dentro do limite:
Digite a temperatura medida em C: 75.5
Situacao do equipamento: Operacao normal
Execução acima do limite:
Digite a temperatura medida em C: 92
Situacao do equipamento: Acima do limite
A decisão fica dentro da função, e o programa principal apenas lê a temperatura, pede a classificação e exibe o resultado. Como o return encerra a função, o else é dispensável: se a temperatura estiver dentro do limite, a função termina na linha 3; caso contrário, a execução segue até o return da linha 4. Se o limite mudar, só a função precisa ser alterada.
Leituras de vazão (simulacao_acumulador.py): Crie um programa que leia leituras de vazão em L/min (decimais), uma por vez, até o usuário digitar 0, e exiba a soma das leituras válidas. As leituras ficam em uma lista, e uma função somar_leituras_validas percorre essa lista com for e soma apenas os valores maiores que zero.
def somar_leituras_validas(leituras):
soma = 0
for leitura in leituras:
if leitura > 0:
soma += leitura
return soma
leituras = []
leitura = float(input("Digite uma leitura de vazao em L/min (0 para parar): "))
while leitura != 0:
leituras.append(leitura)
leitura = float(input("Digite uma leitura de vazao em L/min (0 para parar): "))
resultado = somar_leituras_validas(leituras)
print(f"Soma das leituras validas: {resultado} L/min")Exemplo de execução:
Digite uma leitura de vazao em L/min (0 para parar): 12.5
Digite uma leitura de vazao em L/min (0 para parar): -3
Digite uma leitura de vazao em L/min (0 para parar): 8
Digite uma leitura de vazao em L/min (0 para parar): 0
Soma das leituras validas: 20.5 L/min
A função recebe uma lista inteira como argumento. Dentro dela, um for percorre as leituras, e um if deixa passar apenas as positivas, que são somadas no acumulador soma. No final, a função devolve o total.
O programa principal monta a lista com um while e leitura antecipada, como no capítulo de laços: lê a primeira leitura, guarda cada uma com append e para quando o usuário digita 0, que não entra na lista. Só então a lista completa é enviada para a função.
Desconto do pedido (decisor_desconto.py): Crie um programa que leia o valor de um pedido de materiais (decimal) e exiba o percentual de desconto, o desconto obtido e o valor final. Uma função definir_percentual_desconto recebe o valor e retorna 0.03 para valores abaixo de 500, 0.06 para valores até 2000 e 0.1 para valores acima de 2000.
def definir_percentual_desconto(valor_compra):
if valor_compra < 500:
return 0.03
if valor_compra <= 2000:
return 0.06
return 0.1
valor_compra = float(input("Digite o valor do pedido de materiais: R$ "))
percentual = definir_percentual_desconto(valor_compra)
valor_desconto = valor_compra * percentual
valor_final = valor_compra - valor_desconto
print(f"Percentual negociado: {percentual * 100}%")
print(f"Desconto obtido: R$ {valor_desconto}")
print(f"Valor final do pedido: R$ {valor_final}")Exemplo de execução:
Digite o valor do pedido de materiais: R$ 1200
Percentual negociado: 6.0%
Desconto obtido: R$ 72.0
Valor final do pedido: R$ 1128.0
Cada faixa de desconto termina em um return, que encerra a função. Por isso, o teste da linha 4 só acontece para valores a partir de 500, já que os menores saíram na linha 3, e a linha 6 só é alcançada por valores acima de 2000.
A função devolve o percentual como fração, por exemplo 0.06. O programa principal usa essa fração para calcular o desconto e o valor final e, na linha 11, multiplica essa fração por 100 para exibir a porcentagem.
4.5 Decomposição de problemas com funções
Decompor significa dividir um problema grande em etapas menores. Cada etapa vira uma função com responsabilidade única.
Na engenharia, fazemos isso o tempo todo: estimar materiais, separar custos e consolidar um orçamento. Em programação, cada etapa pode virar uma função.
Exemplos Práticos:
Laje e viga de borda (decomposicao_retangulo.py): Crie um programa que leia o comprimento e a largura de uma laje em metros (decimais) e exiba a área da laje e o comprimento total da viga de borda. Use uma função calcular_area_laje para a área e uma função calcular_viga_borda para o perímetro.
def calcular_area_laje(comprimento, largura):
return comprimento * largura
def calcular_viga_borda(comprimento, largura):
return 2 * (comprimento + largura)
comprimento = float(input("Comprimento da laje em metros: "))
largura = float(input("Largura da laje em metros: "))
area = calcular_area_laje(comprimento, largura)
perimetro = calcular_viga_borda(comprimento, largura)
print(f"Area da laje: {area} m2")
print(f"Comprimento total da viga de borda: {perimetro} m")Exemplo de execução:
Comprimento da laje em metros: 5
Largura da laje em metros: 4
Area da laje: 20.0 m2
Comprimento total da viga de borda: 18.0 m
Decompor um problema é dividir esse problema em partes menores. Aqui, cada função tem uma única responsabilidade: uma calcula a área da laje, e a outra calcula o perímetro, que é o comprimento da viga de borda. As duas recebem as mesmas medidas, e o programa principal apenas lê os dados, coordena as chamadas e exibe os resultados. Com as funções separadas, cada cálculo pode ser lido, testado e corrigido sem mexer no outro.
Orçamento da tubulação (rastreamento_decomposicao.py): Crie um programa que leia o comprimento de uma tubulação em metros e o preço do tubo por metro (decimais) e exiba o orçamento total. Use três funções: calcular_custo_tubos (comprimento vezes preço), calcular_custo_instalacao (R$ 12,00 por metro) e calcular_orcamento_total, que chama as duas anteriores e retorna a soma.
def calcular_custo_tubos(comprimento_metros, preco_por_metro):
return comprimento_metros * preco_por_metro
def calcular_custo_instalacao(comprimento_metros):
return comprimento_metros * 12
def calcular_orcamento_total(comprimento_metros, preco_por_metro):
tubos = calcular_custo_tubos(comprimento_metros, preco_por_metro)
instalacao = calcular_custo_instalacao(comprimento_metros)
return tubos + instalacao
comprimento = float(input("Comprimento da tubulacao em metros: "))
preco_por_metro = float(input("Preco do tubo por metro: R$ "))
total = calcular_orcamento_total(comprimento, preco_por_metro)
print(f"Orcamento total da tubulacao: R$ {total}")Exemplo de execução:
Comprimento da tubulacao em metros: 10
Preco do tubo por metro: R$ 30
Orcamento total da tubulacao: R$ 420.0
A função calcular_orcamento_total é de nível mais alto: em vez de fazer as contas sozinha, ela chama as outras duas funções e soma os resultados. O programa principal chama apenas essa função e não precisa conhecer os detalhes de cada custo.
Para rastrear a execução com 10 metros a R$ 30,00 por metro, siga as chamadas: calcular_custo_tubos devolve 300.0, calcular_custo_instalacao devolve 120.0, e calcular_orcamento_total devolve a soma, 420.0.
Visita técnica (estimador_orcamento_viagem.py): Crie um programa que estime o custo de uma visita técnica. O programa lê a distância em km, o custo por km, a quantidade de dias (inteiro), o valor da diária e o custo total de alimentação, e exibe o detalhamento do orçamento. Use as funções calcular_combustivel (distância vezes custo por km), calcular_hospedagem (dias vezes diária) e calcular_total (soma das três parcelas).
def calcular_combustivel(distancia_km, custo_por_km):
return distancia_km * custo_por_km
def calcular_hospedagem(dias, diaria):
return dias * diaria
def calcular_total(combustivel, hospedagem, alimentacao):
return combustivel + hospedagem + alimentacao
distancia = float(input("Distancia total da visita tecnica em km: "))
custo_por_km = float(input("Custo estimado por km: R$ "))
dias = int(input("Quantidade de dias da visita: "))
diaria = float(input("Valor da diaria: R$ "))
alimentacao = float(input("Custo total de alimentacao: R$ "))
combustivel = calcular_combustivel(distancia, custo_por_km)
hospedagem = calcular_hospedagem(dias, diaria)
total = calcular_total(combustivel, hospedagem, alimentacao)
print(f"Combustivel: R$ {combustivel}")
print(f"Hospedagem: R$ {hospedagem}")
print(f"Alimentacao: R$ {alimentacao}")
print(f"Total da visita tecnica: R$ {total}")Exemplo de execução:
Distancia total da visita tecnica em km: 300
Custo estimado por km: R$ 0.8
Quantidade de dias da visita: 2
Valor da diaria: R$ 150
Custo total de alimentacao: R$ 120
Combustivel: R$ 240.0
Hospedagem: R$ 300.0
Alimentacao: R$ 120.0
Total da visita tecnica: R$ 660.0
Cada parcela do orçamento (combustível e hospedagem) é calculada por uma função própria, e uma terceira função soma as parcelas. O programa principal guarda cada resultado em uma variável, o que permite usar cada parcela duas vezes: como argumento de calcular_total e no detalhamento exibido ao final.
4.6 Escopo: variável local e variável global
Variáveis criadas dentro da função são locais — só existem durante a execução da função. Variáveis fora da função são globais. Entender escopo evita erros como esperar que uma variável local exista fora da função.
Atenção: Usar o mesmo nome em escopos diferentes pode confundir. A variável local “esconde” a global dentro da função.
Exemplos Práticos:
Escopo local e global (escopo_variaveis.py): Crie um programa, sem entrada do usuário, com uma variável global limite_temperatura igual a 80 e uma função demonstrar_escopo que crie uma variável local com o mesmo nome e valor 65 e a exiba. Depois de chamar a função, exiba o valor da variável global.
Exemplo de execução:
Dentro da funcao: limite usado no teste = 65 C
Fora da funcao: limite configurado no sistema = 80 C
A variável criada na linha 1, fora de qualquer função, é global. Dentro da função, a atribuição da linha 3 não altera essa variável: ela cria uma nova variável local, com o mesmo nome, que existe apenas enquanto a função executa. Por isso a função exibe 65 e, depois que ela termina, a última linha exibe o valor da global, que continua 80.
Escopo do parâmetro (escopo_parametro_local.py): Crie um programa, sem entrada do usuário, com uma variável global pressao igual a 12 e uma função montar_relatorio que receba um parâmetro também chamado pressao e retorne uma mensagem com o valor recebido. O programa exibe a pressão global, chama a função com o valor 18, exibe o retorno e exibe a pressão global de novo.
Exemplo de execução:
Pressao global antes: 12 bar
Leitura analisada: 18 bar
Pressao global depois: 12 bar
Um parâmetro também é uma variável local, criada a cada chamada com o valor do argumento. Na chamada montar_relatorio(18), o parâmetro pressao recebe 18 e, dentro da função, esconde a variável global de mesmo nome. Fora da função, a global continua valendo 12, como mostram as mensagens exibidas antes e depois da chamada.
Três variáveis vazao (escopo_variaveis_avancado.py): Crie um programa, sem entrada do usuário, com uma variável global vazao igual a 120 e duas funções: calcular_vazao_pico, que cria uma variável local vazao igual a 150 e a retorna, e aplicar_reducao, que recebe um parâmetro vazao, subtrai 20 e retorna o resultado. Chame as duas funções (a segunda com 95) e exiba os retornos e a vazão global. Antes de executar, tente prever o que cada print vai exibir.
vazao = 120
def calcular_vazao_pico():
vazao = 150
return vazao
def aplicar_reducao(vazao):
vazao = vazao - 20
return vazao
vazao_pico = calcular_vazao_pico()
vazao_ajustada = aplicar_reducao(95)
print(f"Vazao de pico local: {vazao_pico} L/min")
print(f"Vazao apos reducao: {vazao_ajustada} L/min")
print(f"Vazao base do sistema: {vazao} L/min")Exemplo de execução:
Vazao de pico local: 150 L/min
Vazao apos reducao: 75 L/min
Vazao base do sistema: 120 L/min
O programa tem três variáveis diferentes com o nome vazao: a global, criada na linha 1; a local de calcular_vazao_pico, criada na linha 3; e o parâmetro de aplicar_reducao, que recebe 95 na chamada. Cada função altera apenas a própria variável local e devolve o resultado. Por isso os print exibem 150, 75 e 120, e a variável global nunca é alterada.