Programação com Python: 2016
Publicada por Ernesto Costa à(s) 11:24 Sem comentários:
Acontece com muita frequência que ao fim de resolvermos vários problemas verificamos existir um padrão comum a todas as soluções. Una vez descoberto o padrão passamos a olhar para novos problemas entanto perceber em que medida esse padrão se pode aplicar, adaptado claro está à nova questão. Vejamos uns exemplos simples.
Comecemos pelo caso de um programa que retira de uma cadeia de caracteres os elementos repetidos.
def tira_repete_1(cadeia):
acum = ''
if car not in acum:
acum = acum + car
A ideia é ir juntando caracteres formando um novo objecto associado ao nome atum cada vez que o ciclo é percorrido, caso o elemento ainda não esteja na nova cadeia.
[ Mesmo um problema tão simples pode ter várias variantes em função do que a linguagem concreta permite:
def tira_repete_2(cadeia):
acum = acum + cadeia[i]
def tira_repete_3(cadeia):
if cadeia.find(cadeia[i],i+1) == -1:
def tira_repete_4(cadeia):
return ''.join([cadeia[i] for i in range(len(cadeia)) if cadeia[i] not in cadeia[i+1:]])
Mas este aspecto não é o objectivo deste texto e por isso não comentamos as diferenças.]
Admitamos agora que nos pedem para calcular o produto escalar de dois vectores.
Um programa simples para resolver esta questão é o seguinte:
acum = acum + (vec1[i] * vec2[i])
Nesta solução vamos acumulando a soma parcial em acum. A cada etapa do ciclo vamos acrescentando à soma parcial o novo termo vec1[i] * vec2[i].
[ Esta solução supõe que os vectores têm a mesma dimensão. Caso não seja verdade uma alternativa seria:
dim = min(len(vec1), len(vec2))
Estes dois exemplos mostram uma solução comum: um acumulador onde vamos juntando o resultado parcial efectuado em cada etapa do ciclo. Armados desta conhecimento vamos tentar uma nova questão: calcular o factorial de um inteiro não negativo, ou seja, n!. Como fazer? Sabemos que por definição n! = n X (n-1) X (n-2) X … X 1. Olhando para a fórmula verificamos que ela envolve produtos repetidos. Podemos então recorrer a um ciclo, controlado por uma variável i, em que na etapa i do ciclo já calculámos os factorial … de i.
acum = acum * i
Olhando para estes três exemplos também resulta claro qual deve ser o valor inicial do acumulador: deve ser o elemento neutro para a operação realizada no interior do ciclo (cadeia vazia para concatenação de cadeias, 0 para somas, 1 para produtos.).
Publicada por Ernesto Costa à(s) 10:42 Sem comentários:
Publicada por Ernesto Costa à(s) 13:50 Sem comentários:
Publicada por Ernesto Costa à(s) 20:05 Sem comentários:
Em Python tudo são objectos. Os objectos têm atributos que dependem do tipo do objecto. No entanto existem três que todos têm: identidade, valor e tipo. O nome de um objecto é também um atributo que o objecto obtém através de uma atribuição. Quando fazemos x = x + 1 isso é informaticamente possível porque à esquerda do sinal de atribuição o 'x' remete para o nome, enquanto que à direita do sinal de atribuição remete o valor.
def distancia(lat1,long1,lat2,long2):
termo1 = math.sin(lat1) * math.sin(lat2)
termo2 = math.cos(lat1) * math.cos(lat2) * math.cos(long1 - long2)
return 6371.01 * math.acos(termo1 + termo2)
Desenhar um tiragulo rectângulo é semelhante a desenhar um triângulo, só que agora basta termos as duas medidas dos catetos. Tornar o desenho livre da dimensão dos lados, da orientação, da cor, obriga a usar esses elementos como parâmetros e a uma preparação para o desenho antes de concretizar. É isso que faz o código seguinte:
def tri_rect(x,y,orienta,cor,lado_1,lado_2):
Na segunda parte da pergunta era pedido que usassem a definição anterior como auxiliar para o desenho formado por um número variável de triângulos rectângulos alinhados circularmente e igualmente espaçados. A única dificuldade era controlar a orientação, o que obrigava a saber o espaçamento. É isso que é feito no programa:
tri_rect(x,y,orienta,cor,menor,maior)
Publicada por Ernesto Costa à(s) 20:35 Sem comentários:
Depois de vários anos a ensinar programação em Python resolvi publicar um livro. O texto cobre toda a matéria de IPRP, isto é a parte procedimental da linguagem, mas acrescenta uma parte sobre programação orientada aos objectos e outros aspectos que aprofundam o conhecimento da linguagem.
Quem gostar de aprender a programar numa linguagem que hoje é ensinada nas melhores escolas e usada pelas grandes empresas, tem neste livro uma oportunidade de o fazer de modo completo e em português.
Publicada por Ernesto Costa à(s) 12:45 Sem comentários:
Nestas primeiras aulas dissemos que em Python tudo são objectos. Cada objecto tem um conjunto determinado de atributos, como a identidade, o valor e o tipo, e um conjunto de operações em que podem participar. Os atributos num dado instante definem o estado do objecto, enquanto que as operações determinam o seu comportamento.
Podemos usar estes elementos para usar Python como se fosse um vulgar calculadora que me ajuda a saber o peso ideal de uma pessoa do género masculino.
>>> 72.7 * 1.81 - 58
73.58700000000002
Podemos fazer o mesmo para calcular o peso-ideal de uma pessoa do género feminino. E até podemos escrever um único programa que nos permite calcular o peso ideal de qualquer pessoa.
def peso_ideal(altura,genero):
if genero == 'M':
return round(72.7 * altura - 58,2)
return round(62.1 * altura - 44.7,2)
print(peso_ideal(1.81,'M'))
print(peso_ideal(1.74,'F'))
Este exemplo simples mostra a vantagem de soluções genéricas. Para as conseguir fazemos uso de uma abstracção procedimental, uma definição (def). Neste exemplo os dados são fornecidos ao programa no momento da chamada do programa através dos argumentos da definição, também designados de parâmetros formais, e o resultado é comunicado a quem o solicitou através do comando de regresso (return). Não tem que ser forçosamente assim.
def peso_ideal_2():
altura = float(input('A sua altura sff: '))
genero = input('O seu género sff [M/F]: ')
print(round(72.7 * altura - 58,2))
print(round(62.1 * altura - 44.7,2))
peso_ideal_2()
Como se pode ver a grande diferença entre as duas soluções reside no modo como se processa a entrada dos dados a a comunicação do resultado. Agora usamos input para introduzir os dados e print para comunicar o resultado. Neste exemplo, estão presentes o que designamos de instruções, que de um modo geral podem ser agrupadas em dois grandes grupos: destrutivas e de controlo. No primeiro grupo, estão as instruções de atribuição (=), entrada (input) e saída (print). No segundo grupo, as instruções de sequência (;), condicionais (if) e ciclos ou repetições (for). São os blocos construtores dos programas.
Outro exemplo que quer tratámos envolvia desenho de polígonos regulares. Mostrei como se podia passar de um programa muito simples para desenhar um quadrado:
para outro programa mais completo.
# Nova Definição
def vai_para(x,y):
def quadrado(x,y,orientacao,cor,lado):
vai_para(x,y)
quadrado(50, -50, 45,'red',50)
Completámos a ideia de abstracção ao mostrar como um único programa podia ser usado para desenhar qualquer polígono regular.
def poligono_reg(num_lados,x,y,orientacao,cor,lado):
angulo = 360//num_lados
turtle.right(angulo)
poligono_reg(7,50, -50, 45,'red',50)
A moral desta história é simples: generalizar + abstrair compensa!
Publicada por Ernesto Costa à(s) 17:35 Sem comentários:
Começar de novo Cá estamos em mais um início de ano lectivo. Para os estreantes quero apenas dizer que neste blogue podem encontrar vários elementos que vos ajudarão na disciplina de IPRP e, assim o espero, a tornarem-se melhores programadores. Para todos os outros bom regresso.