1. Conceitos básicos#

1.1. Programas como textos#

Um programa é simplesmente um texto escrito numa linguagem de programação, por exemplo na linguagem Python.

Na linguagem Python, esse texto é interpretável por um computador como um conjunto de “comandos” de “ordens” para serem executados.

Quando “corremos” ou “executamos” um programa essas ordens são executadas (a grande velocidade, diga-se) e o programa produz um resultado.

Os comandos são executados um a um à medida que aparecem no texto (“de cima para baixo”), embora esta ordem possa ser alterada por indicações especiais capazes de repetir comandos ou executar comandos em alternativa, como veremos mais tarde.

1.2. Objetos e nomes#

1.2.1. Objetos fundamentais#

Para as primeiras impressões sobre a linguagem Python começaremos não por escrever e executar pequenos programas mas por usar um modo interativo chamado a Python Shell.

Neste modo interativo, escrevem-se comandos que são executados imediatamente originando um resultado.

Tendo uma distribuição da linguagem Python instalada, podemos iniciar uma Python shell numa janela de terminal (“linha de comando”, “shell”).

No sistema Windows, por exemplo, usando a Anaconda Prompt da distribuição Anaconda escrevemos

python

para iniciar uma Python shell.

Como alternativa, podemos iniciar uma aplicação que contem uma Python shell chamada Idle, escrevendo

idle

Reconhece-se a Python shell por apresentar

>>>

a indicar que podemos escrever um comando do Python. Ao terminar o comando com Enter obtemos imediatamente uma resposta.

Vamos experimentar alguns comandos.

Muitas vezes, os comandos da linguagem Python consistem na manipulação daquilo que se designa genericamente por objetos (virtuais, claro).

Estes objetos são valores que estão representados na memória do computador, num determinado momento durante a execução do programa.

1.2.1.1. Números#

Números são uns dos objetos mais fundamentais da linguagem Python. Podemos usar a Python Shell como uma calculadora. Experimente estes comandos:

>>> 45 + 32
77
>>> 3.27 * 0.18
0.5886
>>> (1 + 5**0.5) / 2
1.618033988749895
>>>

Numa expressão envolvendo números, podemos usar (vários níveis de) parêntesis curvos () e as seguintes operações:

Operador

Operação

+

adição

-

subtração

*

multiplicação

/

divisão

**

potenciação

%

resto da divisão

As regras de prioridade são: ** tem maior prioridade do que * / que têm maior prioridade do que + -. Em caso de “empate” e sem parêntesis, os cálculos são feitos da esquerda para a direita.

>>> - (4.2 * 0.01)**(1/3)
-0.347602664488645
>>> (1 + 5**(1/2)) / 2
1.618033988749895
>>> 5 % 3
2

Naturalmente, podemos trabalhar com números com casas decimais, designados genericamente como números em vírgula flutuante.

Na gíria é muitas vezes usada a designação floats.

>>> 4.2 * 0.01
0.042
>>> 4.2 * 1e-2
0.042
>>> 4.2e3 - 2e2
4000.0

Note a utilização da representação “de engenharia”, por exemplo 4.2e3, equivalente a 4.2 x 103.

Atenção

Nos números em Python usa-se sempre um ponto decimal . (e não uma vírgula)

1.2.1.2. Strings#

Um outro tipo de objetos fundamentais num programa são as strings.

Estas são pequenos textos entre "" ou ''.

São sequências de caracteres (além das letras, os espaços e pontuação, desde que estejam entre as aspas, contam como caracteres).

>>> "Hoje fiquei em casa"
'Hoje fiquei em casa'
>>> 'Mas fiz uns programas'
'Mas fiz uns programas'
>>> "Com muita determinação"
'Com muita determinação'
>>>

É indiferente usar " ou '. Se precisarmos de usar um tipo de aspas “no interior” de uma string podemos usar o outro tipo para delimitar a string:

>>> "Hoje não fui p'rá FCUL"
"Hoje não fui p'rá FCUL"
>>>

Podemos “somar” strings e multiplicar strings por um número inteiro:

>>> 'Hoje vai' + " chover"
'Hoje vai chover'
>>> "Blá" * 4
'BláBláBláBlá'
>>>

Mas não podemos fazer certo tipo de operações entre números e strings:

>>> 2 + "muito"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
    2 + "muito"
TypeError: unsupported operand type(s) for +: 'int' and 'str'
>>>

Nem mesmo quando um número é, realmente, uma string:

>>> 4 / "2"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for /: 'int' and 'str'
>>>

1.2.1.3. Objetos booleanos#

No Python existem dois objetos que representam os conceitos de verdadeiro e falso. São eles True e False (começam por maiúscula).

Estes objetos surgem como resul11tado de expressões lógicas, isto é, cujo resultado pode ser considerado falso ou verdadeiro.

>>> 5 > 5
False
>>> 7 > 5
True
>>> 2 < 1
False
>>> 4.0 == 16**0.5
True
>>> 5 != 5
False

Os símbolos == e != são pouco usuais: eles significam igual e diferente em comparações lógicas, respetivamente.

