Operadores lógicos


Antes de conhecer as instruções de controle de fluxo, como comandos condicionais ou de repetição, é necessário entender a representação de Yes e No, além de saber como escrevê-los no código em Python.


Valores booleanos


Enquanto os tipos de dados inteiro, ponto flutuante e string têm um número quase ilimitado (depende do tamanho da memória) de valores possíveis, o tipo de dados booleano (homenagem a George Boole) possui apenas dois valores: True e False.

Quando digitado como código Python, os valores booleanos True e False não tem aspas em torno como as strings e sempre começam com uma letra T ou F maiúscula e o restante da palavra em letras minúsculas.


Digite no shelll interativo as instruções a seguir levando em conta que algumas podem estar incorretas:

>>> 
>>> word = True
>>> word
True
>>> 
>>> word2 = False
>>> word2
False
>>> 
>>> False
False
>>> 
>>> true
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'true' is not defined
>>> 
>>> False = 3 * 4
>>> False
12
>>> True = 4 + 4
>>> True
8
>>> 

Se como no caso acima, o interpretador aceitar uma variável como False ou True ainda assim não é interessante que a usemos. Devemos mantê-las sempre como palavras reservadas para evitar interpretações indevidas do código-fonte por outras pessoas.

Operadores de comparação


Os operadores de comparação comparam dois valores e são avaliados como um único valor booleano. A tabelinha abaixo mostra estes operadores.


Operador Significado
== igual a
!= diferente de
< menor que
> maior que
<= menor ou igual a
>= maior ou igual a


Estes operadores são avaliados como True ou False de acordo com os valores fornecidos.


#Testando alguns operadores
>>> 
>>> 1230 == 1230
True
>>> 
>>> 1230 == 1230.0
True
>>> 
>>> 10.00000000000 == 10.00000000001    
False
>>> 
>>> 10.00000000000 != 10.00000000001
True
>>> 
>>> "Casa" = "Casa"        #Usando atribuição?
  File "<stdin>", line 1
SyntaxError: can't assign to literal
>>> 
>>> "Casa" == "Casa"
True
>>> 
>>> "Casa" == "casa"     #Maiúscula x minúscula
False


Observe que podemos comparar valores string além de valores inteiros e pontos flutuantes.

>>> 4 > 1.2
True
>>> 
>>> 20.000001 < 20.00001
True
>>> 
>>> 2312 <= 2313
True
>>> 
>>> 2312 >= 2312
True
>>> 
>>> 2312 >= 2313
False
>>> 


Operadores booleanos


Os três operadores booleandos (and, or e not) são usados para comparar valores booleanos. Assim como os operadores de comparação, eles avaliam essas expressões reduzindo-as a um valor booleano.

Explorando estes operadores em detalhes.

Operadores booleanos binários


Os operadores and e or sempre aceitam dois valores booleanos (ou expressões), portanto são considerados operadores binários.

O operador and avalia uma expressão como True se ambos os valores booleanos forem True, caso contrário, ela será avaliada como False.

Exercitando no shell interativo:

>>> True
True
>>> 
>>> True and True
True
>>> 
>>> True and False
False
>>> 
>>> False and False
False
>>> 


  • Tabela Verdade do operador and
Expressão Avaliação
True and True True
True and False False
False and True False
False and False False



O operador or avalia uma expressão como verdade se um dos dois valores for True.

>>> True or True
True
>>> 
>>> True or False
True
>>> 
>>> False or False
False
>>> 
  • Tabela Verdade do operador or
Expressão Avaliação
True and True True
True and False True
False and True True
False and False False


Isto nos permite montar a Tabela da Verdade que mostra os resultados possíveis de um operador booleano. Este é o grande princípio do mundo digital, onde os circuitos eletrônicos normalmente se baseiam em operações com dois dígitos (On ou Off) e partir daí as operações podem ser executadas.

Exemplo de circuito eletrônico


Operador not


De modo diferente de and e or, o operador not atua somente sobre um valor booleano (ou uma expressão). O operador not simplesmente é avaliado como o valor booleano oposto.

>>> 
>>> not True
False
>>> 
>>> not False
True
>>> 


Podemos aninhar operadores na mesma expressão:

>>> 
>>> not not not False
True
>>> 
>>> not not not not True
True

<br.


  • Tabela Verdade do operador not
Expressão Avaliação
not True False
not False True


Operadores de comparação e booleanos numa mesma expressão


Como os operadores de comparação são avaliados como operadores booleanos, podemos usá-los em expressões com operadores booleanos.

Embora expressões como 10 < 1 não sejam valores booleanos, elas são expressões avaliadas como valores booleanos.

