Novo Blog

Novo endereço

https://blog.nilo.pro.br

terça-feira, 27 de dezembro de 2016

Consultas via Telegram

Leia no novo blog

Seria legal se profissionais de informática dessem consultas como médicos ou advogados, mas algo nos impede de cobrar por tudo e esse desejo ou intenção de compartilhar ideias nos consome.

Eu participo de vários grupos de Telegram, principalmente sobre Python, um deles é o PyCoding e o outro é o pybr. Normalmente eu leio os grupos quando estou usando meu celular, então nem sempre é possível ajudar com as dúvidas, mas vou tentar separar um pouco de tempo para explorar algumas ideias aqui e lá.

Hoje está tão fácil aprender qualquer coisa que tenho notado uma ansiedade cada vez maior de quem começa a programar de aprender tudo. Em um só mês, algumas pessoas querem aprender Python, SciPi, TensorFlow, Android e o que mais der. Um mês é pouco tempo. Pode-se aprender a programar em períodos relativamente pequenos, mas leva tempo para se acostumar com as novas ideias, linguagens e bibliotecas. O Peter Norvig comentou sobre essa ansiedade no Learn Programming in Ten Years.

Cálculo de médias


Vamos ao interesse do post, a tal consulta.

print('-------->DESCUBRA SE VOCE FOI APROVADO OU REPROVADO NA ESCOLA<---------\n-AVISO!!!!\n-ANTES DE COMEÇAR,LEMBRRE-SE QUE NAO E PERMITIDO O USO DE (VIRGULAS),APENAS (PONTOS)')
while True:
nome = input('Digite o nome do aluno: ') #input»comando tipo pergunta ex:digite alguma coisa
m1 = input('Digite a media da sua escola: ')
n1 = input('Digite a primeira nota: ') #nao precisa informar o tipo da variavel,da o nome e qqr valor
n2 = input('Digite a segunda nota: ') #mais precisa declarar a variavel sempre
n3 = input('Digite a terceira nota: ')
n4 = input('Digite a quarta nota: ') #variaveis:int==inteiro:str==string e float
media = float(n1)+float(n2)+float(n3)+float(n4) /4
print("A media do aluno e:",(media))
print('Sendo que a media da escola e:',(m1))#print;comando,escreva
try:
media == 2/0
except Exception as erro:
print('Aconteceu algum erro😨 sistema nao reconhece (virgulas),apenas (pontos)'
'\n»» SE VOCE NAO COMETEU NENHUM ERRO DESCONSIDERE ESSA MENSAGEM. ««')
if float(media) >= float(m1): #if{se}
print((nome),'Foi APROVADO!!!')
else: #else{se nao}
print ((nome), 'SE FUDEU!!!Aluno REPROVADO')
print('.')
print('.') #comparaçoes == igual;>= maior ou igual;<=menor ou igual;!= diferente ou igual
print('.') #comparaçoes; and or
print('.')
print('.')
print('.')
print('.')
print('.')
print('.')
print('.')
print('.')
print( '.............................fim do sistema.................................................' )
view raw wesley2.py hosted with ❤ by GitHub
O colega Wesley enviou dois programas, vou começar pelo mais simples. Primeiro vamos desconsiderar os palavrões, nosso colega é jovem.

Uma coisa que gostei muito foi a primeira linha de mensagens. Poucos se preocupam em dizer o que faz o programa, isso é legal! Eu faria apenas uma pequena modificação para que a linha não fosse tão grande.

Como eu cresci nos anos 80, sem letras minúsculas e acentos, é questão de honra corrigir as mensagens.

Nas linhas 7 a 11, os valores das variávies m1, n1, n2, n3 e n4 são solicitados. Como a função input retorna strings, veja que no resto do programa a função float foi utilizada para converter estes valores. Neste caso, o valor convertido deveria ser armazenado diretamente na variável.

Desta forma, simplificamos a linha 12 de forma a facilmente perceber um erro de prioridade de operações. Quando fazemos o cálculo de n1 + n2 + n3 + n4 / 4, sem utilizar parênteses, as operações são realizados por ordem de prioridade, como na matemática. Assim, n4/4 é somado a n1, n2 e n3. Para calcular a média, precisamos de parênteses: (n1 + n2 + n3 + n4) / 4. Agora, a soma das notas é calculada e depois dividida por quatro, como queríamos.

