Python para Desenvolvedores

2ª edição, revisada e ampliada

Capítulo 5: Tipos


Variáveis no interpretador Python são criadas através da atribuição e destruídas pelo coletor de lixo (garbage collector), quando não existem mais referências a elas.

Os nomes das variáveis devem começar com letra (sem acentuação) ou sublinhado () e seguido por letras (sem acentuação), dígitos ou sublinhados (), sendo que maiúsculas e minúsculas são consideradas diferentes.

Existem vários tipos simples de dados pré-definidos no Python, tais como:

  • Números (inteiros, reais, complexos, ... )
  • Texto

Além disso, existem tipos que funcionam como coleções. Os principais são:

  • Lista
  • Tupla
  • Dicionário

Os tipos no Python podem ser:

  • Mutáveis: permitem que os conteúdos das variáveis sejam alterados.
  • Imutáveis: não permitem que os conteúdos das variáveis sejam alterados.

Em Python, os nomes de variáveis são referências, que podem ser alteradas em tempos de execução.

Os tipos e rotinas mais comuns estão implementados na forma de builtins, ou seja, eles estão sempre disponíveis em tempo de execução, sem a necessidade de importar nenhuma biblioteca.

Números

Python oferece alguns tipos numéricos na forma de builtins:

  • Inteiro (int): i = 1
  • Real de ponto flutuante (float): f = 3.14
  • Complexo (complex): c = 3 + 4j

Além dos números inteiros convencionais, existem também os inteiros longos, que tem dimensão arbitrária e são limitados pela memória disponível. As conversões entre inteiro e longo são realizadas de forma automática. A função builtin int() pode ser usada para converter outros tipos para inteiro, incluindo mudanças de base.

Exemplo:

In [1]:
# Convertendo de real para inteiro
print 'int(3.14) =', int(3.14)

# Convertendo de inteiro para real
print 'float(5) =', float(5)

# Calculo entre inteiro e real resulta em real
print '5.0 / 2 + 3 = ', 5.0 / 2 + 3

# Inteiros em outra base
print "int('20', 8) =", int('20', 8) # base 8
print "int('20', 16) =", int('20', 16) # base 16

# Operações com números complexos
c = 3 + 4j
print 'c =', c
print 'Parte real:', c.real
print 'Parte imaginária:', c.imag
print 'Conjugado:', c.conjugate()
int(3.14) = 3
float(5) = 5.0
5.0 / 2 + 3 =  5.5
int('20', 8) = 16
int('20', 16) = 32
c = (3+4j)
Parte real: 3.0
Parte imaginária: 4.0
Conjugado: (3-4j)

Os números reais também podem ser representados em notação cientifica, por exemplo: 1.2e22.

O Python tem uma série de operadores definidos para manipular números, através de cálculos aritméticos, operações lógicas (que testam se uma determina condição é verdadeira ou falsa) ou processamento bit-a-bit (em que os números são tratados na forma binária).

