Python, sendo uma linguagem de alto nível, suporta nativamente estruturas de dados complexas como listas e dicionários, entre outros.
Listas
Um aspecto muito interessante é que muitos tipos de estruturas de dados complexas têm uma forma sucinta para serem definidas. No caso das listas, estas podem ser criadas com parênteses rectos:
x=[1,2,3]
, (como aliás já tinha sido mostrado num post anterior.)
Obviamente, as listas podem ser aninhadas:
x=[ [1, 2], 3 ]
(uma lista de dois elementos onde o primeiro elemento é ele próprio uma lista (com os elementos 1 e 2) e o segundo elemento é o 3.
Assim, a avaliação da construção sintáctica
[ ... ] cria uma lista (uma instância de list) cujos elementos são dados pela avaliação do que está dentro dos parênteses. Uma lista vazia é naturalmente escrita com [].
Também é possível criar uma lista usando
list(). Mais, em python, para criar uma instância de uma classe
xpto deve-se escrever xpto(). i.e. ao definir uma classe C, fica implicitamente definida uma função com nome C, função essa que tem todas as propriedades das outras funções e é chamada da mesma forma.
Tuplos
Um tuplo é uma sequência ordenada de elementos cujos tipos podem arbitrários e até diferentes. Tal como para as listas, existem formas sucintas de criar tuplos. Os tuplos criam-se com parêntesis.
Exemplo:
() <- tuplo vazio. Os parêntesis neste caso não são opcionais.
(100, 200, 300) <- tuplo com 3 elementos
(3.14, ) <- forma de criar um tuplo com apenas um elemento. a virgula a seguir ao número NÃO é um engano. Ela existe pois de outra forma seria impossível distinguir da aplicação normal de parêntesis para avaliar algo primeiro. Tal como nas listas, pode-se chamar o construtor de tuplo, que é a função tuple(). Esta função recebe no máximo um argumento e, quando esse argumento é um iterável, o tuplo contem os mesmos elementos do iterável.
Exemplo:
tuple('wow'), retorna um tuplo igual a
('w', 'o', 'w') pois uma string é um tipo de iteravel cujos elementos são os seus caracteres. Para ter um tuplo com 1 único elemento igual a 'wow' deve-se usar
('wow', ) ou então
x = 'ola'
tuplo = ( x, )
Dicionários
Um dicionário é um tipo de container (um objecto que contém outros objectos) que permite mapear uma colecção arbitrária de objectos a uma colecção arbitrária de outros objectos, chamados chaves. Noutros contextos, estas estruturas são também chamadas de mapas ou hash tables.
Estes também possuem um açucar sintáctico para a sua definição:
{'x':42, 'y':3.14, 'z':7}
esta expressão tem como valor um dicionário que mapeia a string 'x' ao elemento 42, a string 'y' ao número 3.14 etc. Para definir um dicionário vazio é, como se espera, {}
Também se pode criar um dicionáriochamando o seu construtor. Irei exemplificar para aproveitar e apresentar outra característica da linguagem:
dict(x=42, y=3.14, z=7)
Esta expressão cria exactamente o mesmo dicionário que a anterior. O que quero apresentar é que, na chamada a uma função o python suporta
named arguments i.e. para além dos argumentos posicionais normais, pode-se passar também novos argumentos no formato nome=valor. No caso particular da função dict, ela usa esses argumentos nomeados para criar um dicionário contendo um mapeamento entre os seus nomes ('x','y','z') e os seus valores.
No caso geral, imagine-se a seguinte funcão:
def divide(divisor, dividend):
return dividend / divisor
Esta função pode ser chamada de várias formas:
divide(20,5) , a chamada "normal" onde os parametros formais são ligados aos valores pela sua posição relativa (20 fica ligado a divisor e 5 fica ligado a dividend).
No entanto, ela também pode ser chamada assim:
divide(dividend=94, divisor=12)
Um uso excelente para os named arguments, é a de passar parâmetros opcionais. Considere-se a seguinte função:
def f(middle, begin='init', end='finis'):
return begin+middle+end
Esta função apresenta vários outros conceitos. Ao fazer a=b na lista de parâmetros formais, estamos a definir o valor de defeito como sendo b para o argumento com nome a, como em C++.
Segundo, tal como em Java, o + pode ser usado para concatenar strings mas, em python, o mecanismo é bastante mais poderoso, sendo parecido com o de C++.
ao fazer a+b, o Python chama o método __add__ sobre o objecto a com argumento b. Claro que este método pode ser chamado explícitamente:
>>> 'a'+'b'
'ab'
>>> 'a'.__add__('b')
'ab'
>>>
Aproveito também para dizer que practicamente todos os mecanismos "especiais" do python podem ser alterados pois por trás existem sempre chamadas a método especiais. Métodos especiais devem ser chamados __nome__ (são dois underscores antes e depois). Todos os operadores, comparações, conversões implícitas entre tipos são executadas por métodos especiais. A única excepção existente é para a atribuição a=b que não pode ser
overloaded e tem sempre a mesma semântica.
Voltando ao exemplo da função f. Esta função pode ser chamada das seguintes formas:
>>> f('ola')
initolafinis
>>> f('ola',end=' mundo')
initola mundo
>>> f('ola',end=' mundo', begin='')
ola mundo
>>>
Voltando ainda aos containers (dicionários e listas etc.), podemos obter os seus elementos usando o operador de indexação []. Alguns exemplos:
>>> listaMaravilha=[1,2,3,4]
>>> listaMaravilha
[1, 2, 3, 4]
>>> listaMaravilha[3]
4
Note-se que as listas sao indexadas a partir do 0'
>>> listaMaravilha[-1]
4
'Mas tambem se pode usar indices negativos. O significado é o de comecar a partir do fim. Veja-se:
>>> listaMaravilha[-2]
3
No entanto, os indíces admissíveis são apenas entre [-N, N+1], onde N é o número de elementos.
>>> listaMaravilha[-5]
Traceback (most recent call last):
File "", line 1, in
IndexError: list index out of range
>>> listaMaravilha[4]
Traceback (most recent call last):
File "", line 1, in
IndexError: list index out of range
>>>
Da mesma forma se pode indexar e até alterar os valores de um dicionário.
>>> foo={'ola':1, 'mundo':2}
>>> foo[0]
Traceback (most recent call last):
File "", line 1, in
KeyError: 0
>>> foo['mundo']
2
>>> foo['mundo']=3
>>> foo['mundo']
3
>>>
>>> foo
{'ola': 1, 'mundo': 3}
>>> foo['nova chave']=43
>>> foo
{'ola': 1, 'nova chave': 43, 'mundo': 3}
>>>