Instruções

A instrução de atribuição do Python permite ter uma lista como destino da atribuição. Já tinha visto noutras linguagens: no PHP e no Prolog. Eis um exemplo em Python, onde a atribuição à lista a,b premite fazer a troca das variáveis, sem variável auxiliar:

>>> a=2
>>> b=5
>>> a,b=b,a
>>> print a, b
5 2

A instrução pass é uma instrução nula, não executa nenhuma operação, e é útil para quando a sintaxe obriga à existência de uma instrução num local onde não pretendemos ação alguma.

def f(arg): pass    # a function that does nothing (yet)

class C: pass       # a class with no methods (yet)

A instrução del pemite apagar uma lista de objetos. As variáveis a e b do exemplo acima, podem ser apagadas da forma seguinte:

del a,b

A instrução print imprime um objeto ou uma lista de objetos.

>>> a=2
>>> b=5
>>> print a, b
2 5

A instrução return permite devolver um objeto ou uma lista de objetos, como resultado de uma função.

A instrução yield é usada com funções geradoras. Para perceber a instrução yield é preciso perceber o que são funções geradoras (generators). Uma função geradora é semelhante a um iterável, mas é criada on-the-fly, e o seu valor só pode ser usado uma vez, pois não fica guardado. A instrução yield faz o retorno de uma finção geradora e, nesse contexto, é semelhante a um return.

>>> def createGenerator():
...     mylist = range(3)
...     for i in mylist:
...         yield i*i
...
>>>
>>> mygenerator = createGenerator() # create a generator
>>>
>>> print(mygenerator) # mygenerator is an object!

>>> for i in mygenerator:
...      print(i)
...
0
1
4

As instruções break e continue podem ser usadas apenas no âmbito de instruções for e while.

A instrução global cria identificadores globais.

A instrução exec permite a execução dinâmica de código Python. Segue-se um exemplo de execução de código que está contido numa string.

>>> mycode = 'print "hello world"'
>>> exec(mycode)
hello world

Expressões e curiosidades

Começo pela curiosidade. E digo curiosidade, porque penso que é a primeira linguagem de programação onde vejo esta construção. Há outras linguagens pelas quais nunca incursei, como o Ruby, ou incursei pouco, como o Perl, que talvez permitam este tipo de construções, mas nunca vi. A sintaxe seguinte permite criar uma lista de valores que é um subconjunto de uma progressão aritmética.

>>> a = 42
>>> b = list(a + i for i in range(10))
>>> b
[42, 43, 44, 45, 46, 47, 48, 49, 50, 51]

Ou ainda:

>>> list(map(lambda x: 2*x, (a + i for i in range(10))))
[84, 86, 88, 90, 92, 94, 96, 98, 100, 102]

Passemos às expressões. Nas expressões aritméticas, as conversões são feitas sempre para cima, antes de operar. “Para cima” significa, que entre dois operandos de tipos diferentes, a conversão é feita para o tipo “maior”, sendo a sequência crescente a seguinte: int, long, float, complex. Os booleanos são inteiros. A unidade imaginária é o j.

>>> 5+True
6
>>> True + (2.5+3j)
(3.5+3j)

