M ´etodos Computacionais em F´ısica I
Sandra Amato
Instituto de F´ısica
Universidade Federal do Rio de Janeiro
Percorrendo uma lista
Ü Suponha que queiramos criar uma lista com valores de temperatura em graus cent´ıgrados e uma outra com a convers ˜ao para Farenheit. Ü uma forma pode ser atrav ´es de um loop, acessando o ´ındice da lista:
n = 21 C_min = -10 C_max = 40
dC = (C_max - C_min)/float(n-1) # incremento em C Cdegrees = [0]*n # cria lista com 21 zeros for i in range(len(Cdegrees)): Cdegrees[i] = -10 + i*dC Fdegrees = [0]*n for i in range(len(Cdegrees)): Fdegrees[i] = (9.0/5)*Cdegrees[i] + 32 for i in range(len(Cdegrees)):
print (’%d %5.1f %5.1f’ % (i, Cdegrees[i], Fdegrees[i]))
List Comprehension
Ü Percorrer uma lista e para cada elemento criar um novo elemento em outra lista ´e uma tarefa comum
Ü o python prov ˆe uma sintaxe compacta para esse fim, chamada de List Comprehension:
novalista = [E(e) for e in velhalista]
onde E(e) representa uma express ˜ao envolvendo o elemento e n = 21
Cdegrees = [-10 + i*2.5 for i in range(n)] Fdegrees = [(9.0/5)*C + 32 for C in Cdegrees] C_plus_5 = [C+5 for C in Cdegrees]
for i in range(len(Cdegrees)):
Percorrer mais de uma lista - zip
Ü E comum querermos percorrer mais de uma lista simultaneamente, por´ exemplo, criar uma tabela com a temperatura em Celsius e Farenheit Ü O for usando o elemento n ˜ao ´e adequado. No slide anterior fizemos
isso usando o for com o ´ındice das duas listas.
Ü No python h ´a uma outra forma mais compacta – zip – que nos permite usar o for com elemento:
for e1, e2, e3, ... in zip(lista1, lista2, lista3,...):
e1 ´e o elemento da lista1, e2 ´e o da lista2 etc n = 21
Cdegrees = [-10 + i*2.5 for i in range(n)] Fdegrees = [(9.0/5)*C + 32 for C in Cdegrees] C_plus_5 = [C+5 for C in Cdegrees]
for C, F in zip(Cdegrees, Fdegrees): print (’%5d %5.1f’ % (C, F))
User Input
Ü
Considere o programa A seno omegaT.py
from math import sin
A = 0.1
w = 1
t = 0.6
x = A * sin(w*t)
print (x)
Ü
A, w
e t s ˜ao vari ´aveis de entrada (input) e x ´e de sa´ıda (output)
Ü
As de input est ˜ao fixas (hardcoded)
Ü
para usar outros valores, deve-se editar o programa, mud ´a-las,
salvar e rodar novamente
Regra b ´asica de boa programac¸ ˜ao:
Edic¸ ˜ao de programa fonte deve ser evitada pois h ´a sempre o perigo de
se introduzir erros
User Input
Ü
Vamos ver quatro maneiras de ler dados de input
1
O programa escreve uma mensagem na tela, e espera pela
resposta do usu ´ario na janela de comando.
J ´a vimos como fazer: coloque dentro do programa:
massa= float(input("Dˆe o valor da massa em kg"))
2
O usu ´ario passa os inputs ao chamar o python:
$ python3 A seno omegaT.py 0.1 1 .6
3
o usu ´ario fornece um arquivo de input
4
o usu ´ario entra com o input atrav ´es de uma interface gr ´afica
Passando input na linha de comando
Ü Considere o programa anterior que calcula x = A*sin(w*t)
Ü queremos que os valores de A, w e t sejam passados pela linha de comando ao rodar o programa:
$ python3 A seno omegaT.py 0.1 1 .6
ÜPara isso fazemos: import sys
from math import sin A = float(sys.argv[1]) w = float(sys.argv[2]) t = float(sys.argv[3]) x = A*sin(w*t)
print (x)
ÜColoque coment ´arios
(doc string) para que o usu ´ario saiba a ordem dos argumentos
m o m ´odulo sys tem uma lista argv que cont ´em todos os argumentos passados pela linha de comandos
m o primeiro sys.argv[0] ´e sempre o nome do programa
m os elementos s ˜ao tratados como string, se forem n ´umeros devem ser convertidos
m os argumentos devem ser separados por espac¸o
N ´
umero vari ´avel de argumentos
Ü Suponha que eu queira escrever um programa, soma.py, que receba pela linha de comando uma quantidade qualquer de n ´umeros e imprima na tela a soma desses n ´umeros. Ex:
$python3 soma.py 5 5 4 2
$python3 soma.py 101.2 2.1 3.4
Ü Lembre que os n ´umeros s ˜ao armazenados como strings na lista sys.argv[1:]
import sys s = 0
for arg in sys.argv[1:]: numero = float(arg) s += numero
print("A soma de ", end="") for arg in sys.argv[1:]:
print(arg, end=" ") print("´e", s)
N ´
umero vari ´avel de argumentos
Ü O c ´odigo anterior ´e bem claro, e n ˜ao h ´a nada de errado com ele, mas ele pode ser reescrito (soma1.py) em uma forma mais compacta, talvez n ˜ao t ˜ao clara:
import sys
s = sum([float(x) for x in sys.argv[1:]])
print("A soma de %s ´e %s" %(’ ’.join(sys.argv[1:]),s))
Ü Usamos o m ´etodo sum que j ´a soma os elementos de uma lista
Ü A construc¸ ˜ao S.join(L) coloca todos os elementos da lista L, um ap ´os o outro, separados pela string S
Ü Digitar $python3 na frente do comando ´e meio chato... seria melhor fazer simplesmente
$ ./soma.py 5 5 4 2
Basta colocar na primeira linha do programa: #!/usr/bin/python3
onde /usr/bin/ ´e o local onde est ´a o python3 na sua m ´aquina ( esse ´e o ex. do LIG)
Error Handling
Ü Considere o seguinte programa(c2f cml.py)que transforma Celsius em Fahrenheit:
import sys
C = float(sys.argv[1]) F = 9.0*C/5 + 32
print(F)
Ü Que deve ser executado, p. ex., com o comando $ python3 c2f cml.py 21
69.8
Ü O que acontece se o argumento n ˜ao for do tipo esperado? $ python3 c2f cml.py 21C
Traceback (most recent call last):
File "c2f_cml.py", line 2, in <module> C = float(sys.argv[1])
Error Handling
Ü O que acontece se n ˜ao fornecermos o argumento necess ´ario? $ python3 c2f cml.py
Traceback (most recent call last):
File "c2f_cml.py", line 2, in <module> C = float(sys.argv[1])
IndexError: list index out of range
Ü Poder´ıamos fazer o programa parar de uma forma mais elegante. if len(sys.argv) < 2:
print (’O valor em graus Celsius deve ser fornecido’) sys.exit(1)
Ü Mas existe uma estrutura melhor no Python, que ´e considerada a melhor forma de lidar com potenciais erros:
try:
alguns comandos except:
try ... except ...
(c2f cml except1.py) import systry:
C = float(sys.argv[1]) except:
print (’O valor em graus Celsius deve ser fornecido’) sys.exit(1) # abort
F = 9.0*C/5 + 32
print (’%gC ´e %.1fF’ % (C, F))
Ü O comando C = float(sys.argv[1]) ´e (tentado ser) executado Ü Se der erro, o programa pula para o bloco do except
Ü Neste bloco, alguma tentativa de recuperac¸ ˜ao pode ser executada, p. ex., um valor default pode ser usado, sem a necessidade de sair do programa.
Ü ... mas o programa pode falhar, n ˜ao porque esquecemos de dar o argumento, mas por termos dado um tipo errado.
import sys try:
C = float(sys.argv[1]) except IndexError:
print (’O valor em graus Celsius deve ser fornecido’) sys.exit(1) # abort execution
except ValueError:
print (’O valor deve ser um n´umero, ’\ ’e n˜ao "%s"’ % sys.argv[1] sys.exit(1) F = 9.0*C/5 + 32 print ’%gC is %.1fF’ % (C, F) Ü e executando: $python3 c2f cml except2.py
O valor em graus Celsius deve ser fornecido $python3 c2f cml except2.py 21C
O valor deve ser um n´umero, e n˜ao 21C $python3 c2f cml except2.py 21
Tipos de exceptions
Ü IndexError:O python sempre para ao encontrar o ´ındice inv ´alido diferente de outras linguagens
>>> data = [2*i for i in range(1,10)] >>> data
[2, 4, 6, 8, 10, 12, 14, 16, 18] >>> data[9]
IndexError: list index out of range
Ü ValueError: convers ˜ao de string para float n ˜ao ´e permitido >>> C= float(’21 C’)
ValueError: could not convert string to float: ’21 C’ Ü NameError:N ˜ao se pode usar vari ´aveis n ˜ao inicializadas
>>> print (a)
Tipos de exceptions
Ü ZeroDivisionError: Divis ˜ao por zero para o programa >>> 3.0/0
Traceback (most recent call last): File "<stdin>", line 1, in <module> ZeroDivisionError: float division by zero Ü SintaxError: Erro ao escrever um comando do Python
>>> forr d in data: File "<stdin>", line 1
forr d in data: ˆ
SyntaxError: invalid syntax Ü IdentationError: Erro de identac¸ ˜ao
>>> for d in data: ... print (data)
File "<stdin>", line 2 print (data)
raise
Ü Podemos tamb ´em definir as nossas pr ´opriasexceptions.
Ü Por exemplo, um valor em graus Celsius menor que -273.15 n ˜ao tem sentido f´ısico, e queremos que o programa pare neste caso:
try:
C = float(sys.argv[1]) except IndexError:
print (’O valor em graus Celsius deve ser fornecido’) sys.exit(1) # abort execution
if C < -273.15:
raise ValueError (’C=%g ´e um valor n˜ao f´ısico!’ % C) F = 9.0*C/5 + 32
print (’%gC ´e %.1fF’ % (C, F))
Ü executando:
$python3 c2f_cml_except2.py -300
File "c2f_cml_except2.py", line 11, in <module>
if C < -273.15: raise ValueError (’C=%g ´e um valor n˜ao f´ısico!’ % C) ValueError: C=-300 ´e um valor n˜ao f´ısico!
Operador cast
Ü J ´a vimos como transformar uma vari ´avel de um certo tipo em outro tipo, o chamado operador cast
>>> r = "2" # r ´e str >>> s = int(a) # s ´e int >>> a = 3 # a ´e int >>> b = float(a) # b ´e float 3.0 >>> c = 3.9 # c ´e float >>> d = int(c) # d ´e int 3 >>> d = round(c) # d ´e float 4.0 >>> d = str(c) # d ´e str "3.9"
Ü ... e se quis ´essemos transformar a string “1 + 2” na express ˜ao matem ´atica 1 + 2 ?
Ü ... melhor ainda, transformar a string “sqrt(2) ∗ sin(pi/4) + 1” em uma func¸ ˜ao
Ü ... e ainda pass ´a-la para o programa pela linha de comando!! Ü A func¸ ˜aoevalnos d ´a essa possibilidade!!
a func¸ ˜ao eval
Ü
A func¸ ˜ao
eval
recebe uma string e retorna uma express ˜ao
>>> r = eval("1+2") ´e equivalente a >>> r >>> r = 1 + 2 3 o tipo de r ´e int >>> x = eval("3.2") ´e equivalente a >>> type(x) >>> x = 3.2 <class ’float’> >>> w = eval("[1, 2, 3]") ´e equivalente a >>> type(w) >>> w = [1, 2, 3] <class ’list’>
>>> from math import sqrt
>>> r = eval("sqrt(2)") ´e equivalente a >>> r >>> r = sqrt(2)
1.414213562 sqrt tem que estar definida
>>> r = eval(’ "Bom dia" ’) string tem que estar
>>> r dentro de string
’Bom dia’
Aplicac¸ ˜ao de eval
Ü Uma das principais vantagens da func¸ ˜ao eval ´e seu uso ao passar par ˆametros de input pela linha de comando.
Ü Ao lermos um par ˆametro atrav ´es da func¸ ˜ao input ou sys.arg ele vem sempre na forma de string e em geral convertemos para outro tipo, p. ex. int ou float
Aplicac¸ ˜ao de eval – 1
Ü Queremos fazer um programa (soma qualquer input.py) que calcula a soma de dois objetos, passados pela linha de comando, mas que podem ser de qualquer tipo, int, float, lista ou string (qualquer um que possamos usar o operador +)
Ü como n ˜ao sabemos o tipo que usu ´ario dar ´a, usamos eval para converter #!/usr/bin/python import sys i1 = eval(sys.argv[1]) i2 = eval(sys.argv[2]) r = i1 + i2
print (’%s + %s vira %s\n com valor %s’ % \ (type(i1), type(i2), type(r), r)) Ü e na linha de comando:
$ ./soma_qualquer_input.py 3 5
$ ./soma_qualquer_input.py ’ "Te" ’ ’ " amo" ’ $ ./soma_qualquer_input.py [1,3,5] [1,9,25]
Aplicac¸ ˜ao de eval – 2
Ü Uma outra aplicac¸ ˜ao muito ´util ´e transformar uma f ´ormula, dada como string na linha de comando, em express ˜ao matem ´atica:
from math import * #importa todas as func¸˜oes import sys
formula = sys.argv[1] x = eval(sys.argv[2]) result = eval(formula)
print("%s para x=%g ´e %g" % (formula, x, result)) Ü e na linha de comando:
$python3 formula.py ’sin(x)’ pi/6
Aplicac¸ ˜ao de eval – 3
Ü Uma aplicac¸ ˜ao muito ´util ´e fazer um pequeno programa (plot cml.py) que recebe uma func¸ ˜ao qualquer pelo teclado, al ´em dos valores m ´aximos e m´ınimos de x e mostra o gr ´afico dessa func¸ ˜ao: import sys
from numpy import *
from matplotlib.pyplot import * formula = sys.argv[1] xmin = eval(sys.argv[2]) xmax = eval(sys.argv[3]) x = linspace(xmin, xmax, 101) y = eval(formula) plot(x,y) title(formula) show() Ü e na linha de comando:
$ python3 plot_cml.py "exp(-0.2*x)*sin(2*pi*x)" 0 4*pi Ü Modifique o seu programa que calcula raiz de uma func¸ ˜ao para que ela seja lida
Leitura de dados de arquivo
Ü Uma outra forma de passar dados para um programa, ´e atrav ´es de um arquivo. Python oferece diversas func¸ ˜oes para leitura de arquivo. Ü J ´a vimos a func¸ ˜ao loadtxt do m ´odulo numpy. Supondo que o arquivo
val.txtcontenha uma coluna com 3 valores: 1.0 1.5 -2.2 >>> from numpy import loadtxt
>>> a = loadtxt ("val.txt") >>> print (a) [ 1. 1.5 -2.2] >>> type(a) <class ’numpy.ndarray’> type(a[0]) <class ’numpy.float64’> >>> media = sum(a)/len(a) # 0.10
Ü Os valores s ˜ao lidos como objetos float para um array Ü e podemos usar os m ´etodos de array: len(a), sum(a), etc... Ü Este ´e o melhor m ´etodo se vamos lidar s ´o com n ´umeros
A func¸ ˜ao open()
Ü Um outro m ´etodo para ler dados de um arquivo ´e atrav ´es do comando open. Ele ´e mais apropriado para ler strings ou uma mistura de n ´umeros e strings. Veja o programa readlines 0.py
infile = open("val.txt",’r’) soma = 0
cont = 0
for line in infile:
soma = soma + float(line) cont += 1
media = soma/cont print("%d %.2f %.2f"\
%(cont, soma, media)) infile.close()
m Execute o programa:
$ python3 readlines_0.py 3 0.30 0.10
m o arquivo “val.txt” ´e aberto com o comando open e com a opc¸ ˜ao de leitura (’r’) de read
m infile´e um objeto do tipo file, uma colec¸ ˜ao de linhas do arquivo
m a vari ´avel line conter ´a uma linha do arquivo a cada vez que passar pelo loop
m ela ´e do tipo string, por isso float(line)
m a vari ´avel cont est ´a aqui s ´o para contar o n ´umero de linhas do arquivo
m Depois de lido, o arquivo deve ser fechado
A func¸ ˜ao readline()
Ü Um m ´etodo menos pr ´atico para ler uma linha de cada vez ´e a func¸ ˜ao readline(). Veja o programa readlines 00.py
infile = open("val.txt",’r’) soma = 0 cont = 0 while True: line = infile.readline() if not line: break
soma = soma + float(line) cont += 1
media = soma/cont print("%d %.2f %.2f"\
%(cont, soma, media)) infile.close()
m o arquivo “val.txt” ´e aberto
m infile.readline()retorna uma stringcom o conte ´udo da linha em quest ˜ao
m a vari ´avel line conter ´a uma linha do arquivo a cada vez que passar pelo loop
m a cada chamada de
infile.readline()o programa passa para a pr ´oxima linha
m temos que controlar se chegamos ao fim do arquivo. Nesse caso
A func¸ ˜ao readlines()
Ü Em vez de ler linha a linha, podemos ler todas as linhas de uma vez usando readlines(). Veja o programa readlines.py
infile= open("val.txt", ’r’) lines = infile.readlines() infile.close()
print(lines) soma = 0
for line in lines: soma += float(line) media = soma/len(lines) print("%.2f" %media) $ python3 readlines.py [’1.0\n’, ’1.5\n’, ’-2.2\n’] 0.10
m o arquivo “val.txt” ´e aberto
m a vari ´avel lines ser ´a umalistacom todas as linhas do arquivo.
´
E equivalente a lines = []
for line in infile: lines.append(line)
m cada elemento ´e do tipo string, por isso float(line)
m n ˜ao precisamos contar o n ´umero de linhas
List comprehension
Ü Al ´em do m ´etodo len(lista), tamb ´em temos o m ´etodo sum(lista), desde que todos os elementos da lista sejam n ´umeros e n ˜ao strings Ü Poder´ıamos criar uma nova lista, fazendo um loop sobre os elementos e
transformando-os em float
Ü o Python fornece uma sintaxe compacta, para fazer uma operac¸ ˜ao sobre todos os elementos da lista, chamado list comprehension: Ü novalista = [E(i) for i in listaOriginal]
onde E representa uma express ˜ao envolvendo o elemento i da lista
>>> n=5
>>> Cdegrees = [1 + i*0.5 for i in range(n)] [1.0, 1.5, 2.0, 2.5, 3.0]
>>> Fdegrees = [(9.0/5)*C + 32 for C in Cdegrees] [33.8, 34.7, 35.6, 36.5, 37.4]
>>> list_str = [’1’,’2’,’3’] [’1’, ’2’, ’3’]
>>> list_float = [float(i) for i in list_str] [1.0, 2.0, 3.0]
Ü readlines.pypode ser simplificado para readlines 1.py infile = open("valores.txt", ’r’)
lines = infile.readlines() infile.close()
print(lines)
numeros = [float(line) for line in lines] print (numeros)
media = sum(numeros)/len(numeros)
print("%.2f %.2f" %(sum(numeros),media)) #ou simplesmente
infile = open("val.txt", ’r’)
numeros = [float(line) for line in infile.readlines()] infile.close() media = sum(numeros)/len(numeros) print("%.2f %.2f" %(sum(numeros),media)) $ python3 readlines_1.py [’1.0\n’, ’1.5\n’, ’-2.2\n’] [1.0, 1.5, -2.2] 0.30 0.10 0.30 0.10
Func¸ ˜
oes read() e split()
Ü Em vez deler todas as linhas de uma vez em umalista, podemos ler em umastringusando read().
>>infile=open("val.txt",’r’) >>filestr = infile.read() >>filestr ’1.0\n1.5\n-2.2\n’ >>print (filestr) 1.0 1.5 -2.2 >> words = filestr.split() >> words [’1.0’, ’1.5’, ’-2.2’]
>>num=[float(w) for w in words] >> num
[1.0, 1.5, -2.2]
m o arquivo “val.txt” ´e aberto
m a vari ´avel filestr ser ´a uma´unica stringcom todas as linhas do arquivo
m cada n ´umero ´e separado por um \n que representa “linha nova”
m Note a diferenc¸a entre filestr e print(filestr)
m a vantagem de ler para uma string ´e que existem v ´arias func¸ ˜oes para manipul ´a-las, por ex, split que cria uma lista de strings separadas por espac¸o (default)
Ü Os dois exemplos que vimos
m readlines()que l ˆe o arquivo todo para uma lista de strings e depois transformamos os elementos para float
m read()que l ˆe o arquivo todo para uma string e depois com
split()transforma a string em uma lista contendo as strings que estavam separadas por espac¸o, (ficando neste ponto igual ao resultado de readlines() anterior) e depois transformando os elementos para float
chegam ao mesmo produto final: uma lista de floats: [1.0, 1.5, -2.2]
m Qual o melhor m ´etodo depender ´a de cada problema.
m Conhecendo as possibilidades, Voc ˆe analisar ´a as necessidades, se precisa ser compacto, mais claro, mais f ´acil de extender mais tarde, etc, e escolher ´a o mais apropriado para o seu caso.
m Em geral, se trabalhamos s ´o com n ´umeros, acho a loadtxt() da numpymelhor
m para trabalhar com mistura de n ´umeros e strings, a leitura linha a linha ou readlines pode ser melhor. Veja o exemplo a seguir
Leitura de arquivo que cont ´em strings e n ´
umeros
Ü O arquivo chuva.dat cont ´em duas colunas, o nome do m ˆes e o ´ındice pluviom ´etrico. A primeira linha tem um t´ıtulo, e a ´ultima a informac¸ ˜ao do ano todo. Queremos ler os dados para duas listas, uma contendo os m ˆeses e outra com os ´ındices para posterior an ´alise de dados. Veja o programa chuva.py
´
Indice pluviom´etrico (em mm) em Roma: entre 1782 e 1970 Jan 81.2 Fev 63.2 . . . Nov 111.0 Dez 97.9 Ano 792.9
Percorrer mais de uma lista ao mesmo tempo
Ü J ´a prevemos aqui que vamos percorrer duas listas ao mesmo tempo.
Ü Suponha que temos uma lista meses e outra valores. Podemos fazer isso da seguinte forma:
for i in range(len(meses)): print (meses[i], valores[i])
Ü Python fornece um m ´etodo mais simples:
for e1, e2, e3, ... in zip(list1, list2, list3, ...): trabalha com elemento e1 da lista1,
elemento e2 da lista 2, etc
Ü Que no nosso exemplo se torna
for mes, valor in zip(meses, valores): print (mes, valor)
def extrai_dados(filename): infile = open(filename, ’r’)
infile.readline() # lˆe a primeira linha e nao faz nada com ela meses = []
chuva = []
for line in infile:
palavras = line.split()
# palavras[0]: mes, palavras[1]: chuva meses.append(palavras[0])
chuva.append(float(palavras[1])) infile.close()
meses = meses[:-1] # Descarta a ´ultima linha ("Year") media_anual = chuva[-1] # Guarda a info do ano em uma vari´avel chuva = chuva[:-1] # Descarta a ´ultima linha (792.9)
return meses, chuva, media_anual
meses, valores, media = extrai_dados(’chuva.dat’) print (’M´edia de chuva para os meses:’)
for mes, valor in zip(meses, valores): print (mes, valor)
Escrevendo dados em arquivo
Ü Para escrever dados em um arquivo, precisamos primeiro abri-lo, usando a func¸ ˜ao open, por ´em o segundo argumento tem que ser
m “w” (write) para criar um novo ou escrever por cima de um j ´a existente
m “a” (append) para incluir no final de um arquivo j ´a existente
Ü e para escrever, usamos a func¸ ˜ao write: s = "uma string"
outfile = open(’nomeDoArquivo.dat’, ’w’) outfile.write (s + ’\n’)
Ü s ´e uma string e devemos acrescentar \n para mudar de linha Ü podemos usar os mesmos argumentos de formato da func¸ ˜ao print Ü o seguinte c ´odigo pode ser colocado no final do arquivo chuva.py outfile = open(’chuva_out.dat’, ’w’)
outfile.write ("%7s %7s\n" %("Mˆes", "´ındice")) for mes, valor in zip(meses, valores):
outfile.write ("%7s %.1f \n" %(mes, valor)) outfile.close()
standard input/output e error
Ü Ao usarmos a func¸ ˜ao a = input(), o programa espera que o valor de aseja dado pelo teclado, que ´e o meio chamado de standard input Ü Ao usarmos a func¸ ˜ao print(a), o programa escreve o valor de a na
tela, que ´e o meio chamado de standard output Ü Considere o programa A seno omegaT input.py
from math import sin
A = float(input("De o valor de A " )) #0.1 w = float(input("De o valor de w " )) #1 t = float(input("De o valor de t " )) #0.6 x = A*sin(w*t)
print (x)
Ü Podemos redirecionar o input e/ou output para que seja lido/escrito de/em um arquivo, sem mudar nada no c ´odigo
Ü supondo que o arquivo dados.dat tenha os valores 0.1 1 0.6 podemos rodar omesmoprograma fazendo
Func¸ ˜
oes Lambda
Ü J ´a vimos como definir uma func¸ ˜ao simples: def f(x):
return x**2 + 4
Ü e depois us ´a-la no programa principal: y = f(2)
Ü Para func¸ ˜oes matem ´aticas simples, escritas em uma s ´o linha, o Python fornece a func¸ ˜ao lambda que deve ser escrita diretamente no programa principal, e depois usada da mesma forma acima:
f = lambda x: x**2 + 4
Ü cuja sintaxe ´e: antes do sinal “:” colocamos os argumentos da func¸ ˜ao, que podem ter keywords, e depois a express ˜ao:
f = lambda t, A=1, a=0.5: -a*2*t*A*exp(-a*t**2) Ü ela ´e mais apropriada para passar como argumento de outra func¸ ˜ao.
inline if
Ü J ´a vimos que podemos atribuir um valor para uma vari ´avel dependendo de uma condic¸ ˜ao:
if condic¸˜ao: a = valor1 else:
a = valor2
Ü O Python fornece uma sintaxe mais compacta para um if simples como esse, que pode ser feito em apenas uma linha:
a = valor1 if condic¸˜ao else valor2 Ex: def f(x):
return sin(x) if 0 <= x <= 2*pi else 0
Ü como o inline if ´e uma express ˜ao com um valor, e ´e feito em uma ´unica linha, ele pode ser usado na func¸ ˜ao lambda
>>> f = lambda x: sin(x) if 0 <= x <= 2*pi else 0 >>> f(2)
0.9092974268256817 >>> f(-2)
Como testar se um programa funciona?
Ü Todoprograma deve ser testado com valores que voc ˆe conhec¸a o resultado, prevendo possibilidades de erro, p.ex. divis ˜ao por zero, raiz de n ´umero negativo, etc...
Ü Uma boa pr ´atica de programac¸ ˜ao ´e criar func¸ ˜oes de teste que
imprimam uma mensagem caso o resultado n ˜ao seja o esperado. P. ex, queremos testar a func¸ ˜ao
def dobro(x): return 2*x
Ü uma func¸ ˜ao de teste poderia ser: def teste_dobro():
if dobro(2) != 4:
print ("dobro de 2 nao deu 4") if dobro("Beijo") != "BeijoBeijo":
print ("dobro de string deu ruim") if abs(dobro(0.1) - 0.2) > 1.e-15:
print ("dobro de real tem problema") teste_dobro()
assert
Ü
Existem alguns pacotes (
pytest
,
nose
) que testam
automaticamente as func¸ ˜oes desde que algumas convenc¸ ˜oes
sejam seguidas. A func¸ ˜ao de teste deve:
m
ter um nome que comece com test
m
n ˜ao tenha argumentos
m
ter uma vari ´avel booleana (p.ex. success) que seja
True se passar no teste e False se falhar
m
ter uma mensagem de erro armazenada numa string
(p.ex. msg) explicando onde falhou
m
usar o comando
assert success, msg
que vai parar o programa e escrever a mensagem de erro,
caso o teste falhe (a vari ´avel success ´e False)
def dobro(x): return 2*x def test_dobro():
success = dobro(2) == 4 msg = ’dobro de 2 nao deu 4’ assert success, msg
success = abs(dobro(0.1) - 0.2) < 1E-15 msg = "dobro de real tem problema" assert success, msg
success = dobro([1, 2]) == [1, 2, 1, 2] msg = "dobro de lista tem problema" assert success, msg
success = dobro(3+4j) == 6+8j
msg = "dobro de complexo tem problema" assert success, msg
# n˜ao ´e necess´ario ter a vari´avel
assert dobro(’Oi’) == ’OiOi’, ’dobro de string deu ruim’ test_dobro()
Exerc´ıcio
f0(x ) ≈f (x + h) − f (x − h) 2h
Ü A f ´ormula acima pode ser usada para encontrar o valor num ´erico da derivada de f (x ) no ponto x , desde que h seja bem pequeno
Ü Escreva um programa em python, derivada.py que
m contenha uma func¸ ˜ao diff (f, x, h=1e-5) que retorne o valor da f ´ormula acima
m contenha uma func¸ ˜ao de teste test diff(), com as convenc¸ ˜oes do pytest. Uma func¸ ˜ao f apropriada ´e a func¸ ˜ao quadr ´atica, pois para ela, a f ´ormula aproximada acima se torna exata
m nesta func¸ao quadr ´atica use a func¸ ˜ao lambda do python
m no seu programa principal chame a func¸ ˜ao de teste test diff() e
m imprima o valor “exato” e o valor calculado pela func¸ ˜ao diff() das derivadas das seguintes func¸ ˜oes
f (x ) = ex em x = 0, f (x ) = e−2x2 em x = 0,
f (x ) = cos(x ) em x = 2π, f (x ) = ln(x ) em x = 1,
m Use h = 0.01, e em cada print, imprima tamb ´em a diferenc¸a entre o valor exato e o aproximado
Ü Ü m Ü