Entre as linhas 15 e 19 acredito que tenha sido apenas um teste. Vou remover para não atrapalhar o entendimento do programa final.

As linhas de 24 a 35 imprimem vários pontos, vou apenas simplificar.

Para terminar, pequenas modificações para usar as f strings do Python 3.6.

print("""
--------> DESCUBRA SE VOCE FOI APROVADO OU REPROVADO NA ESCOLA <---------
!!!AVISO!!!!
- Antes de começar, lembre-se que não é permitido o uso de vírgulas,
apenas pontos.""")
while True:
nome = input('Digite o nome do aluno: ') #input»comando tipo pergunta ex:digite alguma coisa
m1 = float(input('Digite a média da sua escola: '))
n1 = float(input('Digite a primeira nota: ')) #nao precisa informar o tipo da variavel,da o nome e qqr valor
n2 = float(input('Digite a segunda nota: ')) #mais precisa declarar a variavel sempre
n3 = float(input('Digite a terceira nota: '))
n4 = float(input('Digite a quarta nota: ')) #variaveis:int==inteiro:str==string e float
média = (n1 + n2 +n3 +n4) / 4
print(f"A media do aluno é: {média}")
print(f'Sendo que a média da escola é: {m1}') #print;comando,escreva
if média >= m1: #if{se}
print(f'{nome} - Aluno APROVADO!!!')
else: #else{senao}
print(f"{nome} - Aluno REPROVADO")
print(".\n" * 12)
print("{'fim do sistema':.^80}")
view raw wesley2b.py hosted with ❤ by GitHub

Programa com tkinter

O outro programa é uma interface gráfica, usando tkinter.

from tkinter import messagebox
from tkinter import *
janela = tkinter.Tk()
janela.title('MEDIA ALUNO')
janela.configure(background='#000000')
rotulo = tkinter.Label(janela, text='»»»»»DESCUBRA SE VOCE FOI APROVADO OU REPROVADO NA ESCOLA«««««««',bg='#FFB6C1')
rotulo.pack()
rotulo2 = LabelFrame(janela, text="-AVISO!!!!!!!!",bg='#FFB6C1')
rotulo2.pack(fill="both", expand="yes")
rotulo3 = Label(rotulo2, text="-ANTES DE COMEÇAR,LEMBRRE-SE QUE NAO E PERMITIDO O USO DE (VIRGULAS),APENAS (PONTOS)",bg='#FFB6C1')
rotulo3.pack()
rotulonome =tkinter.Label(janela,text='DIGITE O PRIMEIRO NOME DO ALUNO: ',bg='#FFB6C1') # input»comando tipo pergunta ex:digite alguma coisa
rotulonome.pack()
camponome = tkinter.Entry(bd =5)
camponome.pack()
rotulom1 = tkinter.Label(janela,text='DIGITE A MEDIA DA ESCOLA DO ALUNO: ',bg='#FFB6C1')
rotulom1.pack()
campom1 = tkinter.Spinbox(from_=0, to=10)
campom1.pack()
rotulon1 = tkinter.Label(janela,text='DIGITE A PRIMEIRA NOTA: ',bg='#FFB6C1',bd =5) # nao precisa informar o tipo da variavel,da o nome e qqr valor
rotulon1.pack()
campon1 = tkinter.Entry()
campon1.pack()
rotulon2 = tkinter.Label(janela,text='DIGITE A SEGUNDA NOTA: ',bg='#FFB6C1') # mais precisa declarar a variavel sempre
rotulon2.pack()
campon2 = tkinter.Entry(bd =5)
campon2.pack()
rotulon3 = tkinter.Label(janela,text='DIGITE A TERCEIRA NOTA: ',bg='#FFB6C1')
rotulon3.pack()
campon3 = tkinter.Entry(bd =5)
campon3.pack()
rotulon4 = tkinter.Label(janela,text='DIGITE A QUARTA NOTA: ',bg='#FFB6C1') # variaveis:int==inteiro:str==string e float
rotulon4.pack()
campon4 = tkinter.Entry(bd =5)
campon4.pack()
def resultado():
soma1 = float(campon1.get())+float(campon2.get())+float(campon3.get())+float(campon4.get())
soma = soma1 / 4
if soma <= float(campom1.get()):
tkinter.messagebox.showinfo('»RESULTADO«',(camponome.get(),'SE FUDEU!! ALUNO REPROVADO\n A MEDIA DO ALUNO É: ' +str(soma)))
else:
tkinter.messagebox.showinfo('»RESULTADO«',(camponome.get(),'ALUNO APROVADO \n a media do aluno e: ' + str(soma)))
botao = tkinter.Button(janela, text='ENVIAR',bg='#FFB6C1', command=resultado)
botao.pack()
janela.mainloop()
view raw wesley1.py hosted with ❤ by GitHub
Como os fontes foram postados no Telegram, muito se perde. De cara há um problema com o import da linha 2. Eu parabenizo o Wesley pela coragem de usar o tkinter. É umas das partes do Python que menos gosto, mas que funciona.


