Aula 6

Fundamentos do Python

  • Hoje aprenderemos uma nova linguagem de programação chamada Python, e lembre-se de que um dos objetivos gerais do curso não é aprender linguagens específicas, mas sim como programar de forma 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 "olá, mundo", tudo o que precisamos escrever é:

    print("olá, mundo")
    
    • Note que, diferentemente 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:

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

  • Condições são parecidas 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 JavaScript (onde 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, apenas dizemos elif.
  • Expressões booleanas são um pouco diferentes também:

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

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

    for i in [0, 1, 2]:
        print("tosse")
    
    • Listas em Python são como vetores em C, mas podem crescer e encolher facilmente com o interpretador gerenciando a implementação e memória para nós.
    • Este loop for definirá a variável i como o primeiro elemento, 0, executará, depois como o segundo elemento, 1, executará e assim por diante.
    • E podemos usar uma função especial, range, para obter algum número de valores, como em for i in range(3). Isso nos dará 0, 1 e 2, totalizando três valores.
  • Em Python, existem muitos tipos de dados:

    • bool, True ou False
    • float, números reais
    • int, 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 de hash
    • set, coleção de valores únicos
  • docs.python.org é a fonte oficial de documentação, mas o Google e o StackOverflow também terão recursos úteis quando precisarmos descobrir como fazer algo em Python. Na verdade, programadores do mundo real raramente conhecem tudo na documentação, mas sim como encontrar o que precisam quando precisam.

Exemplos

  • Podemos desfocar uma imagem com:

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

    palavras = set()
    
    def verificar(palavra):
        if palavra.lower() in palavras:
            return True
        else:
            return False
    
    def carregar(dicionario):
        arquivo = open(dicionario, "r")
        for linha in arquivo:
            palavras.add(linha.rstrip("\n"))
        arquivo.close()
        return True
    
    def tamanho():
        return len(palavras)
    
    def descarregar():
        return True
    
    • Primeiro, criamos um novo conjunto chamado palavras. Então, para verificar, podemos simplesmente perguntar if palavra.lower() in palavras. Para carregar, abrimos o arquivo e usamos palavras.add para adicionar cada linha ao nosso conjunto. Para tamanho, podemos usar len para contar o número de elementos do conjunto e, finalmente, para descarregar, 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 do nosso programa em Python é mais lento do que nosso programa em C, pois nosso interpretador precisa fazer mais trabalho para nós. Portanto, dependendo de nossos objetivos, também teremos que considerar a troca de tempo humano de escrever um programa mais eficiente em relação ao tempo de execução do programa.

  • Em Python, também podemos incluir a biblioteca CS50, mas a 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)
    
  • Podemos substituir expressões em nossas strings formatadas também:

    from cs50 import get_int
    
    idade = get_int("Qual é a sua idade?\n")
    print(f"Você tem pelo menos {idade * 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" or s == "y":
        print("Concordou.")
    elif s == "N" or s == "n":
        print("Não concordou.")
    
    • Python não tem caracteres individuais, então podemos verificá-los como strings diretamente.
    • Também podemos dizer if s in ["Y", "y"]:, ou if s.lower() in ["y"]:.
    • Acontece que strings em Python são como estruturas em C, onde temos não apenas variáveis, mas também funções que podemos chamar. Por exemplo, dado uma string s, podemos chamar sua função lower com s.lower() para obter a versão em minúsculas da string.
  • Podemos melhorar também as versões de cough:

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

    for i in range(3):
        cough()
    
    def cough():
        print("cough")
    
    • Observe que não precisamos especificar o tipo de retorno de uma nova função, que podemos definir com def.

    • Mas isso causa um erro quando tentamos executá-lo: NameError: name 'cough' is not defined. Acontece que precisamos definir nossa função antes de usá-la, então podemos mover a 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 realmente chamamos nossa função main, a função cough já 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 número inteiro positivo:

    from cs50 import get_int
    
    def main():
        i = get_positive_int()
        print(i)
    
    def get_positive_int():
        while True:
            n = get_int("Número 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á indefinidamente, mas usamos o comando break para encerrar o laço assim que n > 0. Então, nossa função apenas retornará 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 assim pode ser acessado posteriormente na função.
  • Podemos imprimir uma fileira de pontos de interrogação na tela:

    for i in range(4):
        print("?", end="")
    print()
    
    • Quando imprimimos cada bloco, não queremos uma 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. Em seguida, depois de imprimir nossa fileira, podemos chamar print para obter uma nova linha.
  • Também podemos "multiplicar" uma string e imprimir isso diretamente com: print("?" * 4).

  • Podemos imprimir uma coluna com um laço:

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

  • Podemos implementar laços 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 incorporada ao 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, então podemos usar get_string que solicitará novamente.

  • Em 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 possa mais caber 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 tantos bits quanto 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 encadeada.
    • 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()
    
    • O Python pegará cada caractere da string para nós.
  • Para tornar uma string maiúscula, também, podemos simplesmente chamar s.upper() para obter a versão em maiúsculas de toda a string, sem precisar iterar sobre cada caractere nós mesmos.

Recursos adicionais

  • Podemos receber argumentos de linha de comando com:

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

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

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

    import sys
    
    nomes = ["EMMA", "RODRIGO", "BRIAN", "DAVID"]
    
    if "EMMA" in nomes:
        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
    
    pessoas = {
        "EMMA": "617-555-0100",
        "RODRIGO": "617-555-0101",
        "BRIAN": "617-555-0102",
        "DAVID": "617-555-0103"
    }
    
    if "EMMA" in pessoas:
        print(f"Encontrado {pessoas['EMMA']}")
        sys.exit(0)
    print("Não encontrado")
    sys.exit(1)
    
    • Observe que podemos obter o valor de uma chave específica em um dicionário com pessoas['EMMA']. Aqui, usamos aspas simples (tanto aspas simples quanto 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 apenas com ==:

    from cs50 import get_string
    
    s = get_string("s: ")
    t = get_string("t: ")
    
    if s == t:
        print("Iguais")
    else:
        print("Diferentes")
    
  • Copiar strings também funciona sem nenhum esforço adicional da nossa parte:

    from cs50 import get_string
    
    s = get_string("s: ")
    
    t = s
    
    t = t.capitalize()
    
    print(f"s: {s}")
    print(f"t: {t}")
    
  • Trocar o valor de duas variáveis também pode ser feito 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
    
    arquivo = open("agenda.csv", "a")
    
    nome = get_string("Nome: ")
    número = get_string("Número: ")
    
    escritor = csv.writer(arquivo)
    escritor.writerow((nome, número))
    
    arquivo.close()
    
    • Acontece que o Python também possui um pacote (biblioteca) chamado csv que nos ajuda a trabalhar com arquivos CSV, então depois de abrirmos o arquivo para adicionar dados, podemos chamar csv.writer para criar um escritor a partir do arquivo e então escritor.writerow para escrever uma linha. Com os parênteses internos, estamos criando uma tupla com os valores que queremos escrever, então estamos passando um único argumento que contém todos os valores para nossa linha.
  • Podemos usar a palavra-chave with, que gentilmente fechará o arquivo para nós:

    ...
    with open("agenda.csv", "a") as arquivo:
        escritor = csv.writer(arquivo)
        escritor.writerow((nome, número))
    

Novas funcionalidades

  • Uma funcionalidade do Python que o C não possui são as expressões regulares, ou padrões contra os quais podemos comparar strings. Por exemplo, sua sintaxe inclui:

    • ., para qualquer caractere
    • .*, para 0 ou mais caracteres
    • .+, para 1 ou mais caracteres
    • ?, para algo opcional
    • ^, para o início da entrada
    • $, para o final da entrada
  • Por exemplo, podemos comparar strings com:

    import re
    from cs50 import get_string
    
    s = get_string("Você concorda?\n")
    
    if re.search("^s(im)?$", s, re.IGNORECASE):
        print("Concordo.")
    elif re.search("^n(ão)?$", s, re.IGNORECASE):
        print("Não concordo.")
    
    • Primeiro, precisamos do pacote re, ou biblioteca, para expressões regulares.
    • Em seguida, para s ou sim, temos a expressão regular ^s(im)?$. Queremos garantir que a string comece com s, e tenha opcionalmente im imediatamente após o s, e então termine.
    • Da mesma forma, para n e não, queremos que nossa string comece, tenha a letra n, e opcionalmente a letra ão em seguida, e então termine. A expressão regular para isso seria ^n(ão)?$.
    • Passamos outro argumento, re.IGNORECASE, para ignorar o caso das letras na string.
    • Se nenhuma expressão regular corresponder, não imprimiríamos nada.
  • No 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
    
    reconhecedor = speech_recognition.Recognizer()
    with speech_recognition.Microfone() as fonte:
        print("Diga algo!")
        áudio = reconhecedor.listen(fonte)
    
    print("O Reconhecimento de Fala do Google pensa que você disse:")
    print(reconhecedor.recognize_google(áudio))
    
    • Acontece que também há outra biblioteca que podemos baixar, chamada speech_recognition, que pode ouvir o áudio e convertê-lo em uma string.
  • Agora, podemos comparar na fala para imprimir algo diferente:

    ...
    palavras = reconhecedor.recognize_google(áudio)
    
    # Responder à fala
    if "olá" in palavras:
        print("Olá para você também!")
    elif "como você está" in palavras:
        print("Estou bem, obrigado!")
    elif "adeus" in palavras:
        print("Adeus para você também!")
    else:
        print("Hã?")
    
  • Podemos até usar expressões regulares para comparar parte de uma string:

    ...
    palavras = reconhecedor.recognize_google(áudio)
    
    correspondências = re.search("meu nome é (.*)", palavras)
    if correspondências:
        print(f"Olá, {correspondências[1]}.")
    else:
        print("Olá, você.")
    
    • Aqui, podemos obter todos os caracteres após meu nome é com .* e imprimi-lo.
  • Executamos detect.py e faces.py, que encontra cada rosto (ou até um rosto específico) em uma foto.

  • qr.py também irá gerar um código QR para uma URL específica.