Program Arcade Games
With Python And Pygame

Chapter 9: Funções

— Armando Marques Sobrinho

9.1 Introdução a Funções

Video: Porque usar Funções?

Funções são usadas por dois motivos. Primeiro, podem fazer o código fácil de ler e entender. Segundo, elas permitem usar o mesmo código mais de uma vez.

Até o fim desse capítulo, iremos aprender a criar nossas próprias funções de forma que possamos escrever programas e dizer drawSnowman(50,100) que é para desenhar um boneco de neve em que posição da tela quisermos.

Imagine um conjunto de código que controla um carro de brinquedo. Suponha que o programador deseja fazer o carro andar para a frente. Para fazer isso, o programador tem de executar os seguintes comandos:

turnOnMotor()
pauseOneSecond()
turnOffMotor()

Definindo uma função que permita que o programa possa reutilizar esse mesmo código muitas vezes:

def moveForward():
    turnOnMotor()
    pauseOneSecond()
    turnOffMotor()

Por si mesmo, esse código não faz um carro se mover para frente, isto é feito dizendo ao computador como ele se move para frente. Você tem de chamar a função para rodar o código que faz o carro se mover que está dentro da função:

moveForward()

Com uma biblioteca de funções que definem o que o carro pode fazer, um programa final pode parecer com isso:

moveForward()
turnLeft()
moveForward()
moveForward()
turnRight()
moveForward()

Lembre que moveFoward tem três linhas de código. Cada um deses comandos tem múltiplas linhas de código também. Usando funções podemos repetir os comandos sem precisar reescrever todo o código contido nesses comandos, com isso o programa fica bem menor.

Nome de funções devem ser descritivos, de forma que um não programador possa ler uma sequência de código e pegar a idéia do que está acontecendo. Nomes de função seguem as mesmas regras para nomes de variáveis e podem começar com letras minúsculas.

9.2 Parâmetros das Funções

fig.function

Funções podem ter parametros. Eles podem ser usados para incrmentar a flexibilidade de uma função alterando a forma do seu funcionamento baseado nos parâmetros passados com ela. Por exemplo, nossa função chamada moveForward() dirige o robot para frente por um segundo. Mas a função pode ser mudada para passar um parâmetro e especificar quantos segundos queremos mover para frente. Por exemplo, moveForward(3) fará com que se movimento por três segundos e moveForward(6) para mover por seis segundos.

Ajustando a função para o robot, ficaria parecida com isso:

def moveForward(time):
    turnOnMotor()
    for i in range(time):
        pauseOneSecond()
    turnOffMotor()

Aqui está uma função diferente que pode ser executada sem um carro robô. Esta função irá calcular e imprimir o volume de uma esfera:

def volumeSphere(radius):
    pi = 3.141592653589
    volume = (4 / 3) * pi * radius ** 3
    print("The volume is", volume)
Video: Creating a Function
Os valores para os parâmentros são atribuidos quando a função é chamada, não quando ela é definida.

O nome da função é volumeSphere. Os dados que estão sendo passados para a função serão armazenados dentro da variável chamada radius. O resultado será o volume impresso na tela. A variável radius não pega seu valor aqui, os programadores frequentemente se confundem com isso, achando que o valor do paramentro de uma função é atribuido quando a função é definida, e isso está errado. parâmetros tem seus valores atribuidos quando a função é chamada.

Para chamar a função use:

volumeSphere(22)

A variável radius nessa função é criada e incializada com o valor 22. O código de uma função é executado quando atinge a chamada da função.

O que aconteceria s preicsassemos de mais de um valor? Múltiplos parametros podem ser passados para uma função, cada um separado por uma vírgula:

def volumeCylinder(radius, height):
    pi = 3.141592653589
    volume = pi * radius ** 2 * height
    print("The volume is", volume)

Essa função é chamada assim:

volumeCylinder(12, 3)

Parâmetros são ordenados, assim radius irá ter o valor de 12 e height receberá o valor de 3.

Infelizmente, os exemplos dessas funções são limitados. Por que? Se uma pessoa quiser usar a função volumeCylinder para calcular o volume em um Six-Pack, não funcionaria. Ela só imprime o volume de um cilindro. Não é possível usar o resultado da função de volume de um cilindro em uma equação e multiplicar por 6 para obter o volume de um Six-Pack.

Isto pode ser resolvido usando um comando return. Por exemplo:

def volumeCylinder(radius, height):
    pi = 3.141592653589
    volume = pi * radius ** 2 * height
    return volume

Return não é uma função e não se usa com parenteses. Não faça return(volume).

