Python 3 – Estruturas de controle
- Python 1 – Uma introdução ao Python
- Python 2 – Tipos no Python
- Python 3 – Estruturas de controle
Índice
- 1. Sumário
- 2. 3.1. Um programa em Python
- 2.1. 3.1.1 Encoding…
- 3. 3.2. Estrutura if
- 4. 3.3. Estrutura for
- 4.1. 3.3.1. List Comprehension
- 4.2. 3.3.2. Generator Expression
- 5. 3.4. Estrutura while
- 6. 3.5. Funções e Procedimentos
- 6.1. 3.5.1. Passando elementos de uma lista/dicionário
- 6.2. 3.5.2. Escopo de função
- 6.3. 3.5.3. Função sum
- 6.4. 3.5.4. Função lambda
- 6.5. 3.5.5. Função map
- 6.6. 3.5.6. Função filter
- 6.7. 3.5.7. Função reduce
- 6.8. 3.5.8. Função zip
- 7. 3.6. Conclusão
Neste terceiro artigo, vou apresentar as estruturas de controle de fluxo de programa, como if, while, for e funções. Para a apresentação neste texto, setá necessário a construção de alguns pequenos programas ou módulos, por isto, neste artigo ainda será apresentado como criar um programa em Python.
Sumário
- 3.1. Um programa em Python
- 3.2. Estrutura if
- 3.3. Estrutura for
- 3.4. Estrutura while
- 3.5. Funções e Procedimentos
- 3.6. Conclusão
3.1. Um programa em Python
Um programa em Python, consiste de uma sequência de comandos, dispostos em um arquivo texto. Para construir seu primeiro programa, escolha um editor de arquivo texto como o vim, nano, mcedit ou algum editor gráfico como kwrite, kate, gvim, ou outro de sua preferência.
Em seguida inicie o arquivo prog-01.py, no seu editor e coloque as linhas abaixo:
# Primeiro programa
print 'Eu apenas imprimo esta linha...'
Após salvar o arquivo, você pode executá-lo, passando-o como argumento para o interpretador, como na linha de comando abaixo:
python prog-01.py Eu apenas imprimo esta linha...
Uma segunda forma, mais elegante, de fazer isto, é declarar no próprio programa o interpretador Python. Isto é feito adicionado uma chamada ao comando env, do sistema e passando o interpretador python como argumento, em uma linha de comentário especial, no início do programa. Esta linha é iniciada por uma tralha, seguida de um ponto de exclamação, ‘#!‘, como abaixo:
#!/bin/env python
# Primeiro programa
print 'Eu apenas imprimo esta linha...'
Neste caso, não é mais necessário a extensão ‘.py’ no nome do programa. Em seguida, modifique a permissão do arquivo para executável e o execute:
mv prog-01.py prog-01 [prompt]chmod +x prog-01 [prompt]./prog-01 Eu apenas imprimo esta linha...
O interpretador Pyhton também pode ser chamando diretamente na linha #!, como no código abaixo:
#!/usr/bin/python
# Primeiro programa
print 'Eu apenas imprimo esta linha...'
Isto não é aconselhado, pois embora o caminho do interpretador Python geralmente se encontra em /usr/bin/python, não existe uma padronização para isto, o que não acontece com o comando do sistema env, que sempre será encontrado em /bin/env.
3.1.1 Encoding…
Se tentar colocar alguns caracteres acentuados em seu código, irá se deparar com uma limitação do Python 2.6 e anteriores. Experimente executar o código do programa poema, abaixo:
#!/bin/env python
# O Poeta
print 'O Bicho\n\
\n\
Vi ontem um bicho\n\
Na imundície do pátio\n\
Catando comida entre os detritos.\n\
\n\
Quando achava alguma coisa,\n\
Não examinava nem cheirava:\n\
Engolia com voracidade.\n\
\n\
O bicho não era um cão,\n\
Não era um gato,\n\
Não era um rato.\n\
\n\
O bicho, meu Deus, era um homem.\n\
\n\
"Manuel Bandeira"'
chmod +x poema [prompt]./poema File "./poema", line 6 SyntaxError: Non-ASCII character '\xed' in file ./poema on line 7, but no encoding declared; see http://www.python.org/peps/pep -0263.html for details
Este erro acontece por conta do ‘í’ de ‘imundície’, encontrado na linha 6 do poema ‘O Bicho’ de Manuel Bandeira, que não é um caractere da tabela ASCII. O problema pode ser resolvido passando o enconding com na linha abaixo:
# -*- coding: iso-8859-1 -*-
geralmente reconhecido por todos os editores de texto, ou na forma resumida:
# coding: iso-8859-1
Para ambos o resultado será o mesmo. O código do poema ficara como segue abaixo:
#!/bin/env python
# -*- coding: iso-8859-1 -*-
# O Poeta
print 'O Bicho\n\
\n\
Vi ontem um bicho\n\
Na imundície do pátio\n\
...
Desta vez o poema será apresentado sem problemas:
./poema O Bicho Vi ontem um bicho Na imundície do pátio Catando comida entre os detritos. Quando achava alguma coisa, Não examinava nem cheirava: Engolia com voracidade. O bicho não era um cão, Não era um gato, Não era um rato. O bicho, meu Deus, era um homem. "Manuel Bandeira"
A versão 3 do Python não usa mais a tabela ASCII como padrão, dando lugar para as tabelas Unicode. Não testei o Python 3 ainda, mas acho que ele deve usar a localização padrão do sistema, geralmente declarada na variável do sistema LANG,
echo $LANG pt_BR.ISO8859-1
3.2. Estrutura if
E estrutura do if do Python não é muito diferente ao if de outras linguagens de programação, exceto pela ausência de delimitador de bloco de comandos, que no Python é feita pela indentação do texto. Sua sintaxe é apresentada abaixo:
if <condição 1>:
<comandos>
elif <condição 2>:
<comandos>
elif <condição 3>:
...
else:
<comandos>
Os elif (contração else + if) e o else são opcionais na estrutura do if. As condicionais foram apresentadas na seção 2.7.1. Booleanos e condicionais.
Segue abaixo um pequeno programa para fazer uma simples checagem da paridade de um número:
#!/bin/env python
# -*- coding: iso-8859-1 -*-
# Verifica se um número é par ou impar
#
n = input("Entre com um inteiro: ")
if type(n) == int:
if (n % 2) == 0:
print '%d é um par' % n
else:
print '%d é impar' % n
else:
print 'Este número (%s) não é um inteiro!' % n
O comando input, introduzido no código acima, permite a entrada apenas de valores numéricos. Para a entrada de strings, deve-se usar o raw_input, que possui uma sintaxe semelhante ao input.
3.3. Estrutura for
A estrutura de laço for segue a mesma ideia do for do bash, com a adição da sentença else. No laço for, a variável do laço alterna seu conteúdo com os valores da lista passada e caso nenhum break seja encontrado, até que o último elemento da lista seja processado, os comandos da sentença else serão executados. Sua sintaxe segue a forma abaixo:
for <variável> in <lista ou tupla de valores>:
<comandos>
...
break
...
continue
else:
<comandos>
O break, continue e o else são opcionais. O break e o continue podem aparecer em qualquer nível de indentação, dentro do laço for. Ao alcançar um break, o laço irá terminar imediatamente, enquanto que um continue irá iniciar, imediatamente, a próxima interação do laço for.
Abaixo segue alguns exemplos de laços for, executados no interpretador Python:
>>> semana = ['dom', 'seg', 'ter', 'qua', 'qui', 'sex', 'sab']
>>> for s in semana:
... print s,
...
dom seg ter qua qui sex sab
>>> for d in range(30):
... if (d+1) % 7 == 0:
... print '%4s' % (d+1)
... else:
... print '%4s' % (d+1),
...
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
A função range(i[, j]) é muito útil para gerar listas com uma progressão numéricas no intervalo de i a j-1. Se j for omitido a lista gerada será de zero a i-1. Alguns exemplos abaixo podem ajudar a elucidar o funcionamento desta função.
>>> range(10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> range(5, 12)
[5, 6, 7, 8, 9, 10, 11]
Para terminar a apresentação do for, um clássico algorítimo para imprime os primos no intervalo de 1 a n, com o emprego do break e else:
#!/bin/env python
# -*- coding: iso-8859-1 -*-
# primo1.py: imprime os primos
print 'Imprime os números primos de 1 até n.\n'
# Entra com o limite:
n = input('Entre com o limite superior para o primo: ')
print '\nSão primos:'
print 1,
for i in range(2, n):
for j in range(2, i):
if i % j == 0:
break
else:
print i,
O break é empregado para interromper o for interno, a cada vez que o resto da divisão do número testado é nulo, que indica ter encontrado um divisor.
3.3.1. List Comprehension
List Comprehension é uma forma curta de se criar uma lista a partir de um laço for embutido. Sua sintaxe é apresentada a seguir:
[ expressão_com_var for var in lista_de_valores if <condicional> ]
O if é opcional. Os dois exemplos a segui geram uma lista de múltiplos de 4:
>>> [ 4*x for x in range(1,11)]
[4, 8, 12, 16, 20, 24, 28, 32, 36, 40]
>>> [ x for x in range(1,41) if x % 4 == 0 ]
[4, 8, 12, 16, 20, 24, 28, 32, 36, 40]
Vários List Comprehension podem ser associados em uma única lista:
>>> [ '%d%d' % (x, y) for x in range(2) for y in range(2)]
['00', '01', '10', '11']
3.3.2. Generator Expression
Generator Expression são similares a List Comprehension, com um diferença fundamental, ele retorna um iterador a uma tupla e não uma lista.
( expressão_com_var for var in lista_de_valores if <condicional> )
>>> b = ( '%d%d' % (x, y) for x in range(2) for y in range(2))
>>> for i in b: print i
...
00
01
10
11
>>> b
<generator object <genexpr> at 0x7fece5bb8690>
Uma grande vantagem de Generator Expression com relação a List Comprehension é o uso de recursos, já que estas primeiras utilizam estruturas mais simples, próprias para o uso em laços e acessos sequências, um iterador.
3.4. Estrutura while
O laço while é empregado quanto se deseja realizar um teste a cada interação do laço. O while também suporta as sentenças break, continue e else, como no laço for. Sua sintaxe é apresentada a seguir:
while <contição>:
<comandos>
...
break
...
continue
else:
<comandos>
O código a seguir retorna os primos no intervalo de 1 a n, usando uma técnica difere da apresentada no exemplo anterior.
#!/bin/env python
# -*- coding: iso-8859-1 -*-
# primo2.py: imprime os primos
from math import sqrt
print 'Imprime os números primos de 1 até n.\n'
# Entra com o limite:
n = input('Entre com o limite superior para o primo: ')
print '\nSão primos:'
a = range(n+1)
r = int(sqrt(n))
for i in range(2, r):
if a[i] == 0:
continue
j = i+i
while j <= n:
a[j] = 0
j += i
for i in range(n+1):
if a[i] != 0:
print i,
A ideia consiste em remover os múltiplos dos primos, de uma lista com todos os números até o último valor passado para se determinar o número primo. A linha 4 apenas carrega a função sqrt, raiz quadrada, do módulo math.
Embora seja bem mais dispendioso no consumo de memória que o código anterior, este último código consegue gerar os primos até 10.000, oitenta vezes mais rápido que o anterior.
time python primos1.py > /dev/null real 0m8.193s user 0m8.119s sys 0m0.051s [prompt]time python primos2.py > /dev/null real 0m0.109s user 0m0.093s sys 0m0.013s
Para este teste, substitua a linha 7, em primo1.py, e a linha 9, em primo2.py, por
n = 10000
3.5. Funções e Procedimentos
Funções e procedimentos são muito similares, sendo a única diferença entre eles o fato de que uma função deve retornar algum valor, enquanto um procedimento pode alterar o valor de uma, ou algumas, das variáveis passadas, editar um banco de dados, uma imagem, um arquivo, imprimir uma mensagem, … Para o Python uma função ou um procedimento será tratada pelo interpretador da mesma forma, sendo a diferença puramente conceitual, com uma função terminada por um comando return. Sua sintaxe é apresentada abaixo:
def nome_função([arg_1 [= valor_1[, arg_2 [= valor_2, ...]]]]):
global <variáveis>
<comandos>
[return valor]
A sentença global é necessária quando se deseja que valores das variáveis locais sejam repassadas para as variáveis globais, ou seja, transcende o escopo do procedimento.
Como exemplo, abaixo é definido uma função para retornar verdadeiro se um número passado for par.
>>> def iseven(n = 0):
... """ iseven(n): This function return True if the argument n is even """
... return n % 2 == 0
...
>>> iseven(12)
True
>>> iseven(13)
False
>>> iseven()
True
>>> print iseven.__doc__
iseven(n): This function return True if the argument n is even
A string entre as três aspas duplas, no início da função é chamada de docstring. Como seu nome já diz, são strings de documentação, utilizadas para documentar funções, procedimentos, classes e módulos. Estas strings também podem ser usadas na construção de documentação de seus programas, módulos ou bibliotecas. Docstrings não são obrigatórias, mas o seu uso é uma prática muito encorajada no Python.
A função iseven possui um argumento n, com valor padrão 0 e por isto a função aceita uma chamada sem argumento algum.
A próxima função gera a série de Fibonacci, com valor padrão 10:
>>> def fibonacci(n = 10):
... """ fibonacci(n): Generate the Fibonacci series """
... s = []
... a, b = 0, 1
... while b < n:
... s.append(b)
... a, b = b, a+b
... return s
...
>>> fibonacci()
[1, 1, 2, 3, 5, 8]
>>> fibonacci(50)
[1, 1, 2, 3, 5, 8, 13, 21, 34]
Para mostrar a flexibilidade na entrada de argumentos em uma função, a seguir é apresentado uma função para retorna as raízes reais de um polinômio de segundo grau, onde são requerido até três argumentos na entrada.
>>> from math import sqrt as raiz
>>> def seggrau(a = 0., b = 0., c = 0.):
... """ seggrau(a, b, c): Retorna as raízes reais do polinômio ax²+bx+c """
... if a == 0.:
... print "Não e um polinômio de 2o. a deve ser != 0."
... return None
... delta = b**2 - 4*a*c
... if delta < 0.:
... print "Este polinômio não possui raízes reais"
... return None
... a2 = 2. * a
... return [(-b + raiz(delta))/a2, (-b - raiz(delta))/a2]
...
>>> seggrau()
Não e um polinômio de 2o. a deve ser != 0.
>>> seggrau(1, 2, 3)
Este polinômio não possui raízes reais
>>> seggrau(1, 5, 3)
[-0.69722436226800544, -4.3027756377319948]
>>> seggrau(2, c = -5)
[1.5811388300841898, -1.5811388300841898]
A primeira linha utiliza novamente o comando import para carrega a função sqrt, do módulo math, aqui, renomeada como raiz. A função seggrau< \em> retorna nada (None), sempre que ocorre um erro.
A última entrada “seggrau(2, c = -5)“, são passados apenas as variáveis a e c ao polinômio, deixando o b com o valor padrão, 0. O mesmo resultado pode ser alcançado, iniciando a função com “seggrau(c = -5, a = 2)”
3.5.1. Passando elementos de uma lista/dicionário
Uma função/procedimento também pode receber elementos de um lista, ou dicionário, de tamanho indeterminado, como argumento. Isto é feito usando o operador “*” à frente do nome da lista, como no exemplo a seguir:
>>> def imprime_lista(*lista):
... for valor in lista:
... print valor
...
>>> imprime_lista(1,2,3,4,'alberto',12.3)
1
2
3
4
alberto
12.3
Elementos de um dicionário são passados de forma semelhante, usando o operador “**”, à frente do nome do dicionário. O exemplo a seguir ilustra isto:
>>> def imprime_dic(**dicionario):
... keys = dicionario.keys()
... keys.sort()
... for k in keys:
... print 'dic[%s]: %s' % (k, dicionario[k])
...
>>> imprime_dic(nome = 'alberto', idade = 42, sexo = 'M')
dic[idade]: 42
dic[nome]: alberto
dic[sexo]: M
Para terminar estas entradas múltiplas, o próximo procedimento, imprime uma lista e um dicionário, passados por argumento:
>>> def imprime_all(*lista, **dicionario):
... print 'Esta é a lista passada:'
... for l in lista:
... print l,
... print '\n\nEste é o dicionário passado:'
... keys = dicionario.keys()
... keys.sort()
... for k in keys:
... print 'dic[%s]: %s' % (k, dicionario[k])
...
>>> imprime_all(3,0,12.5,'alberto', nome = 'alberto', idade = 42, sexo = 'M')
Esta é a lista passada:
3 0 12.5 alberto
Este é o dicionário passado:
dic[idade]: 42
dic[nome]: alberto
dic[sexo]: M
Os argumentos também podem ser passados pela lista e pelo dicionário diretamente ao procedimento como abaixo:
>>> l = [3,0,12.5,'alberto']
>>> d = {'idade': 42, 'sexo': 'M', 'nome': 'alberto'}
>>> imprime_all(*l, **d)
Esta é a lista passada:
3 0 12.5 alberto
Este é o dicionário passado:
dic[idade]: 42
dic[nome]: alberto
dic[sexo]: M
3.5.2. Escopo de função
Variáveis definidas ou alteradas de dentro de uma função, são locais, não afetando seu valor ou definição globalmente. Observe as linhas abaixo:
>>> y = 5
>>> def print_z():
... z = 12
... print 'z = %s z + y = %s' % (z, z + y)
...
>>> print_z()
z = 12 z + y = 17
>>> z
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'z' is not defined
Nas linhas acima a variável z não está definido goblalmente, o que gera o último erro (NameError: name ‘z’ is not defined). Ao executar o função print_z(), z é definida com o valor 12, apenas no escopo da função, enquanto y tem o valor definido no escopo global. Para alterar o valor de y, ele terá que ser definido localmente, dentro da função.
>>> def print_yz():
... z = 12
... y = 10
... print 'z = %s y = %s' % (z, y)
...
>>> print_yz()
z = 12 y = 10
>>> y
5
No entanto, isto não altera o valor da variável y globalmente. Para alterar o valor de uma variável global, deve se definir esta variável com a sentença global, antes de utilizá-la.
>>> def swap_ab():
... global a, b
... a, b = b, a
...
>>> a = 5
>>> b = 12
>>> print a, b
5 12
>>> swap_ab()
>>> print a, b
12 5
>>> swap_ab()
Observe que a função swap abaixo não funcionaria como desejado:
>>> def swap(a,b):
... a, b = b, a
...
>>> x, y = 5, 9
>>> x, y
(5, 9)
>>> swap(x,y)
>>> x, y
(5, 9)
Embora a substituição ocorra no escopo da função swap, ela não é repassada para as variáveis x e y. O uso da sentença global poderia resolver, em parte, o problema, mas engessaria a função a argumento específicos, como na função swap_ap, apresentada acima.
Moral da história é que no caso de se desejar alterar o valor de uma variável, é mais aconselhável utilizar uma função, deixando a sentença global para ocasiões específicas, onde seja necessário a escrita em alguma variável, verdadeiramente global.
3.5.3. Função sum
Uma outra função bem prática do Python e a função sum, que soma todos os elementos de uma lista ou tupla.
>>> a = [1,2,3,4,5]
>>> sum(a)
15
>>> a = (1,2,3,4,5)
>>> sum(a)
15
3.5.4. Função lambda
Com a adição das funções lambda, map, filter, reduce e zip, o Python passou a incorporar algumas características de programação funcional, encontradas no List. Um pouco destas funções especiais é apresentado a seguir.
A primeira delas, Lambda, é usada para criar pequenas funções anônimas, compostas apenas por expressões. Sua sintaxe é apresentada abaixo:
lambda <lista de variáveis>: <expressão>
Por exemplo, a função delta na função segrau poderia ser definida como a função lambda, como segue:
>>> delta = lambda a, b, c: b**2-4*a*c
>>> delta(1,2,3)
-8
>>> delta(1,5,3)
13
Mais algumas funções simples:
>>> from math import sqrt
>>> module = lambda x, y, z: sqrt(x*x + y*y + z*z)
>>> module(1,2,4)
4.5825756949558398
>>> module(2,2,2)
3.4641016151377544
3.5.5. Função map
A próxima função map, é empregada para aplicar uma função a todos os elementos de uma lista. Sua sintaxe é apresenta na linha abaixo:
map(<função>, lista/tupla)
A função tanto pode ser definida da forma convencional, ou por uma declaração lambda. O retorno é uma lista com todos os elementos mapeados, segundo a função passada.
>>> a = [1,2,3,4,5]
>>> map(lambda x: x**2, a)
[1, 4, 9, 16, 25]
>>> def x2(x):
... return x**2
...
>>> map(x2, a)
[1, 4, 9, 16, 25]
3.5.6. Função filter
A próxima função procedural, filter, filtra os dados de uma lista e retorna uma lista com apenas os dados filtrados. Sua sintaxe é apresentada a seguir:
filter(<função filtro>, lista/tupla)
A filtragem a seguir retorna os múltiplos de 5:
>>> a = range(1, 51)
>>> filter(lambda x: not x % 5, a)
[5, 10, 15, 20, 25, 30, 35, 40, 45, 50]
Observe que para o Python, qualquer valor diferente de zero é considerado verdadeiro. Por isto a ausência do not, na linha acima, resultaria em todos os números não múltiplos de 5.
3.5.7. Função reduce
A função reduce aplica, recursivamente, um operação a um sequência de números. Sua sintaxe é apresentada a seguir:
reduce(<função de redução>, lista/tupla)
Segue alguns exemplos a seguir:
>>> a = range(1, 6)
>>> reduce(lambda x, y: x + y, a)
15
>>> reduce(lambda x, y: x * y, a)
120
Evidente que para uma soma é mais conveniente utilizar a função sum, mas a intenção é apenas demonstrar o uso da função reduce.
3.5.8. Função zip
A função zip faz uma transposição dos elementos de duas, ou mais, listas, mesclando os seus valores. Sua sintaxe é apresentada a seguir.
zip(lista/tupla, lista/tupla, ...)
Segue um exemplo para reconstruir uma sequência de números.
>>> impares = filter(lambda x: x % 2, range(10))
>>> pares = filter(lambda x: not x % 2, range(10))
>>> impares
[1, 3, 5, 7, 9]
>>> pares
[0, 2, 4, 6, 8]
>>> zip(pares, impares)
[(0, 1), (2, 3), (4, 5), (6, 7), (8, 9)]
3.6. Conclusão
Existe ainda alguns aspectos de funções a serem tratados, os quais ainda poderão ser tratados nos próximos artigos.
1 comentário até agora