>>> (10 < 21 ) and (10 > 2)
True
>>> 
>>> (10 < 21 ) 
True
>>> (10 > 2)
True
>>> 
>>> x = 10
>>> y = 21
>>> z = 2
>>> (x < y) and (x > z)
True
>>>

O interpretador avalia inicialmente a expressão à esquerda e, em seguida, avaliará a expressão à direita. Depois de gerar o resultado de cada expressão, compará as duas e reduzirá a um único valor booleano. Isso vale para qualquer quantidade de comparações.


Um cuidado deve ser tomado com ordens de prioridade já que podemos ter vários operadores booleanos numa mesma expressão juntamento com os operadores de comparação. Assim como os operadores matemáticos existe uma ordem de atuação. O Python, avalia da seguinte forma:

  1. Avalia a expressão da esquerda entre parenteses (x<y)
  2. Atribui a x o valor 10
  3. Atribui a y 0 valor 21
  4. Monta a expressão (10 < 21) and (10<z)
  5. Monta a expressão True and (10<z)
  6. Atribui a z o valor de 2
  7. Monta a expressão True and (10<2)
  8. Monta a expressão True and True
  9. Resulta em True


Execução condicional


Já sabemos que o Python permite que instruções sejam processadas de maneira sequencial (algumas linguagens permitem o processamento paralelo). Estas instruções podem ser montadas em expressões mais complexas que segundo uma regra pré-determinada pelo interpretador ou compilador são executadas passo-a-passo.

A verdadeira eficácia da programação não está somente em executar uma instrução após a outra como uma lista de tarefas do dia-a-dia ou ainda um script de teatro. De acordo com o modo como as expressões são avaliadas, o programa pode decidir alterar a sequência descrita no código-fonte (seja no arquivo texto ou no shell script). Ele efetivamente poderá pular instruções, repeti-las ou escolher uma entre várias.

Para isso temos as instruções de controle de fluxo que poderão decidir quais instruções Python poderão ser executadas de acordo com determinadas condições. Uma forma prática de enxergar estes fluxos é entender o papel dos fluxogramas. Eles basicamente contém estruturas de início, processamento, condição, entrada, saída, fluxo de processamento e fim.




A figura acima mostra um fluxograma que calcula o máximo divisor comum entre dois valores. Nele podemos ver várias estruturas e entre elas algumas que decidem o controle do fluxo. Em um fluxograma, geralmente existe mais de uma maneira de ir do início ao fim. O mesmo vale para as linhas de código em um programa de computador.

Os fluxogramas representam esses pontos de ramificação com losangos, enquanto os demais passos são representados por retângulos. Os passos iniciais e finais podem ser representados por retângulos com cantos arredondados.

Dessa forma, poderemos escrever programas interessantes, podendo checar condições e mudar o comportamento do programa de acordo com elas. As instruções condicionais nos dão essa habilidade. A forma mais simples é a instrução if (se):

>>> numero = input()
11
>>> if(numero>0):
...   print("O numero digitado é positivo.")
... 
O numero digitado é positivo.
>>> 

A expressão booleana depois da instrução if é chamada de condição. Se ela é verdadeira (true), então a instrução indentada é executada. Se não, nada acontece.

>>> numero = input()
-1
>>> if(numero>0):
...   print("O numero digitado é positivo.")
... 
>>> 
>>> 


Assim como outras instruções compostas, a instrução if é constituída de um cabeçalho e de um bloco de instruções:

CABECALHO:
   PRIMEIRO COMANDO
   ...
   ULTIMO COMANDO


O cabeçalho começa com uma nova linha e termina com dois pontos (:). Os comandos ou instruções indentados que seguem são chamados de bloco. A primeira instrução não indentada marca o fim do bloco. Um bloco de comandos dentro de um comando composto ou instrução composta é chamado de corpo do comando.


Não existe limite para o número de instruções que podem aparecer no corpo de uma instrução if, mas tem que haver pelo menos uma. Ocasionalmente, é útil ter um corpo sem nenhuma instrução (usualmente, como um delimitador de espaço para código que você ainda não escreveu). Nesse caso, pode-se usar o comando pass, que indica ao Python: “passe por aqui sem fazer nada”.


Execução alternativa


Um segundo formato da instrução if é a execução alternativa, na qual existem duas possibilidades e a condição determina qual delas será executada. A sintaxe se parece com:

>>> numero = input()
10
>>> if(numero%2==0):
...   print("O numero digitado é par.")
... else:
...   print("O numero digitado é impar.")
... 
O numero digitado é par.
 >>> 
 >>> numero = input()
 11
 >>> if(numero%2==0):
 ...   print("O numero digitado é par.")
 ... else:
 ...   print("O numero digitado é impar.")
 ... 
 O numero digitado é impar.
 >>> 


