Aula 6

Noções básicas de Python

  • Hoje aprenderemos uma nova linguagem de programação chamada Python. Lembre-se de que um dos objetivos gerais do curso não é aprender nenhuma linguagem específica, mas sim como programar em geral.
  • O código-fonte em Python parece muito mais simples do que em C, mas é capaz de resolver problemas em campos como ciência de dados. Na verdade, para imprimir "hello, world", tudo o que precisamos escrever é:

      print("hello, world")
    
    • Observe que, ao contrário do C, não precisamos importar uma biblioteca padrão, declarar uma função main, especificar uma nova linha na função print ou usar ponto e vírgula.
  • Python é uma linguagem interpretada, o que significa que, na verdade, executamos outro programa (um interpretador) que lê nosso código-fonte e o executa de cima para baixo. Por exemplo, podemos salvar o código acima como hello.py e executar o comando python hello.py para executar nosso código, sem precisar compilá-lo.

  • Podemos obter strings de um usuário:

      answer = get_string("Qual é o seu nome?\n")
      print("hello, " + answer)
    
    • Criamos uma variável chamada answer, sem especificar o tipo (o interpretador determina isso a partir do contexto para nós), e podemos facilmente combinar duas strings com o operador + antes de passá-la para print.
    • Também podemos passar vários argumentos para print, com print("hello,", answer), e ele unirá automaticamente essas strings com espaços para nós também.
    • print também aceita strings de formato como f"hello, {answer}", que substitui variáveis dentro de chaves por uma string.
  • Podemos criar variáveis com apenas counter = 0. Para incrementar uma variável, podemos usar counter = counter + 1 ou counter += 1.

  • As condições se parecem com:

      if x < y:
          print("x é menor que y")
      elif x > y:
          print("x é maior que y")
      else:
          print("x é igual a y")
    
    • Ao contrário do C e do JavaScript (em que as chaves { } são usadas para indicar blocos de código), a indentação exata de cada linha é o que determina o nível de aninhamento em Python.
    • E em vez de else if, basta dizermos elif.
  • As expressões booleanas também são um pouco diferentes:

      while True:
          print("hello, world")
    
  • Podemos escrever um loop com uma variável:

      i = 3
      while i > 0:
          print("cough")
          i -= 1
    
  • Também podemos usar um loop for, no qual podemos fazer algo para cada elemento de uma lista:

      for i in [0, 1, 2]:
          print("cough")
    
    • As listas em Python são como matrizes em C, mas podem crescer e diminuir facilmente com o interpretador gerenciando a implementação e a memória para nós.
    • Este loop for definirá a variável i para o primeiro elemento, 0, será executado e, em seguida, para o segundo elemento, 1, será executado novamente e assim por diante.
    • E podemos usar uma função especial, range, para obter alguns valores numéricos, como em for i in range(3). Isso nos dará 0, 1 e 2, para um total de três valores.
  • No Python, há muitos tipos de dados:

    • bool, True ou False
    • float, números reais
    • int, números inteiros
    • str, strings
    • range, sequência de números
    • list, sequência de valores mutáveis, que podemos alterar, adicionar ou remover
    • tuple, sequência de valores imutáveis, que não podemos alterar
    • dict, coleção de pares chave/valor, como uma tabela hash
    • set, coleção de valores únicos
  • docs.python.org é a fonte oficial de documentação, mas o Google e o StackOverflow também têm recursos úteis quando precisamos descobrir como fazer algo em Python. Na verdade, os programadores no mundo real raramente sabem tudo que está na documentação, mas sabem como encontrar o que precisam quando precisam.