O conjunto dos operadores de comparação é o seguinte:

operador

significado

>

maior

<

menor

>=

maior ou igual

<=

menor ou igual

==

igual a (Nota: são dois sinais de igual consecutivos)

!=

diferente de

E podemos usar as seguintes operações lógicas:

operador

significado

and

conjunção (e)

or

disjunção (ou)

not

negação (não)

Por exemplo:

>>> (5 >= 5) and not (7 > 10)
True

1.2.1.4. Números complexos#

Finalmente, o Python permite usar números complexos.

Usando a letra j no fim de um número indicamos a parte imaginária de um número complexo:

>>> 1j * 1j
(-1+0j)
>>> 2 + 3j + 4 + 7j
(6+10j)
>>> (3 + 2j) * (5 + 1j)
(13+13j)
>>>

1.2.1.5. Função type()#

Por vezes é necessário saber qual o tipo de um objeto ou do resultado de uma expressão.

A função type() dá como resultado o tipo do objeto ao qual é aplicada:

>>> type(36)
<class 'int'>
>>> type(3.14)
<class 'float'>
>>> type("Ha " * 5)
<class 'str'>
>>> type(5 >= 5)
<class 'bool'>

1.2.2. Atribuição de nomes a “objetos”#

Nota

Este é um dos mais fundamentais comandos em programação!

A forma geral é

<nome> = <expressão>

Vejamos um exemplo:

>>> a = 4
>>> b = 3.2
>>> c = a + b
>>> d = c ** 0.5
>>> a
4
>>> b
3.2
>>> c
7.2
>>> d
2.6832815729997477
>>>

Numa Python shell ou num programa, a atribuição de um nome ao resultado de uma expressão não produz imediatamente um resultado mas permite dar um nome a um valor para utilizar mais à frente.

Depois de uma atribuição, o nome pode ser usado em vez do valor do objeto (ou resultado de uma expressão). Mesmo em atribuições seguintes.

No exemplo anterior, os valores com os nomes ae b (respetivamente 4 e 3.2) foram usados no cálculo de uma expressão a + b ao qual foi dado o nome c.

Um exemplo com strings:

>>> hoje = "Hoje é quinta feira"
>>> mês = "Março"
>>> tudo = hoje + ' e estamos em ' + mês
>>> tudo
'Hoje é quinta feira e estamos em Março'
>>>

Que nomes podemos usar?

As regras são:

  1. Um nome é uma combinação de letras minúsculas ou maiúsculas (podendo ser acentuadas) ou dígitos (0 to 9) ou o underscore. Nomes como x, Km_1 ou velocidade_da_reaccao são exemplos válidos.

  2. Um nome não pode começar com um dígito. 1x é inválido, mas x1 é aceitável.

  3. Palavras usadas como comandos da linguagem (keywords) não são permitidas (por exemplo, for). Na documentação do Python pode-se encontrar uma lista com estas palavras “reservadas”.

  4. Não são permitidos espaços ou símbolos como !, @, #, % nos nomes.

Aviso

A partir deste ponto todos os exemplos serão baseados em programas e não numa Python shell.

Aconselha-se a familiarização com uma aplicação de edição e execução de programas, por exemplo o Visual Studio Code.

Um outro exemplo, mais útil, o cálculo do perímetro de um círculo, a partir do valôr do diâmetro:

pi = 3.1415
diâmetro = 10
perímetro = pi * diâmetro

perímetro
31.415000000000003

Podemos realizar várias atribuições de nomes na mesma linha. Para isso indicamos vários nomes do lado esquerdo do sinal = e (um mesmo número de) expressões do lado direito. Os nomes e as expressões são separados por vírgulas ,

Modificando um pouco o exemplo anterior para ilustrar esta técnica:

pi, diâmetro = 3.1415, 10

perímetro = pi * diâmetro

perímetro
31.415000000000003
# Comentários começam por #

# Podemos dar nomes a vários objetos
# de uma só vez:
a, b  =  3, "experiência"

a, b
(3, 'experiência')

Mais tarde veremos uma generalização desta técnica muito útil.

Já agora, linhas começadas por # são comentários.

Comentários são linhas completamente ignoradas durante a execução de um programa. Servem como notas importantes deixadas para que o autor do programa ou outras pessoas possam mais tarde, ao ler o programa, melhor comprender o que um programa está a fazer.

1.2.3. print()#

Um programa em Python é, como foi dito, uma sequência de comandos que são executados um a um, a grande velocidade, quando o programa é executado.

Ao contrário de uma Python shell, durante a execução de um programa os comandos não produzem resultados imediatamente. Por exemplo, executando este programa:

a = 4
b = 3.2
c = a + b
d = c ** 0.5

O resultado é o seguinte:

 

Num programa, podemos apresentar o valor que um objeto tem com a função print().

Um exemplo:

a = 4
b = 3.2
c = a + b
d = c ** 0.5
print(a)
print(b)
print(c, d)
4
3.2
7.2 2.6832815729997477

Embora este programa faça vários cálculos e atribuições de nome, o resultado visível da execução do programa resulta das funções print().

Como se viu com a última linha (print(c,d)) numa só função print() podemos apresentar vários objetos, ou valores associados a nomes ou expressões separado-os por vírgulas. No resultado de um programa é inserido um espaço entre as várias partes.

Usando print() com strings, as aspas são eliminadas.

hoje = "Hoje é quinta feira"
mês = "Março"
tudo = hoje + ' e estamos em ' + mês

print(hoje)
print(mês)
print(tudo)
Hoje é quinta feira
Março
Hoje é quinta feira e estamos em Março

1.2.4. Alteração dos objetos associados a um nome#

Durante a execução de um programa, os objetos associados a um mesmo nome podem variar:

a = 2
b = 3
c = 'Olá'

b = a + b
a = a + 1
c = a + b

print("a =", a)
print("b =", b)
print("c =", c)
a = 3
b = 5
c = 8

Para melhor compreender as mudanças que ocorrem nos valores atribuídos aos nomes de a, b e c no programa anterior, podemos modifica-lo, mostrando, com print(), os valores atualizados desses nomes, após cada atribuição. Associe cada print() a cada linha do resultado do programa e compreenda as diferentes alterações dos valores associados a cada nome:

a = 2
b = 3
c = 'Olá'
print("a =", a, "b =", b, "c =", c)

b = a + b
print("a =", a, "b =", b, "c =", c)
a = a + 1
print("a =", a, "b =", b, "c =", c)
c = a + b
print("a =", a, "b =", b, "c =", c)
a = 2 b = 3 c = Olá
a = 2 b = 5 c = Olá
a = 3 b = 5 c = Olá
a = 3 b = 5 c = 8

É claro que estas variações de nomes e valores ocorrem muito depressa.

A assimetria de uma atribuição de nome

Note-se que um comando de atribuição de nome é completamente assimétrico:

Dica

Do lado esquerdo do = fica apenas um nome.

Do lado direito fica uma expressão a calcular, seja ela qual for.

Repare que, em programação, é perfeitamente possível escrever a “falsidade matemática”

a = a + 1

Não se trata de dizer que o lado esquerdo é igual ao lado direito. Trata-se de calcular o lado direito e dar o nome que está do lado esquerdo. Estamos a dar uma ordem usa o valor de a, acrescenta 1 e dá o nome a ao resultado.

Mas, no Python, dá um erro escrever uma coisa como

2 * a + 4 = a

Resumo: à direita uma expressão, à esquerda o nome a dar ao resultado

1.2.5. Interpolação de valores em strings (“Strings f”)#

As strings podem ter valores “interpolados”, usando os nomes desses valores ou expressões. Para isso, usam-se {} para identificar em que sítio da string deve ficar cada valor e a string deve ter a letra f como prefixo. Um exemplo:

a = 4.8
b = 3.2
c = a + b

print(f'a é igual a {a}, mas b = {b}, enquanto que c = {c}')
a é igual a 4.8, mas b = 3.2, enquanto que c = 8.0

Um outro exemplo, introduzindo mais pormenores:

a, b  =  3, "experiência"

print(f"a = {a} b = {b}")

# print() deixa uma linha de intervalo
print()

a, b = 3, 4
print(f"a = {a} b = {b}\n")

# Podemos trocar dois nomes desta maneira
a, b = b, a
print('Depois de trocar a e b...')
print(f"a = {a} b = {b}")
a = 3 b = experiência

a = 3 b = 4

Depois de trocar a e b...
a = 4 b = 3

Nota: quando numa string aparece o caractere “especial” \n, este provoca uma linha suplementar quando a string é apresentada com a função print().

1.3. Funções e módulos#

1.3.1. Funções “integradas” na linguagem#

1.3.1.1. abs(), int()#

Além da função print(), as funções int(), que calcula a parte inteira de um número e abs(), que calcula o valor absoluto (módulo) de um número, fazem parte integrante da linguagem Python.

numero = -3.8
x = int(numero)
y = abs(numero)

print(numero, '\n')
print(x)
print(y)
-3.8 

-3
3.8

Podemos encontrar a lista destas funções na documentação oficial da linguagem Pyhton:

Python Built-in functions

1.3.2. Conversão entre tipos de objetos#

1.3.2.1. int(), float(), complex() e str()#

As funções int(), float(), complex() e str() fazem conversões para os vários tipos de objetos:

  • inteiros

  • floats

  • complexos (em que j é a unidade imaginária)

  • strings

x = 3.8

print(x,'\n')
print(int(x))
print(complex(x))
print(str(x))
3.8 

3
(3.8+0j)
3.8
s = '3.4e4'
f = float(s)
c = complex(s)

print(s, '\n')
print(f)
print(c)
3.4e4 

34000.0
(34000+0j)

As conversões nem sempre são possíveis…

s = 'Vamos ver...'
print(s, '\n')

print(float(s))
Vamos ver... 
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[22], line 4
      1 s = 'Vamos ver...'
      2 print(s, '\n')
----> 4 print(float(s))

ValueError: could not convert string to float: 'Vamos ver...'