Se o resto da divisão de x por 2 for 0, então sabemos que x é par, e o programa exibe a mensagem para esta condição. Se a condição é falsa, o segundo grupo de instruções é executado.


Desde que a condição deva ser verdadeira (True) ou falsa (False), precisamente uma das alternativas vai ser executada. As alternativas são chamadas ramos (branches), porque existem ramificações no fluxo de execução.

Condicionais encadeadas


Muitas vezes existem mais de duas possibilidades e precisamos de mais que dois caminhos de execução. Uma condicional encadeada é uma maneira de expressar uma operação dessas:


>>> x = input("Digite x: ")
Digite x: 10
>>> y = input("Digite y: ")
Digite y: 5
>>> if x < y:
...   print x, " e menor que ", y
... elif x > y:
...   print x, " e maior que ", y
... else:
...   print x, " e ", y,  " sao iguais."
...  
10  e maior que  5
>>> 


elif é uma abreviação de “else if” (“senão se”). De novo, precisamente um ramo será executado. Não existe limite para o número de instruções elif, mas se existir uma instrução else ela tem que vir por último:


  • Considerações:
    • Cada condição é checada na ordem.
    • Se a primeira é falsa, a próxima é checada, e assim por diante.
    • Se uma delas é verdadeira, o ramo correspondente é executado, e a instrução termina.
    • Mesmo que mais de uma condição seja verdadeira, apenas o primeiro ramo verdadeiro executa.


  • Exercício:
    • Desenvolva um código que decida se a nota final digitada aprova, reprova (abaixo de 60) ou permite prova alternativa (entre 45 e 60) para determinado aluno.
    • Entrada:
      • Nota final e nome do aluno
    • Saída:
      • "O aluno FULANO está APROVADO." ou
      • "O aluno FULANO poderá fazer PROVA ALTERNATIVA." ou
      • "O aluno FULANO está REPROVADO."


Condicionais aninhadas


Um condicional também pode ser aninhado dentro de outra. Poderíamos ter escrito o exemplo tricotômico (dividido em três) como segue:

>>> 
>>> x = input("Digite x: ")
Digite x: 5
>>> y = input("Digite y: ")
Digite y: 10
>>> if x == y:
.............print x, " e ", y,  " sao iguais."
....else:
.............if x < y:
................. print x, " e menor que ", y
.............else:
..................print x, " e maior que ", y
...  
5  e menor que  10
>>> 


O condicional mais externo tem dois ramos. O primeiro ramo contém uma única instrução de saída. O segundo ramo contém outra instrução if, que por sua vez tem dois ramos. Os dois ramos são ambos instruções de saída, embora pudessem conter instruções condicionais também.


Embora a indentação das instruções torne a estrutura aparente, condicionais aninhados tornam-se difíceis de ler rapidamente. Em geral, é uma boa ideia evitar o aninhamento quando for possível.


Operadores lógicos frequentemente fornecem uma maneira de simplificar instruções condicionais aninhadas. Por exemplo, podemos reescrever o código a seguir usando uma única condicional:

>>> if 0 < x:
...    if x < 10:
...        print "X e um numero positivo de um só algarismo."
... 
X e um numero positivo de um só algarismo.
>>> 

A instrução print é executada somente se a fizermos passar por ambos os condicionais, então, podemos usar um operador and:

>>> 
>>> if 0 < x and x < 10:
...        print "X e um numero positivo de um só algarismo."
... 
X e um numero positivo de um só algarismo.
>>> 


Esses tipos de condições são comuns, assim, Python provê uma sintaxe alternativa que é similar à notação matemática:

 >>> if 0 < x < 10:
........print "x é um número positivo de um só algarismo."


A instrução return



O comando return permite terminar a execução de uma função antes que ela alcance seu fim. Uma razão para usá-lo é se você detectar uma condição de erro:

>>> 
>>> def printLog(x):
...   if x <= 0:
........     print "Somente numeros positivos, por favor."
........      return
...   resultado = math.log(x,10)
...   print "O log de x e ",resultado
... 
>>> 


A função printLog recebe um parâmetro de nome x. A primeira coisa que ela faz é checar se x é menor ou igual a 0, neste caso ela exibe uma mensagem de erro e então usa return para sair da função. O fluxo de execução imediatamente retorna ao ponto chamador, quer dizer, de onde a função foi chamada, e as linhas restantes da função não são executadas.


Lembre-se que para usar uma função de matemática, deve-se importar o módulo math.

Exercícios


  1. Experimente repetir o código calculando o log na base 10 apenas de números positivos maiores que 1.
  2. Desenvolva um código que calcule a raiz quadra de um número levando em conta que a função matemática é sqrt.
  3. Crie um código que receba ângulos em radianos e calcule o seno e o cosseno para valores maiores que zero.