Exemplos

  • Podemos borrifar uma imagem com:

      from PIL import Image, ImageFilter
    
      before = Image.open("bridge.bmp")
      after = before.filter(ImageFilter.BLUR)
      after.save("out.bmp")
    
    • Em Python, incluímos outras bibliotecas com import, e aqui nós vamos importar os nomes Image e ImageFilter da biblioteca PIL.
    • Acontece que se olharmos a documentação para a biblioteca PIL, podemos usar as próximas três linhas de código para abrir uma imagem chamada bridge.bmp, executar um filtro de borramento nela, e salvá-la em um arquivo chamado out.bmp.
    • E podemos executar isso com python blur.py depois de salvar em um arquivo chamado blur.py.
  • Podemos implementar um dicionário com:

      words = set()
    
      def check(word):
          if word.lower() in words:
              return True
          else:
              return False
    
      def load(dictionary):
          file = open(dictionary, "r")
          for line in file:
              words.add(line.rstrip("\n"))
          file.close()
          return True
    
      def size():
          return len(words)
    
      def unload():
          return True
    
    • Primeiro, criamos um novo conjunto chamado words. Então, para check, nós só precisamos perguntar if word.lower() in words. Para load, nós abrimos o arquivo e usamos words.add para adicionar cada linha ao nosso conjunto. Para size, nós podemos usar len para contar o número de elementos em nosso conjunto, e finalmente, para unload, nós não precisamos fazer nada!
  • Acontece que, mesmo que implementar um programa em Python seja mais simples para nós, o tempo de execução de nosso programa em Python é mais lento do que nosso programa em C, pois nosso interpretador tem mais trabalho a fazer para nós. Então, dependendo de nossos objetivos, também teremos que considerar a compensação do tempo humano para escrever um programa que seja mais eficiente, em relação ao tempo de execução do programa.

  • Em Python, também podemos incluir a biblioteca CS50, mas nossa sintaxe será:

      from cs50 import get_string
    
    • Observe que especificamos as funções que queremos usar.
  • Agora podemos obter strings de um usuário:

      from cs50 import get_string
    
      s = get_string("Qual é o seu nome?:\n")
      print("olá, " + s)
    
  • Também podemos substituir expressões em nossas strings de formato:

      from cs50 import get_int
    
      age = get_int("Qual é a sua idade?\n")
      print(f"Você tem pelo menos {age * 365} dias de idade.")
    
  • E podemos demonstrar condições:

      from cs50 import get_int
    
      x = get_int("x: ")
      y = get_int("y: ")
    
      if x < y:
          print("x é menor que y")
      elif x > y:
          print("x é maior que y")
      else:
          print("x é igual a y")
    
  • Para verificar condições, podemos dizer:

      from cs50 import get_string
    
      s = get_string("Você concorda?\n")
    
      if s == "Y" ou s == "y":
          print("Concordo.")
      elif s == "N" ou s == "n":
          print("Não concordo.")
    
    • Python não tem caracteres, então as podemos verificar como strings diretamente.
    • Podemos também dizer if s in ["Y", "y"]:, ou if s.lower() in ["y"]:. Acontece que as strings em Python são como structs em C, em que não temos apenas variáveis, mas funções que podemos chamar. Por exemplo, dada uma string s, podemos chamar sua função lower com s.lower() para obter a versão em minúsculas da string.
  • Também podemos melhorar as versões de cough:

      print("cough")
      print("cough")
      print("cough")
    
    • Não precisamos declarar uma função main, então simplesmente escrevemos a mesma linha de código três vezes.
  • Mas podemos fazer melhor:

      for i in range(3):
          cough()
    
      def cough():
            print("cough")
    
    • Perceba que não precisamos especificar o tipo de retorno de uma nova função, que pode ser definida com def.
    • Mas isso causa um erro quando tentamos executá-la: NameError: name 'cough' is not defined (Erro de nome: o nome 'cough' não está definido). Acontece que precisamos definir nossa função antes de usá-la, então podemos mover nossa definição de cough para o topo ou criar uma função main:

        def main():
            for i in range(3):
                cough()
      
        def cough():
            print("cough")
      
        main()
      
    • Agora, no momento em que chamarmos nossa função main, a função cough terá sido lida pelo nosso interpretador.

  • Nossas funções também podem receber entradas:

      def main():
          cough(3)
    
      def cough(n):
          for i in range(n):
              print("cough")
    
      main()
    
  • Podemos definir uma função para obter um inteiro positivo:

      from cs50 import get_int
    
      def main():
          i = get_positive_int()
          print(i)
    
      def get_positive_int():
          while True:
              n = get_int("Inteiro Positivo: ")
              if n > 0:
                  break
          return n
    
      main()
    
    • Como não há um laço do-while em Python como em C, temos um laço while que continuará infinitamente, mas usamos break para finalizar o laço assim que n > 0. Então, nossa função simplesmente return n.
    • Observe que as variáveis em Python têm escopo de função por padrão, o que significa que n pode ser inicializado dentro de um laço, mas ainda pode ser acessado posteriormente na função.
  • Podemos imprimir uma linha de pontos de interrogação na tela:

      for i in range(4):
          print("?", end="")
      print()
    
    • Quando imprimimos cada bloco, não queremos a nova linha automática, então podemos passar um parâmetro, ou argumento nomeado, para a função print. Aqui, dizemos end="" para especificar que nada deve ser impresso no final de nossa string. Então, depois de imprimir nossa linha, podemos chamar print para obter uma nova linha.
  • Também podemos “multiplicar” uma string e imprimi-la diretamente com: print("?" * 4).

  • Podemos imprimir uma coluna com um loop:

      for i in range(3):
          print("#")
    
  • E sem um loop: print("#\n" * 3, end="").

  • Podemos implementar loops aninhados:

      for i in range(3):
          for j in range(3):
              print("#", end="")
          print()
    
  • Não precisamos usar a função get_string da biblioteca CS50, pois podemos usar a função input embutida no Python para obter uma string do usuário. Mas se quisermos outro tipo de dado, como um inteiro, do usuário, precisaremos convertê-lo com int().

  • Mas nosso programa travará se a string não puder ser convertida em um inteiro, por isso podemos usar get_string, que simplesmente perguntará novamente.
  • No Python, tentar obter um estouro de inteiro na verdade não funcionará:

      from time import sleep
    
      i = 1
      while True:
          print(i)
          sleep(1)
          i *= 2
    
    • Chamamos a função sleep para pausar nosso programa por um segundo entre cada iteração.
    • Isso continuará até que o inteiro não caiba mais na memória do seu computador.
  • A imprecisão de ponto flutuante também pode ser evitada por bibliotecas que podem representar números decimais com quantos bits forem necessários.

  • Podemos fazer uma lista:

      scores = []
      scores.append(72)
      scores.append(73)
      scores.append(33)
    
      print(f"Média: {sum(scores) / len(scores)}")
    
    • Com append, podemos adicionar itens à nossa lista, usando-a como uma lista vinculada.
    • Também podemos declarar uma lista com alguns valores como scores = [72, 73, 33].
  • Podemos iterar sobre cada caractere em uma string:

      from cs50 import get_string
    
      s = get_string("Entrada:  ")
      print("Saída: ", end="")
      for c in s:
          print(c, end="")
      print()
    
    • Python obterá cada caractere na string para nós.
  • Para deixar uma string em maiúsculas também, podemos simplesmente chamar s.upper() para obter a versão em maiúsculas da string inteira, sem ter que iterar sobre cada caractere nós mesmos.