Por causa de return, esta função pode ser usada depois como parte de uma equação para caucular o volume de um six-pack como isto:

sixPackVolume = volumeCylinder(2.5, 5) * 6

O valor é retornado de dentro de volumeCylinder em uma equação e depois multiplicado por seis

Existe uma grande diferença entre uma função que imprime um valor e uma que retorna um valor. Veja no código abaixo e tente você mesmo.

# Funçao que imrime um valor
def sumPrint(a, b):
    result = a + b
    print(result)

# Função que retorna um resultado
def sumReturn(a, b):
    result = a+b
    return result

# Imprime a soma de 4+4
sumPrint(4, 4)

# Insto não imprime nada
sumReturn(4, 4)

# Isto não irá atribuir a xl o valor da soma
# O seu valor será 'None'
x1 = sumPrint(4, 4)

# Isto irá
x2 = sumReturn(4, 4)

9.3 Documentando Funções

Funções no Python tipicamente podem ter um comentário como o primeiro comando no corpo da função. Este comentário é delimitado usando-se aspas e é chamado de docstring. Uma função deve parecer algo tipo:

def volumeCylinder(radius, height):
    """Retorna o volume de um cilindro dado o seu raio e a sua altura."""
    pi = 3.141592653589
    volume = pi * radius ** 2 * height
    return volume
------------------------

a grande coisa sobre o uso de docstrings em funções é que o comentário pode ser usado para ser exibido em um site documentando seu código usando uma ferramenta como a Sphinx. A maioria das línguagens tem ferramentas semelhante que podem ajudar a fazer documentação seu código como uma brisa. Isto pode poupar muito tempo quando você começar a trabalhar em programas maiores.

Video: escopo variável

O uso de funções introduz o conceito de escopo. Escopo aqui no código significa que uma variável está “viva” e pode ser acessada. Por exemplo, veja o código abaixo:

# Define uma simples função
# x equal to 22
def f():
    x = 22

# Chama a função criada
f()
# Isto falha, x somente existe no escopo da função f()
print (x)

a última linha irá gerar um erro, porque x só existe dentro da função f(). A variável é criada quando f() é chamada e a memória que ele usa é liberada assim que terminar de executar o que está dentro de f().

aqui é onde as coisas se complicam.

A regra se torna mais confusa se está acessando variáveis criadas fora do escopo da função f(). No seguinte código, x é criado antes da função f() e portanto, pode ser lido dentro da função f().

# Cria uma varavel x e define seu valor em 44
x = 44

# Define uma função simples que imprime x
def f():
    print(x)

# Chama a função
f()

Variáveis criadas à frente de uma função podem ser lidas dentro da função somente que a função não altera o seu valor. Este código é muito semelhante ao código acima, ele falhará. O computador vai alegar que não Sabe o que é x.

# Cria uma variável x com o valor de 44
x = 44

# Define uma função simples que imprime x
def f():
    x += 1
    print(x)

# Chama a função
f()

Outras línguagens têm regras mais complexas do que o Python para a criação de variáveis. Como o Python é simples e direta ele é uma boa linguagem introdutória.

Funções passam seus valores, criando uma cópia do original. Por exemplo:

# Define uma função simples que imprime x
def f(x):
    x += 1
    print(x)

# Define y
y = 10
# Chama a função
f(y)
# Imprime y e veja que ele não mudou
print(y)

o valor de y não muda, mesmo que a função f() aumente o valor passado para ele. Cada uma das variáveis listadas como um parâmetro em uma função é uma nova variável. O valor dessa variável é copiado de onde ele foi chamado.

Isto é razoavelmente direto no exemplo anterior. O que o tornou confuso foi que, tanto o código que chama a função como a função em si tem variáveis com o mesmo nome. O código a seguir é idêntico ao listado previamente, mas em vez de usar y usa x.

# Define uma função simples que imprime x
def f(x):
    x += 1
    print(x)

# Define x
x = 10
# Chama a função
f(x)
# Imprime x e veja como ele foi mudado
print(x)

A saída é a mesma que a do programa que usa y. Apesar de que, tanto a função quanto o código circunvizinho usam x como nome de variável, existem na verdade duas variáveis diferentes. Há a variável x que existe dentro da função e uma variável diferente x que existe fora da função.

é totalmente possível para uma função chamar outra função. Por exemplo, definimos duas funções como a seguir:

def armOut(whichArm, palmUpOrDown):
	# o codigo vai aqui

def handGrab(hand, arm):
	# o codigo vai aqui

Em seguida, uma outra função pôde ser criada e nela chamamos as outras funções:

