Curso de Python

Luiz Irber

Grupo de Modelagem Acoplada Oceano-Atmosfera

Python?

Resolvendo um problema!

It's a small world! (Resumo)

1  0.0      0.0

Começando

#!/usr/bin/env python

print 'hello world!'

Executando

$ python smallworld.py

ou

$ chmod +x smallworld.py

$ ./smallworld.py

Interativo x Scripts

$ python
Python 2.6 (r26:66714, Mar 23 2010, 15:24:19)
[GCC 4.3.2 [gcc-4_3-branch revision 141291]] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>>

Lendo dados de um arquivo

import sys

fp = open(sys.argv[1], 'r')
for line in fp:
    print line,

import

open

>>> help(open)
Help on built-in function open in module __builtin__:

open(...)
    open(name[, mode[, buffering]]) -> file object

    Open a file using the file() type, returns a file
    object.  This is the preferred way to open a file.
    See file.__doc__ for further information.

sys.argv[1]

Listas e tuplas

>>> tupla = (0, 1, 2, 3)
>>> lista = list(tupla)  # [0, 1, 2, 3]
>>> tupla[0]
0
>>> tupla[2]
2
>>> tupla[-1]
3
>>> lista[1:3]
[1, 2]
>>> tupla[1:3]
(1, 2)
>>> lista[::2]
[1, 3]

Listas e tuplas

>>> lista[2] = 5
>>> print lista
[1, 2, 5, 4]
>>> tupla[2] = 5
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment

for

for i, line in enumerate(fp):
    print i, line,

Recapitulando

import sys

fp = open(sys.argv[1], 'r')
for line in fp:
    print line,

Adiante!

pessoas = {}
fp = open(sys.argv[1], 'r')
for line in fp:
    pessoa, lat, lon = line[:-1].split()
    pessoas[pessoa] = (float(lat), float(lon))

Dicionários

>>> d = {}
>>> d['chave'] = 'valor'
>>> print d
{'chave': 'valor'}

Métodos

>>> d.keys()
['chave']
>>> d.values()
['valor']
>>> d.items()
[('chave', 'valor')]

Tipos

>>> type(d)
<type 'dict'>
>>> type('string')
<type 'str'>
>>> lista = ['a', 'b', 'c', 'd']
>>> texto = 'abcd'
>>> lista[0] == texto[0]
True
>>> list(texto)
['a', 'b', 'c', 'd']

Split

>>> virgulas = '1,2,3,4'
>>> virgulas.split(',')
['1', '2', '3', '4']
>>> line = '3  -12.2    12.2\n'
>>> line[:-1].split()
['3', '-12.2', '12.2']

Revisando

pessoas = {}
fp = open(sys.argv[1], 'r')
for line in fp:
    pessoa, lat, lon = line[:-1].split()
    pessoas[pessoa] = (float(lat), float(lon))

Funções

def le_dados(arquivo):
    pessoas = {}
    fp = open(arquivo, 'r')
    for line in fp:
        pessoa, lat, lon = line[:-1].split()
        pessoas[pessoa] = (float(lat), float(lon))
    return pessoas

le_dados(sys.argv[1])

Definindo funções

def nome(arg1, arg2=None, arg3=2):
    return arg1, arg2, arg3

>>> nome('1')
('1', None, 2)
>>> nome(1, 2, 3)
(1, 2, 3)
>>> nome(1, arg3=5)
(1, None, 5)

Calculando distância entre duas pessoas

import math

def distance(p1, p2):
    dlat_squared = (p1[0] - p2[0]) ** 2
    dlon_squared = (p1[1] - p2[1]) ** 2
    return math.sqrt(dlat_squared + dlon_squared)

Math

>>> import math
>>> math.cos(math.pi / 4.0)
0.70710678118654757
>>> math.log(1024, 2)
10.0
>>> math.sqrt(25)
5.0

Calculando distância de uma pessoa para outras

pessoas = le_dados(sys.argv[1])
p1 = '1'
distancias = []
for pessoa in pessoas:
    d = distance(pessoas[p1], pessoas[pessoa])
    distancias.append( (d, pessoa) )

Alguém vê o problema?

>>> from pprint import pprint
>>> pprint(sorted(distancias))
[(0.0, '1'),
 (14.28355697996826, '2'),
 (17.253405460951758, '3'),
 (54.16437943888954, '4'),
 (196.96395660120152, '5')]

Tentando de novo