Operações aritméticas:

  • Soma (+)
  • Diferença (-)
  • Multiplicação (*)
  • Divisão (/): entre dois inteiros funciona igual à divisão inteira. Em outros casos, o resultado é real.
  • Divisão inteira (//): o resultado é truncado para o inteiro imediatamente inferior, mesmo quando aplicado em números reais, porém neste caso o resultado será real também.
  • Módulo (%): retorna o resto da divisão.
  • Potência (**): pode ser usada para calcular a raiz, através de expoentes fracionários (exemplo: 100 ** 0.5).
  • Positivo (+)
  • Negativo (-)

Operações lógicas:

  • Menor (<)
  • Maior (>)
  • Menor ou igual (<=)
  • Maior ou igual (>=)
  • Igual (==)
  • Diferente (!=)

Operações bit-a-bit:

  • Deslocamento para esquerda (<<)
  • Deslocamento para direita (>>)
  • E bit-a-bit (&)
  • Ou bit-a-bit (|)
  • Ou exclusivo bit-a-bit (^)
  • Inversão (~)

Durante as operações, os números serão convertidos de forma adequada (exemplo: (1.5+4j) + 3 resulta em 4.5+4j).

Além dos operadores, também existem algumas funções builtin para lidar com tipos numéricos: abs(), que retorna o valor absoluto do número, oct(), que converte para octal, hex(), que converte para hexadecimal, pow(), que eleva um número por outro e round(), que retorna um número real com o arredondamento especificado.

Texto

As strings no Python são builtins para armazenar texto. Como são imutáveis, não é possível adicionar, remover ou mesmo modificar algum caractere de uma string. Para realizar essas operações, o Python precisa criar um nova string.

Tipos:

  • String padrão: s = 'Led Zeppelin'
  • String unicode: u = u'Björk'

A string padrão pode ser convertida para unicode através da função unicode().

A inicialização de strings pode ser:

  • Com aspas simples ou duplas.
  • Em várias linhas consecutivas, desde que seja entre três aspas simples ou duplas.
  • Sem expansão de caracteres (exemplo: s = r'\n', em que s conterá os caracteres \ e n).

Operações com strings:

In [2]:
s = 'Camel'

# Concatenação
print 'The ' + s + ' run away!'

# Interpolação
print 'tamanho de %s => %d' % (s, len(s))

# String tratada como sequência
for ch in s: print ch

# Strings são objetos
if s.startswith('C'): print s.upper()

# o que acontecerá?
print 3 * s
# 3 * s é consistente com s + s + s
The Camel run away!
tamanho de Camel => 5
C
a
m
e
l
CAMEL
CamelCamelCamel

Operador % é usado para fazer interpolação de strings. A interpolação é mais eficiente no uso de memória do que a concatenação convencional.

Símbolos usados na interpolação:

  • %s: string.
  • %d: inteiro.
  • %o: octal.
  • %x: hexacimal.
  • %f: real.
  • %e: real exponencial.
  • %%: sinal de percentagem.

Os símbolos podem ser usados para apresentar números em diversos formatos.

Exemplo:

In [3]:
# Zeros a esquerda
print 'Agora são %02d:%02d.' % (16, 30)

# Real (número após o ponto controla as casas decimais)
print 'Percentagem: %.1f%%, Exponencial:%.2e' % (5.333, 0.00314)

# Octal e hexadecimal
print 'Decimal: %d, Octal: %o, Hexadecimal: %x' % (10, 10, 10)
Agora são 16:30.
Percentagem: 5.3%, Exponencial:3.14e-03
Decimal: 10, Octal: 12, Hexadecimal: a

A partir da versão 2.6, está disponível outra forma de interpolação além do operador %, o método de string e a função chamados format().

Exemplos:

In [5]:
musicos = [('Page', 'guitarrista', 'Led Zeppelin'),
('Fripp', 'guitarrista', 'King Crimson')]

# Parâmetros identificados pela ordem
msg = '{0} é {1} do {2}'

for nome, funcao, banda in musicos:
    print(msg.format(nome, funcao, banda))

# Parâmetros identificados pelo nome
msg = '{saudacao}, são {hora:02d}:{minuto:02d}'

print msg.format(saudacao='Bom dia', hora=7, minuto=30)

# Função builtin format()
print 'Pi =', format(3.14159, '.3e')
Page é guitarrista do Led Zeppelin
Fripp é guitarrista do King Crimson
Bom dia, são 07:30
Pi = 3.142e+00

A função format() pode ser usada para formatar apenas um dado de cada vez.

Fatias (slices) de strings podem ser obtidas colocando índices entre colchetes após a string.

Fatiando strings

Os índices no Python:

  • Começam em zero.
  • Contam a partir do fim se forem negativos.
  • Podem ser definidos como trechos, na forma [inicio:fim + 1:intervalo]. Se não for definido o inicio, será considerado como zero. Se não for definido o fim + 1, será considerado o tamanho do objeto. O intervalo (entre os caracteres), se não for definido, será 1.

É possível inverter strings usando um intervalo negativo:

In [6]:
print 'Python'[::-1]
# Mostra: nohtyP
nohtyP

Várias funções para tratar com texto estão implementadas no módulo string.

In [7]:
# importando o módulo string
import string

# O alfabeto
a = string.ascii_letters

# Rodando o alfabeto um caractere para a esquerda
b = a[1:] + a[0]

# A função maketrans() cria uma tabela de tradução
# entre os caracteres das duas strings que ela
# recebeu como parâmetro.
# Os caracteres ausentes nas tabelas serão
# copiados para a saída.
tab = string.maketrans(a, b)

# A mensagem...
msg = '''Esse texto será traduzido..
Vai ficar bem estranho.
'''
# A função translate() usa a tabela de tradução
# criada pela maketrans() para traduzir uma string
print string.translate(msg, tab)
Fttf ufyup tfsá usbevAjep..
Wbj gjdbs cfn ftusboip.

O módulo também implementa um tipo chamado Template, que é um modelo de string que pode ser preenchido através de um dicionário. Os identificadores são inciados por cifrão ($) e podem ser cercados por chaves, para evitar confusões.

Exemplo:

In [8]:
# importando o módulo string
import string

# Cria uma string template
st = string.Template('$aviso aconteceu em $quando')

# Preenche o modelo com um dicionário
s = st.substitute({'aviso': 'Falta de eletricidade',
    'quando': '03 de Abril de 2002'})

# Mostra:
# Falta de eletricidade aconteceu em 03 de Abril de 2002
print s
Falta de eletricidade aconteceu em 03 de Abril de 2002

É possível usar strings mutáveis no Python, através do módulo UserString, que define o tipo MutableString:

In [9]:
# importando o módulo UserString
import UserString

s = UserString.MutableString('Python')
s[0] = 'p'

print s # mostra "python"
python

Strings mutáveis são menos eficientes do que strings imutáveis, pois são mais complexas (em termos de estrutura), o que se reflete em maior consumo de recursos (CPU e memória).

As strings unicode podem convertidas para strings convencionais através do método decode() e o caminho inverso pode ser feito pelo método encode().

Exemplo:

In [10]:
# String unicode
u = u'Hüsker Dü'
# Convertendo para str
s = u.encode('latin1')
print s, '=>', type(s)

# String str
s = 'Hüsker Dü'
u = s.decode('latin1')

print repr(u), '=>', type(u)
H�sker D� => <type 'str'>
u'H\xc3\xbcsker D\xc3\xbc' => <type 'unicode'>

Para usar os dois métodos, é necessário passar como argumento a codificação compatível, as mais utilizadas com a língua portuguesa são “latin1” e “utf8”.

Listas

Listas são coleções heterogêneas de objetos, que podem ser de qualquer tipo, inclusive outras listas.

As listas no Python são mutáveis, podendo ser alteradas a qualquer momento. Listas podem ser fatiadas da mesma forma que as strings, mas como as listas são mutáveis, é possível fazer atribuições a itens da lista.

Sintaxe:

lista = [a, b, ..., z]

Operações comuns com listas:

In [11]:
# Uma nova lista: Brit Progs dos anos 70
progs = ['Yes', 'Genesis', 'Pink Floyd', 'ELP']

# Varrendo a lista inteira
for prog in progs:
    print prog

# Trocando o último elemento
progs[-1] = 'King Crimson'

# Incluindo
progs.append('Camel')

# Removendo
progs.remove('Pink Floyd')

# Ordena a lista
progs.sort()

# Inverte a lista
progs.reverse()

# Imprime numerado
for i, prog in enumerate(progs):
    print i + 1, '=>', prog

# Imprime do segundo item em diante
print progs[1:]
Yes
Genesis
Pink Floyd
ELP
1 => Yes
2 => King Crimson
3 => Genesis
4 => Camel
['King Crimson', 'Genesis', 'Camel']

A função enumerate() retorna uma tupla de dois elementos a cada iteração: um número sequencial e um item da sequência correspondente.

A lista possui o método pop() que facilita a implementação de filas e pilhas:

In [12]:
lista = ['A', 'B', 'C']
print 'lista:', lista

# A lista vazia é avaliada como falsa
while lista:
    # Em filas, o primeiro item é o primeiro a sair
    # pop(0) remove e retorna o primeiro item
    print 'Saiu', lista.pop(0), ', faltam', len(lista)

# Mais itens na lista
lista += ['D', 'E', 'F']
print 'lista:', lista

while lista:
    # Em pilhas, o primeiro item é o último a sair
    # pop() remove e retorna o último item
    print 'Saiu', lista.pop(), ', faltam', len(lista)
lista: ['A', 'B', 'C']
Saiu A , faltam 2
Saiu B , faltam 1
Saiu C , faltam 0
lista: ['D', 'E', 'F']
Saiu F , faltam 2
Saiu E , faltam 1
Saiu D , faltam 0

As operações de ordenação (sort) e inversão (reverse) são realizadas na própria lista, sendo assim, não geram novas listas.

Tuplas

Semelhantes as listas, porém são imutáveis: não se pode acrescentar, apagar ou fazer atribuições aos itens.

Sintaxe:

tupla = (a, b, ..., z)

Os parênteses são opcionais.

Particularidade: tupla com apenas um elemento é representada como:

t1 = (1,)

Os elementos de uma tupla podem ser referenciados da mesma forma que os elementos de uma lista:

primeiro_elemento = tupla[0]

Listas podem ser convertidas em tuplas:

tupla = tuple(lista)

E tuplas podem ser convertidas em listas:

lista = list(tupla)

Embora a tupla possa conter elementos mutáveis, esses elementos não podem sofrer atribuição, pois isto modificaria a referência ao objeto.

Exemplo (usando o modo interativo):

>>> t = ([1, 2], 4)
>>> t[0].append(3)
>>> t
([1, 2, 3], 4)
>>> t[0] = [1, 2, 3]
Traceback (most recent call last):
  File "<input>", line 1, in ?
TypeError: object does not support item assignment
>>>

As tuplas são mais eficientes do que as listas convencionais, pois consomem menos recursos computacionais (memória), por serem estruturas mais simples, tal como as strings imutáveis em relação às strings mutáveis.

Outros tipos de sequências

O Python provê entre os builtins também:

  • set: sequência mutável unívoca (sem repetições) não ordenada.
  • frozenset: sequência imutável unívoca não ordenada.

Os dois tipos implementam operações de conjuntos, tais como: união, interseção e diferença.

Exemplo:

In [14]:
# Conjuntos de dados
s1 = set(range(3))
s2 = set(range(10, 7, -1))
s3 = set(range(2, 10, 2))

# Exibe os dados
print 's1:', s1, '\ns2:', s2, '\ns3:', s3

# União
s1s2 = s1.union(s2)
print 'União de s1 e s2:', s1s2

# Diferença
print 'Diferença com s3:', s1s2.difference(s3)

# Interseção
print 'Interseção com s3:', s1s2.intersection(s3)

# Testa se um set inclui outro
if s1.issuperset([1, 2]):
    print 's1 inclui 1 e 2'

# Testa se não existe elementos em comum
if s1.isdisjoint(s2):
    print 's1 e s2 não tem elementos em comum'
s1: set([0, 1, 2]) 
s2: set([8, 9, 10]) 
s3: set([8, 2, 4, 6])
União de s1 e s2: set([0, 1, 2, 8, 9, 10])
Diferença com s3: set([0, 1, 10, 9])
Interseção com s3: set([8, 2])
s1 inclui 1 e 2
s1 e s2 não tem elementos em comum

Quando uma lista é convertida para set, as repetições são descartadas.

Na versão 2.6, também está disponível um tipo builtin de lista mutável de caracteres, chamado bytearray.

Dicionários

Um dicionário é uma lista de associações compostas por uma chave única e estruturas correspondentes. Dicionários são mutáveis, tais como as listas.

A chave precisa ser de um tipo imutável, geralmente são usadas strings, mas também podem ser tuplas ou tipos numéricos. Já os itens dos dicionários podem ser tanto mutáveis quanto imutáveis. O dicionário do Python não fornece garantia de que as chaves estarão ordenadas.

Sintaxe:

dicionario = {'a': a, 'b': b, ..., 'z': z}

Estrutura:

Estrutura de um dicionário

Exemplo de dicionário:

dic = {'nome': 'Shirley Manson', 'banda': 'Garbage'}

Acessando elementos:

print dic['nome']

Adicionando elementos:

dic['album'] = 'Version 2.0'

Apagando um elemento do dicionário:

del dic['album']

Obtendo os itens, chaves e valores:

itens = dic.items()
chaves = dic.keys()
valores = dic.values()

Exemplos com dicionários:

In [15]:
# Progs e seus albuns
progs = {'Yes': ['Close To The Edge', 'Fragile'],
    'Genesis': ['Foxtrot', 'The Nursery Crime'],
    'ELP': ['Brain Salad Surgery']}

# Mais progs
progs['King Crimson'] = ['Red', 'Discipline']

# items() retorna uma lista de
# tuplas com a chave e o valor
for prog, albuns in progs.items():
    print prog, '=>', albuns

# Se tiver 'ELP', deleta
if progs.has_key('ELP'):
    del progs['ELP']
Yes => ['Close To The Edge', 'Fragile']
ELP => ['Brain Salad Surgery']
Genesis => ['Foxtrot', 'The Nursery Crime']
King Crimson => ['Red', 'Discipline']

Exemplo de matriz esparsa:

In [17]:
# Matriz esparsa implementada
# com dicionário

# Matriz esparsa é uma estrutura
# que só armazena os valores que
# existem na matriz

dim = 6, 12
mat = {}

# Tuplas são imutáveis
# Cada tupla representa
# uma posição na matriz
mat[3, 7] = 3
mat[4, 6] = 5
mat[6, 3] = 7
mat[5, 4] = 6
mat[2, 9] = 4
mat[1, 0] = 9

for lin in range(dim[0]):
    for col in range(dim[1]):
        # Método get(chave, valor)
        # retorna o valor da chave
        # no dicionário ou se a chave
        # não existir, retorna o
        # segundo argumento
        print mat.get((lin, col), 0),
    print
0 0 0 0 0 0 0 0 0 0 0 0
9 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 4 0 0
0 0 0 0 0 0 0 3 0 0 0 0
0 0 0 0 0 0 5 0 0 0 0 0
0 0 0 0 6 0 0 0 0 0 0 0

Gerando a matriz esparsa:

In [19]:
# Matriz em forma de string
matriz = '''0 0 0 0 0 0 0 0 0 0 0 0
9 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 4 0 0
0 0 0 0 0 0 0 3 0 0 0 0
0 0 0 0 0 0 5 0 0 0 0 0
0 0 0 0 6 0 0 0 0 0 0 0'''

mat = {}

# Quebra a matriz em linhas
for lin, linha in enumerate(matriz.splitlines()):

    # Quebra a linha em colunas
    for col, coluna in enumerate(linha.split()):

        coluna = int(coluna)
        # Coloca a coluna no resultado,
        # se for diferente de zero
        if coluna:
            mat[lin, col] = coluna

print mat
# Some um nas dimensões pois a contagem começa em zero
print 'Tamanho da matriz completa:', (lin + 1) * (col + 1)
print 'Tamanho da matriz esparsa:', len(mat)
{(5, 4): 6, (3, 7): 3, (1, 0): 9, (4, 6): 5, (2, 9): 4}
Tamanho da matriz completa: 72
Tamanho da matriz esparsa: 5

A matriz esparsa é uma boa solução de processamento para estruturas em que a maioria dos itens permanecem vazios, como planilhas, por exemplo.

Verdadeiro, falso e nulo

Em Python, o tipo booleano (bool) é uma especialização do tipo inteiro (int). O verdadeiro é chamado True e é igual a 1, enquanto o falso é chamado False e é igual a zero.

Os seguintes valores são considerados falsos:

  • False (falso).
  • None (nulo).
  • 0 (zero).
  • '' (string vazia).
  • [] (lista vazia).
  • () (tupla vazia).
  • {} (dicionário vazio).
  • Outras estruturas com o tamanho igual a zero.

São considerados verdadeiros todos os outros objetos fora dessa lista.

O objeto None, que é do tipo NoneType, do Python representa o nulo e é avaliado como falso pelo interpretador.

Operadores booleanos

Com operadores lógicos é possível construir condições mais complexas para controlar desvios condicionais e laços.

Os operadores booleanos no Python são: and, or, not, is e in.

  • and: retorna um valor verdadeiro se e somente se receber duas expressões que forem verdadeiras.
  • or: retorna um valor falso se e somente se receber duas expressões que forem falsas.
  • not: retorna falso se receber uma expressão verdadeira e vice-versa.
  • is: retorna verdadeiro se receber duas referências ao mesmo objeto e falso em caso contrário.
  • in: retorna verdadeiro se receber um item e uma lista e o item ocorrer uma ou mais vezes na lista e falso em caso contrário.

O cálculo do valor resultante na operação and ocorre da seguinte forma: se a primeira expressão for verdadeira, o resultado será a segunda expressão, senão será a primeira. Já para o operador or, se a primeira expressão for falsa, o resultado será a segunda expressão, senão será a primeira. Para os outros operadores, o retorno será do tipo bool (True ou False).

Exemplos:

In [20]:
print 0 and 3 # Mostra 0
print 2 and 3 # Mostra 3

print 0 or 3 # Mostra 3
print 2 or 3 # Mostra 2

print not 0 # Mostra True
print not 2 # Mostra False
print 2 in (2, 3) # Mostra True
print 2 is 3 # Mostra False
0
3
3
2
True
False
True
False

Além dos operadores booleanos, existem as funções all(), que retorna verdadeiro quando todos os itens forem verdadeiros na sequência usada como parâmetro, e any(), que retorna verdadeiro se algum item o for.

In [1]:
 
Out[1]: