segunda-feira, 26 de setembro de 2016

Funções e listas

Já andámos a ver várias funções, de conversão ou matemáticas. Mas agora vamos abordar algumas funções que afetam listas. Comecemos por algumas bastante simples e diretas:
>>> max([1,5,3,7,8,2])
8
>>> min([1,5,3,7,8,2])
1
>>> sum([1,5,3,7,8,2])
26
Claro que estas funções apenas resultam se as listas contiverem apenas números. Como seria de esperar, a função max() apresenta o maior número na lista, a função min() apresenta o menor, e a função sum() apresenta a soma de todos os números na lista. As funções max() e min() também podem usar como argumento números ou variáveis separados por vírgulas:
>>> max(1,5,3,7,8,2)
8
>>> min(1,5,3,7,8,2)
1
Também temos um outro operador que funciona tanto em listas como em cadeias de caracteres, o operador in, que testa se algo se encontra numa lista (ou numa cadeia de caracteres) e responde com um booleano:
>>> 4 in [1,2,3,4]
True
>>> 0 in [4,8,7,4,9]
False
>>> 'a' in 'antonio'
True
>>> 'b' in 'antonio'
False
De notar que é a segunda vez que aparece o operador in, pois também é usado de modo diferente nos ciclos for.
E agora vamos ver outra função que é muito comum em várias linguagens: len(). Sendo a abreviatura de length (comprimento), resulta no comprimento de várias estruturas:
>>> len('batata')
6
>>> len([4,8,7,4,9])
5
Aplicado a cadeias de caracteres, diz-nos quantos tem, e em listas, indica o número de elementos da lista mais externa (sim, as listas podem ter listas como elementos).
Ora então chegamos finalmente a range(). No Python 2.x, era uma função que produzia uma lista, mas na versão 3.x produz uma sequência imutável. Antes de mais, o que faz isto? Em Python 2.x, fazia:
>>> range(3)
[0, 1, 2]
>>> range(3,6)
[3, 4, 5]
>>> range(1,11,2)
[1, 3, 5, 7, 9]
Em suma, quando só tem um argumento, range produzia uma lista de zero até esse argumento excluindo-o. Com dois argumentos, indica qual o número de onde começa e até onde vai, excluindo o final. Com 3 argumentos, é como com 2 mas o último argumento indica quanto se soma em cada iteração. Em Python 3.x, é quase a mesma coisa, mas se em 2.x se produzia uma lista que se podia depois modificar, em 3.x produz-se uma "lista-usa-e-deita-fora". Os exemplos acima em Python 3.x vão dar:
>>> range(3)
range(0, 3)
>>> range(3,6)
range(3, 6)
>>> range(1,11,2)
range(1, 11, 2)
Parece confuso, mas na realidade a diferença é subtil. range() é muito usado em conjunto com o comando for, como no programa abaixo:
for i in range(0,15,3):
    print(i)
que vai resultar em:
0
3
6
9
12
Este resultado seria o mesmo em Python 2.x. Mais tarde voltaremos a estas sequências imutáveis...
Falando ainda destas sequências, temos mais uma função que resulta numa destas, a função reversed(). Como o próprio nome indica, esta função inverte a sequência de uma lista que lhe seja fornecida como argumento, e resulta num iterável que corresponde à sequência invertida. Aqui já não há diferença de versões. Para aceder ao resultado, temos de iterar cada um dos elementos, como por exemplo:
for i in reversed([6,4,2,7,9]):
    print(i)
dá o seguinte:
9
7
2
4
6
Se experimentar:
>>> reversed([6,4,2,7,9])
<list_reverseiterator object at 0x02AEFA30>
O que não dá muito jeito... Mas felizmente, temos outra função que trata disto: list(). Esta converte o seu argumento numa lista, o que já dá muito jeito!
>>> list(reversed([6,4,2,7,9]))
[9, 7, 2, 4, 6]
Já agora, a função list() tem outras aplicações, ilustradas a seguir:
>>> list('Python')
['P', 'y', 't', 'h', 'o', 'n']
>>> list(range(6))
[0, 1, 2, 3, 4, 5]
Isto já permite umas coisas engraçadas, se puxar pela imaginação...
E vamos terminar com uma última função, sorted(), que serve para ordenar uma lista. Os exemplos são bastante elucidativos:
>>> sorted([6,4,2,7,9])
[2, 4, 6, 7, 9]
>>> sorted([6,4,2,7,9], reverse=True)
[9, 7, 6, 4, 2]
Como dá para perceber, podemos escolher a ordem, ascendente ou descendente, dependendo do valor que atribuímos ao argumento opcional reverse. E por hoje é tudo!

segunda-feira, 19 de setembro de 2016

Mais funções e operadores que dão jeito