Segundo o manual do Python, as expressões podem ser as seguintes, sendo algumas delas apresentadas em sintaxe BNF:

  • Conversões aritméticas
    • Átomos
    • Identificadores
    • Literais
    • Lista entre parêntesis
    • Listas
    • Conjuntos e dicionários
    • Expressões geradoras
    • Conversões de strings
    • Expressões “yield”
  • Operações primárias
    primary ::=  atom | attributeref | subscription | slicing | call
    • Referências a atributos
    • Indexação
    • Cortes
    • Chamadas
  • Potência
    power ::=  primary ["**" u_expr]
  • Operações unárias
    u_expr ::=  power | "-" u_expr | "+" u_expr | "~" u_expr
  • Operações aritméticas
    m_expr ::=  u_expr | m_expr "*" u_expr | m_expr "//" u_expr | m_expr "/" u_expr
                | m_expr "%" u_expr
    a_expr ::=  m_expr | a_expr "+" m_expr | a_expr "-" m_expr
  • Operações de deslocamento
    shift_expr ::=  a_expr | shift_expr ( "<<" | ">>" ) a_expr
  • Operações bit a bit
    and_expr ::=  shift_expr | and_expr "&" shift_expr
    xor_expr ::=  and_expr | xor_expr "^" and_expr
    or_expr  ::=  xor_expr | or_expr "|" xor_expr
  • Comparações
    comparison    ::=  or_expr ( comp_operator or_expr )*
    comp_operator ::=  "<" | ">" | "==" | ">=" | "<=" | "<>" | "!="
                       | "is" ["not"] | ["not"] "in"
  • Operações booleanas
    or_test  ::=  and_test | or_test "or" and_test
    and_test ::=  not_test | and_test "and" not_test
    not_test ::=  comparison | "not" not_test
  • Expressões condicionais
    conditional_expression ::=  or_test ["if" or_test "else" expression]
    expression             ::=  conditional_expression | lambda_expr
  • Lambdas
    lambda_expr     ::=  "lambda" [parameter_list]: expression
  • Expressões com listas
    expression_list ::=  expression ( "," expression )* [","]

A tabela de precedências dos operadores, do mais fraco para o mais forte, é a seguinte:

Operator Description
lambda Lambda expression
ifelse Conditional expression
or Boolean OR
and Boolean AND
not x Boolean NOT
in, not in,
is, is not, <,
<=, >, >=, <>, !=, ==
Comparisons, including membership
tests and identity tests
| Bitwise OR
^ Bitwise XOR
& Bitwise AND
<<, >> Shifts
+, – Addition and subtraction
*, /, //, % Multiplication, division, remainder
[8]
+x, -x, ~x Positive, negative, bitwise NOT
** Exponentiation [9]
x[index], x[index:index],
x(arguments…), x.attribute
Subscription, slicing,
call, attribute reference
(expressions…),
[expressions…],
{key: value…},
`expressions…`
Binding or tuple display,
list display,
dictionary display,
string conversion

Funções predefinidas II

Eis a lista de funções predefinidas do Python atualmente.

Segue-se a exposição de algumas dessas funções de âmbito mais geral. As primeiras funções já foram apresentadas no artigo anterior.

As funções chr() e ord() convertem uma letra ASCII no seu valor numérico e vice-versa.

>>> chr(65)
'A'
>>> ord('B')
66
>>> chr(225)
'\xe1'

As funções complex(), str(), int(), long() e float() convertem string para número ou vice-versa.
A função hex() converte um inteiro para o formato hexadecimal.
A função oct() converte um inteiro para o formato octal.

>>> complex("5+2j")
(5+2j)
>>> str(3+6)
'9'
>>> int("4")
4
>>> float("3.14")
3.14
>>> hex(1234)
'0x4d2'
>>> oct(123)
'0173'