pessoas = le_dados(sys.argv[1])
p1 = '1'
distancias = []
for pessoa in pessoas:
    if pessoa != p1:
        d = distance(pessoas[p1], pessoas[pessoa])
        distancias.append( (d, pessoa) )

Condicionais

if nome == 'Roger':
    print 'Welease Wogel!'
elif nome == 'Brian':
    print 'Welease Bwian!'
else:
    print 'Welease Wudolph!'

Comparando todo mundo

pessoas = le_dados(sys.argv[1])
todas_distancias = {}
for p1 in pessoas:
    distancias = []
    for p2 in pessoas:
        if p2 != p1:
            d = distance(pessoas[p1], pessoas[p2])
            distancias.append( (d, p2) )
    todas_distancias[p1] = sorted(distancias)

Padrões

Imprimindo no formato do problema

from StringIO import StringIO

saida = StringIO()
for p in todas_distancias:
    saida.write(p)
    saida.write(' ')
    saida.write(todas_distancias[p][0][1])
    saida.write(',')
    saida.write(todas_distancias[p][1][1])
    saida.write(',')
    saida.write(todas_distancias[p][2][1])
    saida.write('\n')
print saida.getvalue()

Por que usar StringIO?

>>> "a" + "b"
"ab"

Qual a vantagem de usar StringIO?

saida = open('saida', 'w')

Pensando melhor...

for p in todas_distancias:
    saida.write(p)
    dados = tuple([d[1] for d in todas_distancias[p]][:3])
    s = " %s,%s,%s\n" % dados
    saida.write(s)

Formatação de strings

>>> "%s %s %s" % ("oi", "tudo bem", "com você")
oi tudo bem com você?
>>> 'oi ' + "tudo bem " +  "com você?"
oi tudo bem com você?
>>> " ".join(['oi', 'tudo bem', 'com você?'])
oi tudo bem com você?

List comprehensions

lista1 = []
for d in todas_distancias[p]:
    lista1.append(d[1])
lista1 = lista1[:3]

lista2 = [d[1] for d in todas_distancias[p]][:3]

>>> lista1 == lista2
True

Pronto! Cumprimos o enunciado do problema!

A que nosso problema se refere?

Quais as características de uma pessoa?

Quais os métodos de cada pessoa?

Que tal assim?

class Pessoa(object):

    def __init__(self, nome, lat, lon):
        self.nome = nome
        self.lat = lat
        self.lon = lon

    def distancia(self, p2):
        dlat_squared = (self.lat - p2.lat) ** 2
        dlon_squared = (self.lon - p2.lon) ** 2
        return math.sqrt(dlat_squared + dlon_squared)

    def imprime(self):
        dados = tuple([d[1].nome for d in self.distancias][:3])
        return " ".join([self.nome, "%s,%s,%s\n" % dados])

Adaptando le_dados

def le_dados(arquivo):
    pessoas = []
    fp = open(arquivo, 'r')
    for line in fp:
        pessoa, lat, lon = line[:-1].split()
        pessoas.append(Pessoa(pessoa, float(lat), float(lon)))
    return pessoas
pessoas = le_dados(sys.argv[1])
def le_dados(arquivo):
    pessoas = {}
    fp = open(arquivo, 'r')
    for line in fp:
        pessoa, lat, lon = line[:-1].split()
        pessoas[pessoa] = (float(lat), float(lon))
    return pessoas
pessoas = le_dados(sys.argv[1])

Processando

for p1 in pessoas:
    distancias = []
    for p2 in pessoas:
        if p1 != p2:
            d = p1.distancia(p2)
            distancias.append((d, p2))
    p1.distancias = sorted(distancias)
todas_distancias = {}
for p1 in pessoas:
    distancias = []
    for p2 in pessoas:
        if p2 != p1:
            d = distance(pessoas[p1], pessoas[p2])
            distancias.append( (d, p2) )
    todas_distancias[p1] = sorted(distancias)

Imprimindo

saida = open('saida', 'w')
for p in pessoas:
    saida.write(p.imprime())
saida = open('saida', 'w')
for p in todas_distancias:
    saida.write(p)
    dados = tuple([d[1] for d in todas_distancias[p]][:3])
    s = " %s,%s,%s\n" % dados
    saida.write(s)

Por que usar objetos?

Problemas extras

Apenas o começo

Dúvidas?

Obrigado!

Luiz Irber

luiz.irber@gmail.com