Temos visto algumas funções de Python que já nos permitem obter algumas conversões interessantes. Mas existem outras funções de cariz mais matemático, que vale a pena abordar agora. Comecemos pelas seguintes:
>>> abs(-4)
4
>>> abs(-4.7)
4.7
>>> round(4.567)
5
>>> round(4.567, 2)
4.57
Como já deve ter percebido, a função abs() devolve o absoluto de um número, isto é, o número sem sinal. Na prática, converte números (inteiros ou decimais) negativos em números positivos.
A função round() arredonda números. Se o argumento for só um número, arredonda-o ao inteiro mais próximo. Com dois argumentos, o segundo é o número de casas decimais pretendidas. Nada de especial até aqui.
E continuamos com pow(). Na sua forma mais simples, pow(x, y) é outra maneira de escrever x**y, ou seja, x elevado a y. No entanto, pow(x, y, z) é o mesmo que x**y%z, isto é, x elevado a y, módulo z. Tenho a certeza que vai descobrir alguma utilidade para isto!...
E também temos divmod(). Esta função, como o próprio nome indica, dá o divisor e o módulo de dois números. Um exemplo explica melhor:
>>> 7 // 3
2
>>> 7 % 3
1
>>> divmod(7, 3)
(2, 1)
>>> divmod(4.8, 2)
(2.0, 0.7999999999999998)
Este último exemplo ilustra bem o problema de aproximações imperfeitas de números decimais. Claro que o resto deveria ser 0,8.
E agora temos uma função muito gira: eval(). Esta pega numa cadeia de caracteres e tenta avaliar se o seu conteúdo é uma expressão matemática válida. Mais um exemplo:
>>> eval('2*3 + 5')
11
>>> eval('2**8-1')
255
>>> x=6
>>> eval('x*4 - 7')
17
Se não for uma expressão matemática válida, dá erro... Mas já viu bem o último exemplo? Apesar de o x ser uma variável, dado que lhe foi atribuído um valor, x é corretamente avaliado dentro da expressão e a função consegue usá-lo para calcular o resultado final! Eu acho isto giro...
Muito bem, vamos passar para outro tipo de matemática, a lógica booleana. E vamos confirmar que em Python também existem os três típicos operadores de conjunção (and), disjunção (or) e negação (not):
>>> 1 and 1
1
>>> True or False
True
>>> not False
True
>>> not 0
True
Pois é, aqui temos de fazer uma ressalva muito importante: embora a lógica booleana apenas trabalhe com valores de Falso ou Verdadeiro, em Python há vários valores que são interpretados como Falso:

  • None (um valor especial que se pode atribuir a uma variável, que significa que não tem valor)
  • False (óbvio, não?)
  • zero em qualquer tipo numérico (0, 0.0, 0j)
  • Qualquer sequência vazia: '', [], (), {} (uma cadeia de caracteres vazia, uma lista vazia, e outros tipos de sequência que veremos mais tarde)
Todos os outros valores são considerados Verdadeiros. Mas o melhor mesmo é não inventar muito e tentar usar essencialmente True ou False como operandos destes operadores, para evitar resultados inesperados...
Claro que o local óbvio para usar os operadores acima é num comando if, onde poderá construir condições mais elaboradas com o auxílio destes operadores. Experimente!

segunda-feira, 12 de setembro de 2016

Conversões para todos os gostos

Na semana passada vimos uma função curiosa que quase passou despercebida: int(). O que vimos é que esta função converte o seu argumento num número inteiro. Nada de especial até aqui. No entanto, o pormenor interessante é que o seu argumento pode ser de vários tipos: inteiro, decimal ou cadeia de caracteres. Se tentarmos:
>>> int(4)
4
>>> int(4.7)
4
>>> int('4')
4
O resultado vai ser sempre 4, sem nenhum tipo de problema. Com um argumento do tipo decimal, o resultado é o inteiro truncado. Quando o argumento é uma cadeia de caracteres, deve poder traduzir-se diretamente num número inteiro, caso contrário resulta em erro. Por exemplo, '4 a', '4.0' ou '4,0' não vão funcionar. No entanto, há uma exceção: quando o argumento é uma cadeia de caracteres válida para representar um número noutra base, podemos usar esta função para o converter em inteiro de base 10. Por exemplo, 25 em binário (base 2) é 11001, portanto podemos usar int() para converter binário em decimal:
>>> int('11001', 2)
25
Isto funciona para qualquer base entre 2 e 36. Por exemplo:
>>> int('11001', 24)
345601
>>> int('1abc', 16)
6844
>>> int('ABC', 16)
2748
>>> int('Zx', 36)
1293
Porquê até 36? Porque apenas podemos representar números com os 10 dígitos e 26 caracteres (maiúsculas ou minúsculas), o que dá um total de 36.
Mas já que estamos com a mão na massa, vamos ver que outras funções de conversão existem. Para começar, temos str(), que converte o argumento em cadeia de caracteres:
>>> str(8)
'8'
>>> str(5.2)
'5.2'
>>> str('90')
'90'
Mais uma vez, o argumento pode ser um número inteiro, um decimal ou uma cadeia de caracteres.
Se quisermos converter o argumento em número decimal, usamos float():
>>> float(4)
4.0
>>> float('5.2')
5.2
>>> float(8.9)
8.9
E para compor o ramalhete de funções de conversão, falta mencionar complex(). Esta converte uma cadeia de caracteres ou dois números inteiros ou decimais num número complexo:
>>> complex(2,3)
(2+3j)
>>> complex(2.5,7)
(2.5+7j)
>>> complex('2.4-1.5j')
(2.4-1.5j)
De notar que a cadeia de caracteres não pode conter espaços entre o sinal e as partes real e complexa do número, senão resulta num erro.
Em qualquer uma das funções acima, o argumento pode ser uma variável, como seria de esperar, e o resultado pode ser atribuído a uma variável. Isto é geralmente possível com todas as funções, e as exceções serão sempre referidas.
Muito bem, agora vamos ver duas funções em que uma é o inverso da outra: chr() e ord():
>>> chr(65)
'A'
>>> ord('A')
65
>>> chr(10084)
'❤'
O resultado de chr() é o caracter Unicode correspondente ao número inserido (que vai de 0 a 65535), e ord() resulta no código Unicode do caracter (o argumento só pode ser uma cadeia de 1 caracter).
E para finalizar, três funções que nos permitem obter números noutra base diferente da decimal:
>>> hex(255)
'0xff'
>>> oct(255)
'0o377'
>>> bin(255)
'0b11111111'
De notar que o resultado é uma cadeia de caracteres. No entanto, os números inteiros também podem ser diretamente representados pelos seus equivalentes em hexadecimal (base 16), octal (base 8) e binário (base 2):
>>> 0xff
255
>>> 0o377
255
>>> 0b11111111
255
Finalmente, para esclarecer quaisquer dúvidas: o primeiro símbolo é um zero e não um O, e o 'x', o 'o' e o 'b' podem ser em maiúsculas ou minúsculas.