Mais recursos

  • Podemos receber argumentos de linha de comando com:

      from sys import argv
    
      for i in range(len(argv)):
          print(argv[i])
    
    • Como argv é uma lista de strings, podemos usar len() para obter seu tamanho, e range() para uma faixa de valores que podemos usar como índice para cada elemento da lista.
  • Mas também podemos deixar o Python iterar sobre a lista:

      from sys import argv
    
      for arg in argv:
          print(arg)
    
  • Também podemos retornar códigos de saída quando nosso programa sai:

      from sys import argv, exit
    
      if len(argv) != 2:
          print("argumento de linha de comando ausente")
          exit(1)
      print(f"olá, {argv[1]}")
      exit(0)
    
    • Importamos a função exit e a chamamos com o código que queremos que nosso programa saia.
  • Podemos implementar a busca linear apenas verificando cada elemento em uma lista:

      import sys
    
      names = ["EMMA", "RODRIGO", "BRIAN", "DAVID"]
    
      if "EMMA" in names:
          print("Encontrado")
          sys.exit(0)
      print("Não encontrado")
      sys.exit(1)
    
  • Se tivermos um dicionário, um conjunto de pares chave:valor, também podemos verificar cada chave:

      import sys
    
      people = {
          "EMMA": "617-555-0100",
          "RODRIGO": "617-555-0101",
          "BRIAN": "617-555-0102",
          "DAVID": "617-555-0103"
      }
    
      if "EMMA" in people:
          print(f"Encontrado {people['EMMA']}")
          sys.exit(0)
      print("Não encontrado")
      sys.exit(1)
    
    • Observe que podemos obter o valor de uma chave em particular em um dicionário com people['EMMA']. Aqui, usamos aspas simples (apóstrofos e aspas duplas são permitidas, desde que correspondam a uma string) para diferenciar a string interna da string externa.
    • E declaramos dicionários com chaves, {}, e listas com colchetes [].
  • Em Python, podemos comparar strings diretamente com apenas ==:

      from cs50 import get_string
    
      s = get_string("s: ")
      t = get_string("t: ")
    
      if s == t:
          print("Igual")
      else:
          print("Diferente")
    
  • Copiar strings também funciona sem nenhum trabalho extra nosso:

      from cs50 import get_string
    
      s = get_string("s: ")
    
      t = s
    
      t = t.capitalize()
    
      print(f"s: {s}")
      print(f"t: {t}")
    
  • A troca de duas variáveis também pode ser feita atribuindo ambos os valores ao mesmo tempo:

      x = 1
      y = 2
    
      print(f"x é {x}, y é {y}")
      x, y = y, x
      print(f"x é {x}, y é {y}")
    