divmod(a,b) calcula a divisão inteira e o resto da divisão inteira entre dois números (a//b,a%b).

>>> divmod(7,3)
(2, 1)

enumerate(sequence, start=0) devolve uma sequência enumerada

>>> seasons = ['Spring', 'Summer', 'Fall', 'Winter']
>>> list(enumerate(seasons))
[(0, 'Spring'), (1, 'Summer'), (2, 'Fall'), (3, 'Winter')]
>>> list(enumerate(seasons, start=1))
[(1, 'Spring'), (2, 'Summer'), (3, 'Fall'), (4, 'Winter')]

A função eval() é semelhante à função homónima do Javascript: avalia uma expressão contida numa string.

>>> x = 1
>>> print eval('x+1')

O comando exec() permite executar código contido numa string. A função execfile() executa código contido num ficheiro.

>>> exec("x=3")
>>> print x
3

As funções file() e open() permitem criar e/ou abrir um ficheiro, mas a última é preferível.
A função format(value[, format_spec]) converte um valor para um formato definido por format_spec (ver documentação).

>>> s = "python string!"
b = "i am a {0}".format(s)
>>> a =  "i am a %s" % s
print "--{:^30}--".format(s)
>>> b = "i am a {0}".format(s)
>>> print a
'{0}{1}{0}'.format('abra', 'cad')
i am a python string!

>>> print b
i am a python string!
>>> print "--{:^30}--".format(s)
'Coordinates: {latitude}, {longitude}'.format(**coord)

--        python string!        --
>>>
>>> '{2}, {1}, {0}'.format('a', 'b', 'c')
'c, b, a'
>>>
>>> '{0}{1}{0}'.format('abra', 'cad')
'abracadabra'
>>>
>>> 'Coordinates: {latitude}, {longitude}'.format(latitude='37.24N', longitude='-115.81W')
'Coordinates: 37.24N, -115.81W'
>>>
>>> coord = {'latitude': '37.24N', 'longitude': '-115.81W'}
>>> 'Coordinates: {latitude}, {longitude}'.format(**coord)
'Coordinates: 37.24N, -115.81W'

globals() devolve um dicionário (objeto JSON) com a tabela de símbolos globais.
locals() devolve um dicionário (objeto JSON) com a tabela de símbolos locais.

>>> globals()
{'__builtins__': <module '__builtin__' (built-in)>, '__name__': '__main__', '__doc__': None, '__package__': None}
>>> locals()
{'__builtins__': <module '__builtin__' (built-in)>, '__name__': '__main__', '__doc__': None, '__package__': None}

len() devolve o número de elementos de um objeto.

>>> len("Olá")
3
>>> len([1,3,5])
3
>>> len(globals())
4

map(function, iterable, …) aplica uma função aos valores de um iterável.
max(iterable[, key]) ou max(arg1, arg2, *args[, key]) determinam o máximo de um conjunto de elementos.
min(iterable[, key]) ou min(arg1, arg2, *args[, key]) determinam o máximo de um conjunto de elementos.
sum(iterable[, start]) soma os elementos de um iterável.

>>> map(lambda x: 2*x, [1,2,4,6,2,3])
[2, 4, 8, 12, 4, 6]
>>> max([1,2,4,6,2,3])
6
>>> min([1,2,4,6,2,3])
1
>>> sum([1,2,4,6,2,3])
18

next(iterator[, default]) obtém o próximo elemento de um iterador.

pow(x, y[, z]) calcula a potÊncia de x elevado a y módulo z, de forma eficiente. z é opcional, e nesse caso pode calcular-se x ** y.

>>> pow(2,3,5)
3
>>> pow(2,3)
8
>>> 2**3
8

print(*objects, sep=’ ‘, end=’\n’, file=sys.stdout) imprime objetos num fluxo (stream).

range() cria um intervalo de inteiros.

>>> range(10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> range(5,10)
[5, 6, 7, 8, 9]
>>> range(0, -10, -1)
[0, -1, -2, -3, -4, -5, -6, -7, -8, -9]

O Python foi criado com o nome de um grupo de animadores britânicos, tal como se percebe pelo exemplo da função raw_input().

>>> s = raw_input('--> ')
--> Monty Python's Flying Circus
>>> s
"Monty Python's Flying Circus"

reduce(function, iterable[, initializer]) aplica uma função de dois arguemntos, iterativamente a um iterável. Por exemplo, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calcula ((((1+2)+3)+4)+5).

>>> def soma(x,y):
...   return x+2*y
...
>>> reduce(soma, [1, 2, 3, 4, 5])
29

round() arredonda um número.

>>> round(3.14)
3.0
>>> round(3.14,1)
3.1
>>> round(3.7)
4.0

frozenset, list, set, tuple e dict são funções que permitem criar iteráveis ou coleções.

sorted(iterable[, cmp[, key[, reverse]]]) ordena um iterável.

>>> sorted( [1,2,4,6,2,3], cmp=lambda x,y: cmp(x, y) )
[1, 2, 2, 3, 4, 6]
>>> sorted( [1,2,4,6,2,3], cmp=lambda x,y: cmp(y, x) )
[6, 4, 3, 2, 2, 1]

tuple([iterable]) cria um tuplo a partir de um iterável.

>>> tuple("xpto")
('x', 'p', 't', 'o')

A função type(object) obtém o tipo de um objeto.

>>> type("xpto")
<type 'str'>
>>> type([1,2,4,6,2,3])
<type 'list'>
>>> type(3+6j)
<type 'complex'>

A função type(name, bases, dict) pode ser usada com 3 prâmetros. Nesse caso cria uma classe. As duas instruções seguintes são equivalentes.

>>> class X(object):
...     a = 1
...
>>> X = type('X', (object,), dict(a=1))

unichr(i) devolve a string Unicode, cujo código é i.

zip([iterable, …]) cria uma lista de tuplos emparelhados pelo índice dos argumentos. A lista gerada tem o comprimento do iterável mais curto.

>>> zip([1,2,3],"abc")
[(1, 'a'), (2, 'b'), (3, 'c')]
>>> zip([1,2,3,4,5,6],"xpto")
[(1, 'x'), (2, 'p'), (3, 't'), (4, 'o')]

Funções predefinidas

Para além do manual de referência, que é relativamente árido nalguns capítulos, o Python tem um manual sobre a Biblioteca Standard, que começa por apresentar as funções predefinidas da linguagem.

A função abs() calcula o valor absoluto de inteiros, reais e complexos.

>>> abs(-3)
3
>>> abs(-7.5)
7.5
>>> abs(3+4j)
5.0

A função all() verifica se todos os elementos de um iterável são verdade.
A função any() verifica se algum elemento de um iterável é verdade.

>>> all([1,0])    # array composto por 1 e 0
False
>>> all([1,4])    # array composto por 1 e 4
True
>>> any([1,0])
True
>>> any([0,0,False])
False
>>> any([True,False])
True

O tipo abstrato basestring() não pode ser instanciado, é a superclasse de str e unicode, mas pode ser usado para testar se um objeto é do tipo str ou unicode.

>>> isinstance("Ola", basestring)
True
>>> isinstance("Olá Mundo", basestring)
True
>>> isinstance(123, basestring)
False

A função bin() devolve uma string com a representação binária de um inteiro. Ainda ninguém desafiou o guru do Python a mostrar a representação binária de um real? Em C pode ser feita assim:

float x = 3.5;
printf("%X", *(int*)&x);

bool() avalia um objeto como booleano.

>>> bin(123)
'0b1111011'
>>> bool(2)
True
>>> bool(0)
False
>>> bool()
False

A função bytearray() devolve o array de bytes que compõem uma string. Se a string estiver em unicode, é necessário passar a codificação como parâmetro. Ver documentação.

>>> bytearray("abc")
bytearray(b'abc')
>>>
>>> s = "Olá Mundo"
>>> ":".join("{:02x}".format(ord(c)) for c in s)
'4f:6c:e1:20:4d:75:6e:64:6f'
>>>
>>> s = bytearray("Olá Mundo")
>>> ":".join("{:02x}".format(c) for c in s)
'4f:6c:e1:20:4d:75:6e:64:6f'

Mais funções no próximo artigo.

Classes

Depois de dois dias a nadar em seco, ou seja, a ler a documentação teórica e abstrata, no manual de referência, sobre o modelo de dados e o modelo de execução do Python, decidi intercalar esse estudo com exemplos práticos sacados ao acaso do stackoverflow.

Eis uma classe simples, que de classe pouco tem, tem apenas a sintaxe. Serve principalmente, para mostrar o funcionamento do método __init__(), que funciona como um construtor: é invocado no momento da criação e antes do objeto ser devolvido. O primeiro parâmetro é o self, ou seja o próprio objeto (object) – pelo que, na minha opinião, deveria ser omitido da sintaxe – e os parâmetros seguintes, são os argumentos que são passados na criação do objeto.

class Soma(object):
  def __init__(self, x, y):
    self.z = x + y

q = Soma(7, 8)
print q.z
15

Objetos

Exemplo de uma sessão em Python que mostra algumas funções de manipulação de objetos

Python 2.7.12 (default, Sep  6 2016, 18:21:48)
[GCC 5.4.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> type(4)
<type 'int'>
>>> type("""a""")
<type 'str'>
>>> type(type("""a"""))
<type 'type'>
>>> id(45)
15021312
>>> id(34)
15019584
>>> exit()

De notar que o tipo de um objeto também é um objeto, de tipo type.
A função id() devolve o id do objeto, que pode ser pensado como o seu endereço em memória.

Os inteiros com mais de 32 bits – para além de do intervalo [-2147483648, 2147483647] – são ineiros longos e não têm limite de tamanho, não estão limitados a 64 bits como no Java ou no C.

Segue-se um exemplo de utilização de números complexos em Python, em modo interativo

>>> x=3
>>> type(x)
<type 'int'>
>>> print(x)
3
>>> x+=2j
>>> type(x)
<type 'complex'>
>>> print(x.real)
3.0
>>> type(x.real)
<type 'float'>
>>> print(x.imag)
2.0
>>> print(x)
(3+2j)

De notar que as componentes de um complexo são sempre float, que é um real de 64 bits.

O Python permite cortar sequências (tuplos, strings, listas, etc.) dinamicamente. Por exemplo, a[i:j] seleciona todos os índices k tais que i <= k < j.

Nalguns casos, é possível um corte estendido, com um terceiro parâmetro k tal que a[i:j:k] seleciona todos os elementos de a com índice x onde x = i + n*k, n >= 0 e i <= x < j.

A sequência resultado é reindexada a partir do 0.

Linhas lógicas e físicas

À partida, no Python cada instrução ocupa uma linha.

O Python distingue linhas físicas de linha lógicas. Uma linha lógica é uma linha de código, que pode, em casos especiais, prolongar-se por várias linhas físicas.

Prolongamento explícito: utiliza a barra invertida

if 1900 < year < 2100 and 1 <= month <= 12 \
   and 1 <= day <= 31 and 0 <= hour < 24 \
   and 0 <= minute < 60 and 0 <= second < 60:   # A valid date
        return 1

Prolongamento implícito: expressões entre parêntesis curvos, retos, ou chavetas.

month_names = ['Januari', 'Februari', 'Maart',      # This is 
               'April',   'Mei',      'Juni',       # Dutch for
               'Juli',    'Augustus', 'September',  # months of
               'Oktober', 'November', 'December']   # the year

Olá Mundo

Para fazer um programa que imprima um caráter com acento, é preciso usar uma codificação excecional. O Unicode devia ser a regra e não a exceção, mas no Python é assim.

Versão sem acentos, num ficheiro batch em Linux

#!/usr/bin/python

print("Ola Mundo")
print('Mais uma frase\n')

Versão Unicode

#!/usr/bin/python
# -*- coding: utf-8 -*-

print("Olá Mundo")
print('Mais uma frase: a fataça e o sururú\n')

Início

Comecei a olhar para o Python, a meio deste ano. É uma linguagem diferente daquelas a que estou habituado. A indentação (alinhamento) é obrigatória, e tem problemas (de fundo, de atitude política) com a codificação em Unicode.

Vou usar este sítio para colocar alguns programas que vá desenvolvendo, assim como algumas questões iniciais da sintaxe da linguagem que vá descobrindo, para servir de registo para o futuro.