Deve-se evitar os import * no Python, isso polui o namespace e causa problemas chatos de resolver. No caso do tkinter, é um caso a se pensar, mas nunca misturar o * com os imports de classes e funções individuais.

Uma coisa que salta aos olhos, não, não falo do fundo caladryl, mas da repetição da cor em várias partes do código. Vamos criar uma constante para cor de fundo, melhor, vamos retirar as cores e deixar as cores padrão.

Um outro problema é a validação de valores, acrescentei uma função float_ou_zero que retorna zero caso o valor digitado não possa ser convertido para float.

Usar tkinter sem classes é um tanto confuso, eu particularmente não gosto de ter funções com variáveis globais e de ter definições de funções e variáveis misturadas, mas isso é assunto para outro post.


import tkinter
import tkinter.messagebox
janela = tkinter.Tk()
janela.title('Média Aluno')
rotulo = tkinter.Label(janela, text='»»»»» Descubra se você foi aprovado ou reprovado na escola «««««««')
rotulo.grid(row=0, column=0, columnspan=2)
rotulo2 = tkinter.LabelFrame(janela, text="AVISO")
rotulo2.grid(row=1, column=0, columnspan=2, padx=10, pady=10)
rotulo3 = tkinter.Label(rotulo2, text="Antes de começar, lembre-se que não é permitido o uso de vírgulas, apenas pontos")
rotulo3.grid(row=2, column=0, columnspan=2, padx=10, pady=10)
rotulonome = tkinter.Label(janela, text='Primeiro nome do aluno:') # input»comando tipo pergunta ex:digite alguma coisa
rotulonome.grid(row=3, column=0, sticky=tkinter.E)
camponome = tkinter.Entry()
camponome.grid(row=3, column=1)
rotulom1 = tkinter.Label(janela, text='Média da escola do aluno:')
rotulom1.grid(row=4, column=0, sticky=tkinter.E)
campom1 = tkinter.Spinbox(from_=0, to=10)
campom1.grid(row=4, column=1)
rotulon1 = tkinter.Label(janela, text='Primeira nota:') # nao precisa informar o tipo da variavel,da o nome e qqr valor
rotulon1.grid(row=5, column=0, sticky=tkinter.E)
campon1 = tkinter.Entry()
campon1.grid(row=5, column=1)
rotulon2 = tkinter.Label(janela, text='Segunda nota:') # mais precisa declarar a variavel sempre
rotulon2.grid(row=6, column=0, sticky=tkinter.E)
campon2 = tkinter.Entry()
campon2.grid(row=6, column=1)
rotulon3 = tkinter.Label(janela, text='Terceira nota:')
rotulon3.grid(row=7, column=0, sticky=tkinter.E)
campon3 = tkinter.Entry()
campon3.grid(row=7, column=1)
rotulon4 = tkinter.Label(janela, text='Quarta nota:') # variaveis:int==inteiro:str==string e float
rotulon4.grid(row=8, column=0, sticky=tkinter.E)
campon4 = tkinter.Entry()
campon4.grid(row=8, column=1)
def float_ou_zero(campo):
try:
v = float(campo.get())
except ValueError:
v = 0.0
return v
def resultado():
soma1 = float_ou_zero(campon1) + float_ou_zero(campon2) + float_ou_zero(campon3) + float_ou_zero(campon4)
soma = soma1 / 4
if soma <= float_ou_zero(campom1):
tkinter.messagebox.showinfo('RESULTADO', f'Aluno {camponome.get()} - REPROVADO\nA média do alunoALUNO é: {soma}')
else:
tkinter.messagebox.showinfo('RESULTADO', f"Aluno {camponome.get()} - APROVADO \nA média do aluno é: {soma}")
botao = tkinter.Button(janela, text='ENVIAR', command=resultado)
botao.grid(row=9, column=0, columnspan=2, padx=10, pady=10)
janela.mainloop()
view raw wesley1b.py hosted with ❤ by GitHub
Vejamos como ficou!