1.4. Módulos: funções adicionais#

Além das funções integradas, existem muitos módulos contendo funções adicionais.

Estes módulos têm de ser importados para que as funções fiquem disponíveis.

Um exemplo é o módulo math que contem muitas funções (e algumas constantes) matemáticas:

import math

x = 2.0

y = math.log(x)
print('ln(2.0) =', y)

y = math.log10(x * 5)
print('ln10(2.0 * 5) =', y)

y = math.exp(x)
print('exp(2.0) =', y)

y = math.sin(x)
print('sin(2.0) =', y)
ln(2.0) = 0.6931471805599453
ln10(2.0 * 5) = 1.0
exp(2.0) = 7.38905609893065
sin(2.0) = 0.9092974268256817
y = math.sin(math.radians(90))
print('sin(90°) =', y)

print('pi =', math.pi)

print('e =', math.e)

y = math.sin(math.pi / 2.0)
print('sin(π / 2) =', y)
sin(90°) = 1.0
pi = 3.141592653589793
e = 2.718281828459045
sin(π / 2) = 1.0
y = math.factorial(100)
print('100! =', y)
100! = 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000

Leitura interessate sobre o módulo math

Um outro exemplo é o módulo calendar que contem muitas funções relacionadas com datas e calendário.

Um exemplo é a função weekday(), que, ao ser dado um ano, mês e dia, calcula um número que representa o dia da semana. (0 - seg, 1 - ter, 2 - qua, 3 - qui, 4 - sex, 5 - sab, 6 - dom)

import calendar

print(calendar.weekday(2017, 3, 30))
#nota: 0:seg 1:ter 2:qua 3:qui 4:sex 5:sab 6:dom
3

Outro exemplo é a função calendar(), que constrói uma string com um calendário de um determinado ano:

import calendar
print(calendar.calendar(2022))
                                  2022

      January                   February                   March
Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su
                1  2          1  2  3  4  5  6          1  2  3  4  5  6
 3  4  5  6  7  8  9       7  8  9 10 11 12 13       7  8  9 10 11 12 13
10 11 12 13 14 15 16      14 15 16 17 18 19 20      14 15 16 17 18 19 20
17 18 19 20 21 22 23      21 22 23 24 25 26 27      21 22 23 24 25 26 27
24 25 26 27 28 29 30      28                        28 29 30 31
31

       April                      May                       June
Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su
             1  2  3                         1             1  2  3  4  5
 4  5  6  7  8  9 10       2  3  4  5  6  7  8       6  7  8  9 10 11 12
11 12 13 14 15 16 17       9 10 11 12 13 14 15      13 14 15 16 17 18 19
18 19 20 21 22 23 24      16 17 18 19 20 21 22      20 21 22 23 24 25 26
25 26 27 28 29 30         23 24 25 26 27 28 29      27 28 29 30
                          30 31

        July                     August                  September
Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su
             1  2  3       1  2  3  4  5  6  7                1  2  3  4
 4  5  6  7  8  9 10       8  9 10 11 12 13 14       5  6  7  8  9 10 11
11 12 13 14 15 16 17      15 16 17 18 19 20 21      12 13 14 15 16 17 18
18 19 20 21 22 23 24      22 23 24 25 26 27 28      19 20 21 22 23 24 25
25 26 27 28 29 30 31      29 30 31                  26 27 28 29 30

      October                   November                  December
Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su      Mo Tu We Th Fr Sa Su
                1  2          1  2  3  4  5  6                1  2  3  4
 3  4  5  6  7  8  9       7  8  9 10 11 12 13       5  6  7  8  9 10 11
10 11 12 13 14 15 16      14 15 16 17 18 19 20      12 13 14 15 16 17 18
17 18 19 20 21 22 23      21 22 23 24 25 26 27      19 20 21 22 23 24 25
24 25 26 27 28 29 30      28 29 30                  26 27 28 29 30 31
31

1.5. Exemplo: Raízes da equação do 2º grau#

Calcular as soluções da equação do 2º grau

\(a x^2 + b x + c = 0\)

ou seja

Dados \(a, b\) e \(c\), calcular

\(x_1 = \frac{-b + \sqrt{b^2 -4 a c}}{2 a}\) e \(x_2 = \frac{-b - \sqrt{b^2 -4 a c}}{2 a}\)

# Este programa calcula x tal que a x2 + b x + c = 0
# testar com os seguintes valores (1,4,1) , (1,2,1) , (1,1,1)

a, b, c = 1, 4, 1

# cálculo do discriminante
delta = b**2 - 4.0 * a * c
rdelta = delta**0.5

x1 = (- b + rdelta) / (2.0 * a)
x2 = (- b - rdelta) / (2.0 * a)

print('a =', a, 'b =', b, 'c =', c, '\n')
print(f"x1 ={x1}, x2 = {x2}")
a = 1 b = 4 c = 1 

x1 =-0.2679491924311228, x2 = -3.732050807568877

Da matemática, sabemos que uma equação do segundo grau pode ter 2 soluções reais, uma solução real “dupla”, ou duas soluções complexas, que neste caso serão complexos conjugados.