Arquivos

  • Vamos abrir um arquivo CSV:

      import csv
      from cs50 import get_string
    
      file = open("phonebook.csv", "a")
    
      name = get_string("Nome: ")
      number = get_string("Número: ")
    
      writer = csv.writer(file)
      writer.writerow((name, number))
    
      file.close()
    
    • Acontece que o Python também tem um pacote csv (biblioteca) que nos ajuda a trabalhar com arquivos CSV, então depois que abrirmos o arquivo para acrescentar, podemos chamar csv.writer para criar um writer do arquivo e depois writer.writerow para escrever uma linha. Com os parênteses internos, estamos criando uma tupla com os valores que queremos escrever, então estamos realmente passando um único argumento que tem todos os valores para nossa linha.
  • Podemos usar a palavra-chave with, que nos ajudará a fechar o arquivo:

      ...
      with open("phonebook.csv", "a") as file:
          writer = csv.writer(file)
          writer.writerow((name, number))
    

Novos recursos

  • Um recurso do Python que o C não tem são as expressões regulares, ou padrões contra os quais podemos combinar strings. Por exemplo, sua sintaxe inclui:
    • ., para qualquer caractere
    • .*, para 0 ou mais caracteres
    • .+, para 1 ou mais caracteres
    • ?, para algo opcional
    • ^, para início da entrada
    • $, para fim da entrada
  • Por exemplo, podemos combinar strings com:

      import re
      from cs50 import get_string
    
      s = get_string("Você concorda?\n")
    
      if re.search("^y(es)?$", s, re.IGNORECASE):
          print("Concordo.")
      elif re.search("^no?$", s, re.IGNORECASE):
          print("Não concordo.")
    
    • Primeiro, precisamos do pacote re, ou biblioteca, para expressões regulares.
    • Então, para y ou yes, temos a expressão regular ^y(es)?$. Queremos ter certeza de que a string começa com y e, opcionalmente, tem es imediatamente após o y, e então termina.
    • Da mesma forma, para n e no, queremos que nossa string comece, tenha a letra n e, opcionalmente, a letra o depois, e então termine. A expressão regular para isso seria ^no?$.
    • Passamos outro argumento, re.IGNORECASE, para ignorar a caixa das letras na string.
    • Se nenhuma das expressões regulares corresponder, não imprimiremos nada.
  • Em nosso próprio Mac ou PC, podemos abrir um terminal após instalar o Python e usar o microfone para converter nossa fala em texto:

      import speech_recognition
    
      recognizer = speech_recognition.Recognizer()
      with speech_recognition.Microphone() as source:
          print("Diga algo!")
          audio = recognizer.listen(source)
    
      print("O Google Speech Recognition acha que você disse:")
      print(recognizer.recognize_google(audio))
    
    • Acontece que há outra biblioteca que podemos baixar, chamada speech_recognition, que pode ouvir áudio e convertê-lo em uma string.

    • E agora, podemos combinar com o áudio para imprimir algo diferente:

      ...
      words = recognizer.recognize_google(audio)
      
      # Responda a fala
      if "hello" in words:
          print("Olá, para você também!")
      elif "how are you" in words:
          print("Estou bem, obrigado!")
      elif "goodbye" in words:
          print("Adeus para você também!")
      else:
          print("Hã?")
      
    • Podemos até usar expressões regulares, para combinar com parte de uma string:

      ...
      words = recognizer.recognize_google(audio)
      
      matches = re.search("my name is (.*)", words)
      if matches:
          print(f"Olá, {matches[1]}.")
      else:
          print("Olá, você.")
      
    • Aqui, podemos obter todos os caracteres após my name is com .* e imprimi-los.

    • Executamos detect.py e faces.py, que encontra cada rosto (ou até mesmo um rosto específico) em uma foto.

    • qr.py também gerará um código QR para um determinado URL.