Convertendo ints

Outro post interessante foi o de como converter vários ints de uma só vez. O problema inicial era calcular um valor do tipo hh:mm:ss em total de segundos.

x, y, z = input().split(':')
h = int(x)
m = int(y)
s = int(z)
segundos = h * 3600 + m * 60 + s
print(f"Total de segundos: {segundos}")
view raw gistfile1.txt hosted with ❤ by GitHub

O que me chamou atenção foi uma das soluções:
h, m, s = [int(x) for x in input().split(':')]
view raw solucao1.py hosted with ❤ by GitHub

Correta, porém, achei que o foco da solução não era mais o problema inicial, mas fazer em menos linhas. De repente, passa o medo de "Perlizar" o Python.
O problema em si, exige validação dos dados. Este é um detalhe importante que é fácil de ser esquecido. Então, ao invés de fazer com menos linhas, vamos adicionar o mínimo de validação.
import datetime
def m_int(*args):
return [int(a) for a in args]
while True:
try:
hs = input("Digite a hora a converter (hh:mm:ss): ")
t = datetime.time(*m_int(*hs.split(":")))
break
except ValueError as v:
print(f"Você digitou um valor inválido: {v}. Redigite.")
segundos = t.hour * 3600 + t.minute * 60 + t.second
print(f"Total em segundos: {segundos}")
view raw solucao2.py hosted with ❤ by GitHub
Esta solução utiliza o módulo datetime do Python e o tipo time para validar as horas entre 0 e 23, minutos entre 0 e 60 e o mesmo para segundos. Se o usuário entrar um valor errado, terá que redigitar após receber uma mensagem de erro. Embora eu tenha usado a expansão de listas duas vezes em uma só linha (Perlização?), acho que o código ficou relativamente bom.

São detalhes, mas que fazem a diferença em programas maiores. Nem sempre escrever em menos linhas é o mais correto ou deveria ser o foco principal da solução de um problema.

Ainda sobra margem para uma outra solução, onde criamos uma função para converter horas, minutos e segundos para total em segundos.

import datetime
def m_int(*args):
return [int(a) for a in args]
def horas_para_segundos(shoras):
t = datetime.time(*m_int(*hs.split(":")))
return t.hour * 3600 + t.minute * 60 + t.second
if __name__ == "__main__":
while True:
try:
hs = input("Digite a hora a converter (hh:mm:ss): ")
segundos = horas_para_segundos(hs)
print(f"Total em segundos: {segundos}")
break
except ValueError as v:
print(f"Você digitou um valor inválido: {v}. Redigite.")
view raw solucao3.py hosted with ❤ by GitHub
Além da validação (ainda que mínima), ganhamos a flexibilidade de digitar valores como 10, 10:20 ou 10:20:30. O programa que fizemos pode ser importado por outros programas e suas funções reutilizadas, sem perder a funcionalidade inicial se usado como programa principal.

Um comentário:

Anônimo disse...

Olá. Gostei do seu post pois ele ajuda a adquirir oas práticas quando se está trabalhando com Python. De fato é muito útil, principalmente em uma linguagem como o Python em que alguns detalhes são necessários para que o programa funcione e diferentemente de JS em que é possível escrever todo o código como se fosse um texto escrito em qualquer idioma.
A repeito da "ansiedade para aprender", por assim dier, realmente é algo que atrapalha e às vezes até impossibilita o aprendizado da linguagem principalmente se não é muito difundida como HTML ou Shell. É bem interessante ter abordado esse tema.
Pude ver alguns dos seus posts na comunidade brasileira de Python e espero ter a oportunidade de ler o seu livro.