Podemos correr o programa várias vezes, para diferentes valores de \(a\), \(b\), \(c\), tentando obter as três situações. Ao fazer isto estamos a testar o programa.

Para fazer estes testes, basta modificar as linhas que definem os valores para a, b e c e voltar a executar o program.

Com a = 1, b = 4, c = 1:

a = 1 b = 4 c = 1 

x1 =-0.2679491924311228, x2 = -3.732050807568877

Com a = 1, b = 2, c = 1:

a = 1 b = 2 c = 1 

x1 =-1.0, x2 = -1.0

Com a = 1, b = 1, c = 1:

a = 1 b = 1 c = 1 

x1 =(-0.49999999999999994+0.8660254037844386j), x2 = (-0.5-0.8660254037844386j)

O programa funciona e parece dar resultados corretos para as três situações pretendidas (embora se note um pequeno erro no caso das duas soluções complexas que deveriam ser, exatamente, dois complexos conjugados).

No entanto, seria mais adequado se o programa pudesse apresentar uma pequena mensagem que indicasse em qual das três situações está o resultado (2 soluções reais ou uma solução real dupla ou duas soluções complexas).

(Podemos também tentar corrigir o pequeno erro).

Para isto, o programa deve ter um comportamento diferente, consoante o tipo de resultado.

Da matemática, sabemos que o que define o tipo de resultado é o valor do “discriminante”, \(\Delta = b^2 - 4 a c\).

  • quando \(\Delta > 0\) temos duas soluções reais.

  • quando \(\Delta = 0\) temos uma solução real (solução dupla).

  • quando \(\Delta < 0\) temos duas uma soluções complexas (complexos conjugados).

Podemos reescrever o programa de modo a realizar o cálculo das soluções e apresentar uma mensagem de um modo diferente, consoante o valor de \(\Delta\) ?

1.6. Execução alternativa#

1.6.1. Alternativa if...else#

A linguagem Python permite a execução alternativa de blocos de comandos.

Continuando com o exemplo anterior, vamos primeiro distinguir o caso das soluções reais (\(\Delta \geqslant 0\)) do caso das soluções complexas (\(\Delta < 0\)).

# Este programa calcula x tal que a x2 + b x + c = 0
# testar com os seguintes valores (1,4,1) , (1,2,1) , (1,1,1)

a, b, c = 1, 4, 1

# cálculo do discriminante
delta = b**2 - 4.0 * a * c

# separar soluções reais das complexas
if delta < 0.0:
    rdelta = (-delta)**0.5 * 1j
    print('Soluções complexas:')
else:
    rdelta = (delta)**0.5
    print('Soluções reais:')

x1 = (- b + rdelta) / (2.0 * a)
x2 = (- b - rdelta) / (2.0 * a)

print(f'Para a = {a}  b = {b}  c = {c}')
print(f"x1 = {x1}\nx2 = {x2}")
Soluções reais:
Para a = 1  b = 4  c = 1
x1 = -0.2679491924311228
x2 = -3.732050807568877

Testando agora o programa para as três situações possíveis:

\(\Delta > 0\):

Soluções reais:
Para a = 1  b = 4  c = 1
x1 = -0.2679491924311228
x2 = -3.732050807568877

\(\Delta = 0\):

Soluções reais:
Para a = 1  b = 2  c = 1
x1 = -1.0
x2 = -1.0

\(\Delta < 0\):

Soluções complexas:
Para a = 1  b = 1  c = 1
x1 = (-0.5+0.8660254037844386j)
x2 = (-0.5-0.8660254037844386j)

O programa funciona, agora, sem problemas.

É feito um teste ao valor de delta à frente do comando if e é executado um de dois blocos alternativos:

  • as linhas entre if e else:, caso delta seja negativo, ou

  • as duas linhas depois de else:, caso delta seja positivo.

A forma geral de incluir blocos alternativos com if...else é:

if <condição> :
    <comandos para condição verdadeira>
else:
    <comandos para condição falsa>

Podemos ter várias linhas no bloco if e no bloco else.

É o alinhamento das linhas do programa (também chamada indentação) que define os dois blocos:

Note-se que, no programa anterior, as linhas

x1 = (- b + r_delta) / (2.0 * a)
x2 = (- b - r_delta) / (2.0 * a)

não pertencem ao bloco else. Isto porque o seu alinhamento é (de novo) igual ao de todas as outras linhas fora dos blocos if...else (e estão alinhadas com as próprias linhas dos comandos if e else)

O programa está bem melhor na maneira de apresentar os resultados, separando o caso real do complexo.

Mas, perfeito, perfeito, seria tratar o caso em que \(\Delta = 0\) de uma forma diferente, tendo o cuidado de apresentar um único valor, no caso de uma raíz dupla.

Precisamos, para isso, que o programa possa se adaptar a cada uma das três alternativas.

1.6.2. Alternativas if...elif...else#

Usando o comando elif podemos testar mais do que uma condição e executar em alternativa e, consequentemente, mais do que dois blocos de comandos.