def macarena():
	armOut("direita", "baixo")
	armOut("esquerda", "baixo")
	armOut("direita", "em cima")
	armOut("esquerda", "em cima")
	handGrab("direita", "braço esquerdo")
	handGrab ("esquerda", "braço direito")
	# etc
variáveis globais são o puro mal.

Como programas podem se tronar grandes, é importante manter o código organizado e colocando ele em funções.O Python nos permite escrever código com “indentação nível 0.” Como pode ser visto na maioria dos códigos escritos até aqui nesse artigo. O nosso código que está alinhado a esquerda não está contido em funções.

Esta filosofia é como o amontoar suas roupas no meio do seu armário, ou manter todas as suas ferramentas em uma pilha na bancada de trabalho. Só funciona bem quando você não tem muitas coisas. Mesmo quando você não tem muitas coisas ainda é um pouco confuso.

Todo o seu código e todas as variáveis devem ser colocados em funções. Isso vai manter seu código organizado. Também ajudará quando você precisar rastrear um bug no programa. Variáveis criadas no “nível de recuo 0” são chamadas de variáveis globais. Variáveis globais são uma coisa muito ruim. Por que? Porque qualquer pedaço de código em qualquer lugar pode alterar seu valor. Se você tem um programa de 50.000 linhas, cada linha de código pode alterar essa variável global. Se em vez disso você manter a variável em uma função, então só o código que está na função pode alterar essa variável. Assim, se você tem um valor inesperado em uma variável, você só precisa olhar através das linhas de código da função, talvez de umas 50 linhas. Caso contrário, você terá que verificar cada linha de código em todo o seu programa!

Uma maneira melhor de escrever um programa em Python seria seguir esse padrão:

def main():
	print("Olá Mundo.")

main()

Neste caso, todo o código que normalmente teria de ser executado no nível de recuo 0 é colocado dentro da função main. A útima linha do arquivo chama a função main.

, Mas espere! Há um outro problema que precisamos consertar. No capítulo 15, vamos falar sobre como dividir nosso programa em vários arquivos. Podemos usar o comando import para fazer isso nas funções de outros módulos que criamos. Se usamos o comando import neste módulo, o programa irá começar automaticamente executando a função main. Não queremos isso. Queremos que o programa importe isso para controlar depois, quando a função for chamada.

Para corrigir este problema, temos de fazer nosso programa verificar uma variável global definida automaticamente pelo Python. (Eu sei, eu disse variáveis globais são ruins, Não é?) Essa variável é chamada __name__, com dois sublinhados antes e depois dela. Com ela, podemos verificar se esse código está sendo importado ou executado. Se o código está sendo executado, o Python irá automaticamente definir o valor dessa variável para __main__. Usando uma instrução se if nós apenas chamaremos a função main se o código estiver sendo executado. Caso contrário o código irá apenas definir a função main. O código que está sendo importado pode chamar a função Quando desejar.

Isto é como todos os seus códigos em Python devem ser executado:

def main():
	print("Ola Mundo.")

if __name__ == "__main__":
    main()

Uma das razões por que eu amo Python como a primeira línguagem é que não somos obrigados a usar essa complexidade até que precisemos. Outras linguagens, como Java, exigem-no não importando o quão pequeno seu programa seja.

Para facilitar as coisas neste livro o que fazemos é não mostrar nosso exemplos usando esse padrão. Mas após este livro, seus programas provavelmente serão complexos o suficiente, para facilitar a sua vida como programador, Não “Jogue todas as suas roupas em uma pilha”, por assim dizer.

Se você está super entusiasmado sobre programação, tente escrever seus programas desta forma a partir de agora. Embora possa ser um pouco mais difícil começar com um desafio, facilitará ao escrever programas mais adiante. É também uma boa maneira de aprender sobre como gerenciar corretamente seus dados e seu escopo.

Aqui tem um exemplo que mostra um template base em PyGame usando esse padrão:
programarcadegames.com/python_examples/f.php?file=pygame_base_template_proper.py

Usando este modelo não é necessário, se sou o único que ensina esse curso de ensino. Eu sou o único, sem problemas, se durante o primeiro semestre você empilhar as roupas no meio da pista. Fico feliz que você estiver vestido. (Para os neat-freaks, podemos limpar este programa ainda mais, quando chegarmos à o capítulo sobre “classes.”)

9.4 Revisão

9.4.1 Teste de Múltiplas Escolhas

Click here for a multiple-choice quiz.

9.4.2 Repostas Curtas

Click here for the chapter worksheet.

9.4.3 Lab

Click here for the chapter lab.


You are not logged in. Log in here and track your progress.