segunda-feira, 5 de setembro de 2016

Comandos condicionais

Olá a quem estiver aí.
Como já deve ter reparado, pouco a pouco vamos aprendendo como construir um programa que faça algo de jeito. Mas o que torna um programa de computador realmente interessante é a capacidade de decidir fazer coisas diferentes de acordo com os dados que lhe fornecemos. E é para isso que existem os comandos condicionais. Vamos supor que queremos que o programa nos pergunte por um número e que veja se é positivo ou negativo:
num = input('Escreve um número: ')
if int(num) < 0:
    print('O número é negativo')
else:
    print('O número é positivo')
Muito bem, neste pequeno programa já há muito sumo a espremer! Vamos analisá-lo linha a linha.
Começamos por obter a partir do utilizador uma entrada a partir do teclado, e aqui está a primeira novidade: se escrevermos uma cadeia de caracteres no interior dos parêntesis de input(), esta cadeia vai servir como pergunta.
Se bem se lembra, tudo o que escrevemos para input() é interpretado como uma cadeia de caracteres, e se queremos que seja convertido num número, usamos a função int(), que converte o seu argumento num número inteiro. Assim, na segunda linha temos um comando condicional, que começa com if e de seguida uma condição int(num) < 0. Aqui temos um primeiro exemplo de um operador de comparação, o menor-do-que. O resultado será um booleano, isto é, ou é verdadeiro ou é falso, dependendo do número que foi inserido em num pelo utilizador. De seguida, surgem dois pontos, a indicar que irá ter início um bloco de código, que terá de ser indentado a indicar o que será executado se a condição for verdadeira.
A terceira linha é o bloco de código que é executado, e é um comando print() a escrever que o número é negativo, o que acontece quando a condição em frente de if se verifica. Este bloco de código poderia ter várias linhas, desde que tivessem todas a mesma indentação.
A quarta linha tem o comando opcional else, seguido de dois pontos. É opcional porque poderíamos decidir fazer executar algo apenas quando a condição de if se verificasse. Mas podemos decidir que vai acontecer algo apenas quando não se verificar a condição, definindo um novo bloco.
Finalmente, a última linha é o comando que é executado apenas quando a condição não se verifica.
Agora vamos ver uma variante do programa acima, e espero que consiga adivinhar o que vai acontecer:
num = input('Escreve um número: ')
if int(num) < 0:
    print('O número é negativo')
elif int(num) > 0:
    print('O número é positivo')
else:
    print('O número é zero')
Aqui temos então o comando elif, que não é mais do que uma aglutinação de else if (mas não tente escrever else if, porque não funciona), e que permite analisar várias condições até encontrar uma que seja verificada. Por outras palavras, podemos escrever o número de comandos elif que quisermos (a seguir a um if inicial, claro!), que o Python verifica sequencialmente qual é a primeira condição verdadeira. (Caso seja um programador experimentado, posso desde já adiantar que o Python não tem uma estrutura do género select case, ou switch, pois uma sequência de if ... elif ... elif ... ... else substitui essa estrutura.)
Ok, antes de acabar, vou referir os vários operadores de comparação que existem: > (maior-do-que), < (menor-do-que), == (igual-a; repare que são dois sinais para distinguir de um igual de atribuição de variável), != (diferente-de), >= (maior-ou-igual-a), <= (menor-ou-igual-a). São 6 no total, e já dão para todas as comparações possíveis! E podem comparar-se cadeias de caracteres, inteiros, com casas decimais, ou mesmo booleanos! Toca a experimentar num programa ou mais para ver o que já consegue fazer!