Seguindo o exemplo da resolução de uma equação do segundo grau, podemos separar os três casos associados ao valor de \(\Delta\) da seguinte forma:

# Este programa calcula x tal que a x2 + b x + c = 0
# testar com os seguintes valores (1,4,1) , (1,2,1) , (1,1,1)

a, b, c = 1, 4, 1

# cálculo do discriminante
delta = b**2 - 4.0 * a * c

if delta < 0.0:
    rdelta = (-delta)**0.5 * 1j
    print('Soluções complexas:')
elif delta > 0:
    rdelta = (delta)**0.5
    print('Soluções reais:')
else:
    x = - b / (2.0 * a)
    print('Solução real (dupla):')
    
x1 = (- b + rdelta) / (2.0 * a)
x2 = (- b - rdelta) / (2.0 * a)    

print(f'Para a = {a}  b = {b}  c = {c}')

if delta == 0:
    print("x =", x)
else:
    print(f"x1 = {x1}\nx2 = {x2}")
Soluções reais:
Para a = 1  b = 4  c = 1
x1 = -0.2679491924311228
x2 = -3.732050807568877

O comando elif é uma abreviatura de else + if e possibilita o teste de uma nova condição para além daquela já usada no comando if.

Podem ser usados vários comandos elif.

E note-se que, mais uma vez, podemos ter várias linhas em cada bloco : o alinhamento (identação) define os blocos:

Testando agora o programa para as três situações possíveis:

\(\Delta > 0\):

Soluções reais:
Para a = 1  b = 4  c = 1
x1 = -0.2679491924311228
x2 = -3.732050807568877

\(\Delta = 0\):

Solução real (dupla):
Para a = 1  b = 2  c = 1
x = -1.0

\(\Delta < 0\):

Soluções complexas:
Para a = 1  b = 1  c = 1
x1 = (-0.5+0.8660254037844386j)
x2 = (-0.5-0.8660254037844386j)

Pode ser usado todo um conjunto de blocos if...else... “dentro” de um bloco if ou elif ou else.

Por exemplo, o o programa também poderia ser escrito da seguinte forma:

# Este programa calcula x tal que a x2 + b x + c = 0
# testar com os seguintes valores (1,4,1) , (1,2,1) , (1,1,1)

a, b, c = 1, 4, 1
print(f"Para a = {a}, b = {b}, c = {c}\n")

# cálculo do discriminante
delta = b**2 - 4.0 * a * c

if delta == 0.0:
    print('Solução real (dupla):')
    x = -b / (2.0 * a)
    print("x =", x)
else:
    if delta < 0:
        print('Soluções complexas:')
        r_delta = (-delta)**0.5 * 1j
    else:
        print('Soluções reais:')
        r_delta = (delta)**0.5

    x1 = (- b + r_delta) / (2.0 * a)
    x2 = (- b - r_delta) / (2.0 * a)    
    print("x1 =", x1, ", x2 =", x2)
Para a = 1, b = 4, c = 1

Soluções reais:
x1 = -0.2679491924311228 , x2 = -3.732050807568877

Nota

O bloco else não é obrigatório. Se não fizer sentido a existência de uma condição alternativa ao if, este bloco pode ser omitido.

Vejamos agora um outro exemplo da utilização de blocos alternativos.

Exemplo: Regra dos anos bissextos

  • Se o ano é divisível por 4, então é bissexto

Regra em vigor até 1582 (calendário Juliano, de Júlio César)

# Este programa determina de um ano é bissexto
# Testar com 2015 N, 2012 S, 1900 N, 2000 S

a = 2015

if a % 4 == 0:
    print(a , "é bissexto")
else: 
    print(a, "não é bissexto")
2015 não é bissexto

Correndo o programa com diferentes valores de a:

2015 nao é bissexto

2012 é bissexto

1900 é bissexto

2000 é bissexto

Este programa parece falhar para 1900. Isto acontece porque, na realidade, a regra actual dos anos bissextos é um pouco mais complexa.

Exemplo: Regra dos anos bissextos (calendário moderno)

  • Se o ano é divisível por 4, então é bissexto

  • Excepto os que são divisíveis por 100: não são bissextos

  • Excepto os divisíveis por 100 que sejam exactamente divisíveis por 400: são bissextos.

Esta regra entrou em vigor após 1582 (calendário Gregoriano, do papa Gregorio XIII)

Da aplicação desta regra resulta que alguns anos de mudança de século (sempre divisíveis por 4) não sejam bissextos. É o caso de 1900. E alguns anos de mudança de século, por exemplo os anos 1600; 2000; 2400, sejam bissextos.

Podemos adaptar o programa anterior para incluir as duas últimas regras:

a = 2015

if a % 4 == 0 and not (a % 100 == 0 and not a % 400 == 0):
    print(a , "é bissexto")
else: 
    print(a, "não é bissexto")
2015 não é bissexto

Correndo o programa com diferentes valores:

2015 nao é bissexto

2012 é bissexto

1900 nao é bissexto

Reparar que o resultado é diferente para 1900.

1900 não é bissexto

Os interessados na história da introdução do calendário gregoriano podem consultar o artigo

