Nesta pergunta estavam envolvidos vários conceitos: alcance das variáveis (local, global), passagem de parâmetros (real, formal) e mutabilidade.
Na primeira situação, na chamada da função f1, a lista l (variável global, mutável) é usada como parâmetro real. Deste modo, no início da execução da função, l e lista são nomes de objectos que têm a mesma identidade. No entanto, na primeira instrução de f1 a atribuição lista = [1,2,3] faz com que os nomes ficam associados a objectos diferentes. Deste modo, todas as alterações a lista não afectam l, pelo que na linha 12 vai aparecer o valor (inalterado) de l = [1,2].
Na segunda situação, ao contrário da anterior, não é desfeita a ligação dos nomes l e lista ao mesmo objecto. Tratando-se de um objecto mutável, todas alterações feitas ao parâmetro formal serão reflectidas no parâmetro real, pelo que ao acrescentarmos 3 à lista usando o método append, essa alteração vai também afectar l. Logo, na linha 17, vai aparecer [1,2,3].
sexta-feira, 30 de janeiro de 2015
quinta-feira, 8 de janeiro de 2015
Teste Final - Pergunta 4
Esta pergunta envolvia manipular um ficheiro em que cada linha é formada por um nome seguido de um ou mais números inteiros. O objectivo é criar um novo ficheiro, deixando o antigo inalterado, adicionando no final de cada linha a soma dos números dessa linha. Valorizava-se uma solução em que as linhas no ficheiro eram reordenadas por ordem crescente das somas.
Solução:
A solução apresentada inclui o ordenamento das linhas. Para isso usamos o método itemgetter do módulo operator. Começamos por percorrer o ficheiro linha a linha, calculando a soma dos números e guardando o resultado numa lista. É feito o ordenamento da lista de seguida. Na terceira parte, criamos o novo ficheiro e guardamos a informação.
Solução:
A solução apresentada inclui o ordenamento das linhas. Para isso usamos o método itemgetter do módulo operator. Começamos por percorrer o ficheiro linha a linha, calculando a soma dos números e guardando o resultado numa lista. É feito o ordenamento da lista de seguida. Na terceira parte, criamos o novo ficheiro e guardamos a informação.
from operator import itemgetter
def trata_ficheiro(ficheiro,novo_ficheiro):
with open(ficheiro,'r') as f_in:
novos_dados = list()
for linha in f_in:
lista_linha = linha[:-1].split()
valor = sum([int(elem) for elem in lista_linha[1:]])
lista_linha.append(valor)
novos_dados.append(lista_linha)
novos_dados.sort(key=itemgetter(-1))
with open(novo_ficheiro,'w') as f_out:
for linha in novos_dados:
linha[-1] = str(linha[-1]) + '\n'
cadeia = ' '.join(linha)
f_out.write(cadeia)
return novos_dados
Teste Final - Pergunta 3
Guardamos num dicionário as classificações que diversos filmes receberam dos críticos (um valor entre 1 e 5). Queremos manter o dicionário actualizado e saber qual o filme com melhor pontuação média. Só podem ser candidatos a melhor filme os que tiverem pelo menos 3 valores.
Solução:
A solução abaixo usa o setdefault para actualizar o dicionário das classificações. Deste modo fica resolvida a questão de incluir uma primeira classificação ou simplesmente actualizar. Actualizado o dicionário, ele é percorrido, item a item, para determinar o melhor, prevendo o caso de não ter as 3 classificações.
Solução:
A solução abaixo usa o setdefault para actualizar o dicionário das classificações. Deste modo fica resolvida a questão de incluir uma primeira classificação ou simplesmente actualizar. Actualizado o dicionário, ele é percorrido, item a item, para determinar o melhor, prevendo o caso de não ter as 3 classificações.
def melhor_filme(filmes, classific):
# actualiza
nome = classific[0]
valores = classific[1:]
filmes[nome] = filmes.setdefault(nome,[]) + valores
# calcula melhor
m_filme = ''
m_pont = 0
for nome,pontos in filmes.items():
comp = len(pontos)
if comp < 3:
continue
media = (sum(pontos)/comp)
if media > m_pont:
m_filme = nome
m_pont = media
return (m_filme, m_pont)
Teste Final - Pergunta 2
Simular um jogo em que se atiram dardos a um alvo. No caso do teste o problema era mais simples pois não se pretendia simular o jogo mas apenas desenhar o alvo e simular o lançamento de um dardo. E fazer isto usando o módulo turtle. E construindo o programa de forma modular.
Vamos então dividir a solução em duas partes: uma para desenhar o alvo, e outra para simular o lançamento do dardo. Por outro lado, vamos fazer com que o desenho do alvo seja feito à custa de uma mesma função, a que desenha um círculo de uma dada cor, numa dada posição e com o dado raio. Essa função chama-se circunf. A partir dela desenhar o alvo é fácil (função alvo). Estas última precisa saber apenas o centro do alvo e o valor dos raios. Os cuidados a ter são desenhar as circunferências da maior para a mais pequena (notar o ordenamento inverso da lista dos raios), e controlar a alternância das cores.
O lançamento do dardo recorre ao módulo random para geral a posição, e ao comando dot para marcar a localização do dardo. Neste último caso, não conhecendo o comando dot, podia socorrer-se uma vez mais ao desenho de uma circunferência…
Vamos então dividir a solução em duas partes: uma para desenhar o alvo, e outra para simular o lançamento do dardo. Por outro lado, vamos fazer com que o desenho do alvo seja feito à custa de uma mesma função, a que desenha um círculo de uma dada cor, numa dada posição e com o dado raio. Essa função chama-se circunf. A partir dela desenhar o alvo é fácil (função alvo). Estas última precisa saber apenas o centro do alvo e o valor dos raios. Os cuidados a ter são desenhar as circunferências da maior para a mais pequena (notar o ordenamento inverso da lista dos raios), e controlar a alternância das cores.
O lançamento do dardo recorre ao módulo random para geral a posição, e ao comando dot para marcar a localização do dardo. Neste último caso, não conhecendo o comando dot, podia socorrer-se uma vez mais ao desenho de uma circunferência…
import turtle
def circunf(posx, posy, raio, cor):
# posiciona
turtle.pu()
turtle.goto(posx,posy-raio)
turtle.pd()
# define cor e desenha
turtle.fillcolor(cor)
turtle.begin_fill()
turtle.circle(raio)
turtle.end_fill()
turtle.hideturtle()
def alvo(posx, posy,raios):
"""
raios: lista dos raios dos discos
"""
raios.sort(reverse=True)
cor = 'black'
for raio in raios:
circunf(posx,posy,raio,cor)
if cor == 'black':
cor = 'white'
else:
cor = 'black'
def dardo():
import random
posx = random.randint(-100,100)
posy = random.randint(-100,100)
turtle.pu()
turtle.goto(posx,posy)
turtle.pd()
turtle.dot(8,'red')
turtle.hideturtle()
if __name__ == ‘__main__’:
alvo(0,0,[20,40,60,80])
dardo()
turtle.exitonclick()
Como se pode ver pelo código o programa é facilmente generalizável. Alvo de vários tamanhos (directo) e cores (passando as cores para argumentos), por exemplo.
Teste Final - Pergunta 1a
Pedia-se para dizer o que eram e para que serviam as excepções e as asserções. Por outro lado, também se pretendia saber as suas semelhanças e as suas diferenças, e ainda a apresentação de um exemplo concreto de cada.
De um modo geral excepções e asserções são formas de controlar possíveis erros ou verificar condições num programa.
As excepções são instruções de controlo, enquanto as asserções são instruções simples. As excepções permitem que o programa continue a ser executado, mesmo na presença de um erro, pois prevê acções de remediarão. No caso das asserções isso não acontece, pois o programa termina no caso da asserção não se verificar. Assim estas últimas são sobretudo usadas para depurar os programas.
As excepções são activadas (raise) quando durante a execução se verifica um erro. Os erros podem ser de diversos tipos, podendo as excepções ser genéricas ou dirigidas a um ou mais tipos de erro. Um exemplo simples e clássico é prevenir erros nas operações:
De um modo geral excepções e asserções são formas de controlar possíveis erros ou verificar condições num programa.
As excepções são instruções de controlo, enquanto as asserções são instruções simples. As excepções permitem que o programa continue a ser executado, mesmo na presença de um erro, pois prevê acções de remediarão. No caso das asserções isso não acontece, pois o programa termina no caso da asserção não se verificar. Assim estas últimas são sobretudo usadas para depurar os programas.
As excepções são activadas (raise) quando durante a execução se verifica um erro. Os erros podem ser de diversos tipos, podendo as excepções ser genéricas ou dirigidas a um ou mais tipos de erro. Um exemplo simples e clássico é prevenir erros nas operações:
def divisao_protegida(x,y): try: res = x/y return res except ZeroDivisionError: print(‘ERRO: divisão por zero’)No caso das asserções elas permitem verificar condições para que um programa possa correr. Um exemplo, também clássico, permite evitar um ciclo infinito:
def factorial(x): assert (x >=0), ‘ERRO: número negativo’ res = 1 while x: res *= x x -= 1 return res
Teste Final - Pergunta 1b
A pergunta 1b do teste pedia para dizer, justificadamente, o que aparecia no lugar dos pontos de interrogação na sessão no interpretador seguinte:
Vamos por partes.
Na sessão começamos por definir a função xpto. A função tem um parâmetro formal de nome x. O corpo da função consiste no incremento de uma unidade do parâmetro formal, seguido pela impressão do seu valor, terminando pela instrução de return, neste caso sem expressão associada.
De seguida associamos o nome x ao objecto 7.
Mandamos depois executar a função xpto passando como parâmetro real o nome x, pedindo ainda para imprimir o resultado da execução.
No final, queremos saber qual o valor associado ao nome x.
Que conceitos estão em jogo?
Desde logo o nome x fora da definição é uma variável do ambiente global, enquanto o parâmetro formal, com o mesmo nome x, é uma variável local à definição. Por outro lado, ao ser associado ao objecto 7, o nome x corresponde a um objecto imutável.
O que acontece quando mandamos executar a função xpto? É feita a passagem de parâmetros, que em Python significa que a identidade do x global (parâmetro real) é passada para o x local (parâmetro formal). Repito: a identidade! De seguida é executada a instrução x += 1. Como se trata de um objecto imutável as identidades do x global e do x local ficam diferentes. Os dois objectos, embora com o mesmo nome, estão guardados em zonas diferentes do espaço dos objectos!
Da execução de xpto resulta a instrução print(x) que vai imprimir o novo valor de x (local), ou seja 8.
Por outro lado, todas as funções devolvem sempre um resultado. Caso não exista return, ou a instrução de return não tenha uma expressão associada, o valor devolvido pela função é sempre o mesmo, o objecto None. Esse objecto é passado à instrução print que faz o que lhe compete, imprimindo … None.
Depois de executada a função xpto os nomes locais à definição (incluindo os parâmetros formais) deixam de estar associados a objectos. Independentemente disso, como já existia separação entre os objectos quando se tenta saber o valor do x “externo” o seu valor continua a ser o anteriormente definido, ou seja, 7. Isto tudo porque o objecto associado é imutável!!!
Portanto, a passagem de parâmetros não se faz por cópia, mas sim por passagem da identidade (referência) do parâmetro real ao parâmetro formal. Por outro lado não é o facto de uma variável ser global e outra local que explica o que aconteceu
Entendeu? Para tirar dúvidas veja o que acontece na situação seguinte:
>>> def xpto(x): … x += 1 … print(x) … return … >>> x = 7 >>> print(xpto(x)) >>> ??? # —> 8 >>> ??? # —> None >>> x >>> ??? # —> 7 >>>À frente dos pontos de interrogação colocámos o resultado real. Das respostas fica a certeza de que ainda existe muita confusão conceptual.
Vamos por partes.
Na sessão começamos por definir a função xpto. A função tem um parâmetro formal de nome x. O corpo da função consiste no incremento de uma unidade do parâmetro formal, seguido pela impressão do seu valor, terminando pela instrução de return, neste caso sem expressão associada.
De seguida associamos o nome x ao objecto 7.
Mandamos depois executar a função xpto passando como parâmetro real o nome x, pedindo ainda para imprimir o resultado da execução.
No final, queremos saber qual o valor associado ao nome x.
Que conceitos estão em jogo?
Desde logo o nome x fora da definição é uma variável do ambiente global, enquanto o parâmetro formal, com o mesmo nome x, é uma variável local à definição. Por outro lado, ao ser associado ao objecto 7, o nome x corresponde a um objecto imutável.
O que acontece quando mandamos executar a função xpto? É feita a passagem de parâmetros, que em Python significa que a identidade do x global (parâmetro real) é passada para o x local (parâmetro formal). Repito: a identidade! De seguida é executada a instrução x += 1. Como se trata de um objecto imutável as identidades do x global e do x local ficam diferentes. Os dois objectos, embora com o mesmo nome, estão guardados em zonas diferentes do espaço dos objectos!
Da execução de xpto resulta a instrução print(x) que vai imprimir o novo valor de x (local), ou seja 8.
Por outro lado, todas as funções devolvem sempre um resultado. Caso não exista return, ou a instrução de return não tenha uma expressão associada, o valor devolvido pela função é sempre o mesmo, o objecto None. Esse objecto é passado à instrução print que faz o que lhe compete, imprimindo … None.
Depois de executada a função xpto os nomes locais à definição (incluindo os parâmetros formais) deixam de estar associados a objectos. Independentemente disso, como já existia separação entre os objectos quando se tenta saber o valor do x “externo” o seu valor continua a ser o anteriormente definido, ou seja, 7. Isto tudo porque o objecto associado é imutável!!!
Portanto, a passagem de parâmetros não se faz por cópia, mas sim por passagem da identidade (referência) do parâmetro real ao parâmetro formal. Por outro lado não é o facto de uma variável ser global e outra local que explica o que aconteceu
Entendeu? Para tirar dúvidas veja o que acontece na situação seguinte:
>>> def xpto2(x):
… x.append('a')
… print(x)
…
>>> x = [1,2,3]
>>> print(xpto2(x))
[1, 2, 3, 'a']
None
>>> x
[1, 2, 3, ‘a']
sexta-feira, 19 de dezembro de 2014
Teste #3 - TP 1
P1
Explicar com rigor o que se passou na listagem abaixo.
P2
Um ficheiro com a seguinte informação por linha: ano e cotação. Qual a cotação máxima e o respectivo ano?
P3
A classificação do campeonato está guardada num dicionário (chave = nome clube, valor = pontos). Conhecidos os resultados de uma jornada, actualizar a classificação. Os resultados da jornada é representado por uma lista de jogos e cada jogo é uma lista em que o primeiro elemento é o nome do clube 1, o segundo os golos marcado, o terceiro o nome do clube 2 e o quarto os golos marcados.
Explicar com rigor o que se passou na listagem abaixo.
>>> lista = [[]] * 3
>>> lista
[[], [], []]
>>> lista[1].append('ai')
>>> lista
[['ai'], ['ai'], [‘ai']]
A primeira instrução vai criar uma lista com três elementos, todos eles uma lista vazia, que de é visualizada(linha 2). Aplicamos depois o método append para acrescentar à lista vazia na segunda posição a cadeia de caracteres 'ai'. O método append altera a lista na segunda posição sem alterar a sua localização. Como os três elementos iniciais partilham a mesma memória, isto é, todos apontam para o mesmo objecto (a lista vazia), alterar um deles significa alterar todos. Estamos perante uma das consequências das listas serem objectos mutáveis e haver partilha de memória. P2
Um ficheiro com a seguinte informação por linha: ano e cotação. Qual a cotação máxima e o respectivo ano?
def cota_maxima(ficheiro):
with open(ficheiro) as f_ent:
maximo = 0
ano = 0
for linha in f_ent:
dados = linha[:-1].split()
ano_cur = int(dados[0])
valor_cota = float(dados[1])
if valor_cota > maximo:
maximo = valor_cota
ano = ano_cur
return ano, maximo
Erro mais frequente: ler todas as linhas com o readlines e depois aplicar o método split. Só que o readlines devolve uma lista e o split não se aplica a listas. P3
A classificação do campeonato está guardada num dicionário (chave = nome clube, valor = pontos). Conhecidos os resultados de uma jornada, actualizar a classificação. Os resultados da jornada é representado por uma lista de jogos e cada jogo é uma lista em que o primeiro elemento é o nome do clube 1, o segundo os golos marcado, o terceiro o nome do clube 2 e o quarto os golos marcados.
def actualiza_tabela(tabela, resultados):
for resultado in resultados:
if resultado[1] > resultado[3]:
tabela[resultado[0]] += 3
elif resultado[1] == resultado[3]:
tabela[resultado[0]] += 1
tabela[resultado[2]] += 1
else:
tabela[resultado[2]] += 3
return tabela
Erro comum: usar dois ciclos em que o primeiro percorre o dicionário e o segundo repete quatro vezes a alteração de um jogo…
Subscrever:
Mensagens (Atom)