http://en.wikipedia.org/wiki/Gregorian_calendar

É desaconselhável escrever uma condição tão complicada num comando if: prejudica muito a legibilidade do programa.

Um programa equivalente, combinando vários blocos de if...else... e a negação lógica not que será (possivelmente) mais fácil de perceber é:

a = 2015

if not a % 4 == 0:
    print(a, "não é bissexto")
else:
    if not a % 100 == 0:
        print(a , "é bissexto")
    else:
        if a % 400 == 0:
            print(a , "é bissexto")
        else:
            print(a , "não é bissexto")
2015 não é bissexto

Correndo o programa com diferentes valores de a:

2015 não é bissexto
2012 é bissexto
1900 não é bissexto
2000 é bissexto

1.7. Função input()#

Até agora, nos exemplos foram apresentados, são incluídos no programa os valores a partir dos quais se fazem os cálculos (tradicionalmente chamados o input do programa).

Por exemplo, nos exemplos da resolução de uma equação do segundo grau incluímos no princípio do programa os valores dos coeficientes:

a, b, c = 1, 4, 1

Os programas partem destes valores, realizam cálculos e apresentam resultados.

A linguagem Python suporta também um outro mecanismo: o pedido de valores ao utilizador durante a execução do programa.

A função input() tem este papel: durante a execução de um programa, ao passar por uma função input() o programa pára esperando que seja introduzido uma string. A função permite também seja apresentada uma mensagem de indicação do que está a ser pedido.

Vejamos com um exemplo:

a = input('Valor de a? ')
b = input('Valor de b? ')
c = input('Valor de c? ')

a = float(a)
b = float(b)
c = float(c)

# cálculo do discriminante
delta = b**2 - 4.0 * a * c

if delta == 0.0:
    print('Solução real (dupla):')
    x = -b / (2.0 * a)
    print("x =", x)
else:
    if delta < 0:
        print('Soluções complexas:')
        r_delta = (-delta)**0.5 * 1j
    else:
        print('Soluções reais:')
        r_delta = (delta)**0.5

    x1 = (- b + r_delta) / (2.0 * a)
    x2 = (- b - r_delta) / (2.0 * a)    
    print("x1 =", x1, ", x2 =", x2)

Executando este programa várias vezes, testando com os diferentes casos, agora os valores dos coeficientes são “pedidos” pelo programa:

Valor de a? 1
Valor de b? 4
Valor de c? 1
Soluções reais:
x1 = -0.2679491924311228 , x2 = -3.732050807568877
Valor de a? 1
Valor de b? 2
Valor de c? 1
Solução real (dupla):
x = -1.0
Valor de a? 1
Valor de b? 1
Valor de c? 1
Soluções complexas:
x1 = (-0.5+0.8660254037844386j) , x2 = (-0.5-0.8660254037844386j)

1.8. Exercícios sobre conceitos fundamentais#

Software

  • Python Shell ou Idle com Python Shell

  • Visual Studio Code.

1.8.1. Exercício 1 (Números, strings, números complexos)#

  1. Abra uma Python Shell ou uma Python Shell no Idle.

  2. Corra vários dos comandos das secção Objetos e nomes. Familiarize-se com

    • Números

    • Números em vírgula flutuante (com casas decimais)

    • Strings

    • Expressões booleanas, True e False

    • Dar nomes a objetos

1.8.2. Exercício 2 (cálculos simples)#

Ainda na Python Shell, calcule

  1. O número de codões no código genético (43)

  2. O número de diferentes sequências possíveis num péptido com 50 aminoácidos (2050)

  3. A percentagem de vitórias de uma equipa que conseguiu vencer 30 jogos em 46 disputados.

1.8.3. Exercício 3 (VSCode e “número de ouro”)#

  • Crie uma pasta de trabalho onde irá criar uma série de programas em Python

Nota

Um programa em Python deve ter um nome acabado em .py

Os programas vão ser criados como ficheiros de texto editados com o VSCode.

  • Abra o editor de texto Visual Studio Code. Para isso, use o botão direito sobre a pasta e selecione “Open with Code”:

  • Em alternativa, se o método anterior não funcionar, abra a app Visual Studio Code e faça File – Open Folder para a pasta que criou.

  • Inicie um ficheiro novo, com File – New File.

  • Escreva um programa que calcule e mostre, com print(), a “proporção de ouro”, isto é, o número phi = (1+√5)/2 e também o seu quadrado e seu inverso.

Importante

Logo que começar a escrever o programa deve salvá-lo o mais depressa possível com File – Save As…!

Deve-lhe dar um nome acabado em .py, por exemplo phi.py.

  • Ao salvar o programa com o nome acabado em .py, a extensão Python para o VSCode será instalada:

  • Só precisa de instalar esta extensão uma vez (em cada computador que usar)!

  • Caso não fique imediatamente instalada, escreva “Python” em “Search Extensions in …”. A primeira que aparece é a extensão Python da Microsoft. Use o botão “Install” para instalar a extensão. Só precisa de o fazer uma vez!

Nota

Se o VSCode indicar que falta selecionar um “Python interpreter”, deve escolher o interpretador instalado do Anaconda, clicando no canto inferior direito onde diz “No Interpreter”. Depois de escolher, deve ver o seguinte no canto inferior direito do VSCode:

Ver o ponto “Select Python interpreter” Nesta página

  • Familiarize-se com a edição de um programa no VSCode. Use alguns shortcuts do teclado: Home e End. Ctrl-C (copy), Ctrl-V (paste). Selecione com o rato e com o teclado.

  • Execute (corra) o programa. Para isso utilize o botão no canto superior direito

  • Observe o resultado do programa. Corra o programa outra vez.

  • Note as propriedades \(\phi^2 = \phi +1\) e \(1 / \phi = \phi - 1\)

1.8.4. Exercício 4 (°C para °F)#

Escreva um outro programa (faça File – New File para criar um novo programa) que calcula os graus Farenheit correspondentes a 36.5 graus Celsius. Não se esqueça de salvar o programa com um nome acabado em .py. A fórmula de conversão é:

°F = 32 + (9/5) * °C

Use a função print() com strings para apresentar mensagens explicativas sobre o resultado (tipo 36.5 graus Celsius são …)

1.8.5. Exercício 5 (import e função input())#

Escreva o seguinte programa novo (sugestão: copy-paste).

Note que há muita coisa neste programa um pouco avançada, mas o objetivo é ilustrar a função input():

from datetime import datetime
import locale
locale.setlocale(locale.LC_ALL, "pt_PT.utf8")

print('Programa: tempo até agora')

name = input('Qual o seu nome? ')
day = input('Em que dia nasceu? ')
month = input('Em que mês nasceu (1-12)? ')
year = input('Em que ano nasceu? ')

year = int(year)
month = int(month)
day = int(day)

birth = datetime(year, month, day)
now = datetime.now()

dif = now - birth

print(f'\n{name}, o seu tempo de vida é')
print(dif)
print('ou seja,', int(dif.total_seconds()), 'segundos')
print('Nasceu em', birth.strftime("%d %B %Y, %A"))

Este programa usa o módulo datetime para realizar cálculos com datas e tempos. Para isso é necessário fazer from datetime import datetime no início do programa.

Corra o programa e observe que, no terminal de resultados, o programa pára em cada função input(), “pedindo” a introdução de um valor:

O programa só continua fazendo Enter, após a introdução de cada valor.

Nota

Para correr o programa do princípio pode sempre “destruír” os resultados anteriores de um programa usando o botão

1.8.6. Exercício 6 (Acesso programático à UniProt)#

  • Escreva e corra o seguinte programa (novo, com outro nome, outro ficheiro .py):

import requests

proteína = 'P00924'
link = f'http://www.uniprot.org/uniprot/{proteína}.fasta'

página = requests.get(link).text

print('Sequência da proteína', proteína, 'é')
print(página)
  • Escreva um novo programa semelhante mudando .fasta para .txt.

1.8.7. Exercício 7 (Solução de equação 1º grau)#

  • Escreva o seguinte programa:

"""Cálculo da solução de uma equação do 1º grau 0 = mx + b."""

m = input('declive (m) = ')
b = input('ordenada na origem (b) = ')

m = float(m)
b = float(b)

r = -b / m
print(f'raíz = {r}')
  • Corra o programa e observe os resultados. Experimente correr várias vezes, com diferentes valores de m e b para teste. Inclua um teste com m = 0.

  • Corrija o programa de forma a não dar erro com m = 0. Para isso modifique o programa da seguinte maneira:

"""Cálculo da raíz de uma equação do 1º grau 0 = mx + b."""

m = input('declive (m) = ')
b = input('ordenada na origem (b) = ')

m = float(m)
b = float(b)

if m == 0:
    print('Reta horizontal: não há raízes')
else:
    r = -b / m
    print(f'raíz = {r}')

Explicação: a parte if... else ... faz com que o programa execute em alternativa certas partes, consoante o valor de uma condição. Neste exemplo, a condição é m == 0.

1.8.8. Exercício 8 (Solução equação do 2º grau)#

  • Escreva um programa que calcule as duas soluções de uma equação do segundo grau

\(a \cdot x^2 + b \cdot x + c = 0\)

  • Para testar o programa, corra com diferentes valores para a, b e c:

    • a = 1, b = 4, c = 2 dá duas soluções reais.

    • a = 1, b = 2, c = 1 dá uma solução dupla: -1

    • a = 1, b = 1, c = 1 dá duas soluções complexas.

1.8.9. Exercício 9 (Conversão entre F e ω)#

  • Escreva um programa que converta a velocidade angular de rotação (ω em 103 rpm) em força centrípeta (F, em g), dado o raio de um rotor de centrifugação (r, em mm).

A fórmula (usando aquelas unidades) é:

\(F = 1.12 \cdot r \cdot \omega^2\)

  • Teste o programa com r = 108 mm, ω = 10 x 103 rpm F = 12 096 g

  • Escreva outro programa que faça a conversão contrária (de g para rpm).