Você está na página 1de 398

DEFINIÇÃO

As linguagens de programação mais populares por nível, por geração, por


paradigmas, destacando o posicionamento da linguagem Python, critérios
usados na avaliação de linguagens de programação dos diferentes domínios
da aplicação, classificação dos diferentes paradigmas de linguagens de
programação e formas de implementação das linguagens.

PROPÓSITO
Compreender as características e classificações das linguagens de
programação, bem como identificar os paradigmas de aplicação de cada
linguagem para escolher adequadamente a linguagem de programação
conforme o tipo de problema e solução demandada.
OBJETIVOS
MÓDULO 1
Classificar as linguagens de programação

MÓDULO 2
Descrever critérios de avaliação de linguagens de programação

MÓDULO 3
Distinguir os paradigmas e suas características

MÓDULO 4
Identificar métodos de implementação das linguagens

INTRODUÇÃO
Desde o surgimento dos computadores, centenas de linguagens de
programação vêm sendo criadas com o objetivo de permitir ao programador
mais eficiência e conforto ao escrever seus códigos.

Muitos são os problemas que hoje em dia são solucionados com a ajuda de
softwares, escritos sempre em uma linguagem de programação (que por sua
vez também é um software) e muitas vezes esses problemas demandam
diferentes pensamentos computacionais em sua solução.

A classificação das linguagens em paradigmas permite que entendamos qual


é o melhor deles para solucionar determinado problema e, a partir daí, escolher
a linguagem de programação (pertencente a esse paradigma) mais adequada,
conforme características e especificidades do contexto em que se aplica o
problema.

PARADIGMAS
Paradigmas é uma forma de agrupar e classificar as linguagens de
programação baseados em suas funcionalidades.

A linguagem Python foi escolhida como instrumento para o desenvolvimento


desta disciplina, pois além de ser multiparadigma (possibilita escrever
programas em diferentes paradigmas) e de uso geral, vem se destacando e
sendo cada vez mais utilizada entre os novos desenvolvedores por vários
motivos:

 Facilidade de aprendizado;

 Boa legibilidade de código;

 Boa facilidade de escrita;

 Produtividade e confiabilidade.

Possui, ainda, comunidade de desenvolvedores crescente e vasta biblioteca,


repleta de funções, aplicada a diversas áreas da ciência, assim como o
crescente números de frameworks desenvolvidos para a linguagem.

MÓDULO 1

Classificar as linguagens de programação

RAZÕES PARA ESTUDARMOS


LINGUAGENS DE PROGRAMAÇÃO
LINGUAGEM DE PROGRAMAÇÃO E
PRODUTIVIDADE DO PROGRAMADOR
Um programa de computador, ou software, é um conjunto de instruções a fim
de orientar o hardware do computador para o que deve ser feito. O software
pode ser classificado em aplicativo ou básico.

Fonte: Shutterstock
SOFTWARE APLICATIVO
Ou, simplesmente, aplicativo ou app (mundo mobile), que visa oferecer ao
usuário facilidades para realizar uma tarefa laboral ou de lazer.
Fonte: Shutterstock
SOFTWARE BÁSICO
Compreende programas essenciais ao funcionamento do computador. O
sistema operacional é o principal exemplo.

Uma linguagem de programação é um software básico, que permite ao


programador escrever outros programas de computador, seja ela um software
aplicativo ou básico.
Fonte: Shutterstock

A codificação de um programa em uma linguagem de programação, chama-se


programa-fonte, que ainda não pode ser entendido e executado pelo hardware
do computador, pois este apenas entende a linguagem de máquina ou
linguagem binária, na qual cada instrução é uma sequência de bits (0 ou 1).

Uma linguagem de programação é um formalismo com um conjunto de


símbolos, palavras reservadas, comandos, regras sintáticas e semânticas e
outros recursos, que permitem especificar instruções de um programa.

ATENÇÃO
As linguagens de programação surgiram da necessidade de livrar o
programador dos detalhes mais íntimos das máquinas em que a programação
é feita, permitindo a programação em termos mais próximos ao problema, ou
em nível mais alto.

A produtividade de um programador ao escrever código em uma linguagem de


programação está intimamente relacionada à facilidade de aprendizado, leitura
e escrita de programas naquela linguagem, somada a expertise do
programador no contato com a linguagem.

Isto é, quanto mais o programador conhecer as propriedades superlativas


daquela linguagem, melhores e mais eficientes serão os códigos escritos.

O ASPECTO MAIS IMPORTANTE, MAS


TAMBÉM O MAIS ELUSIVO DE QUALQUER
FERRAMENTA, É SUA INFLUÊNCIA NOS
HÁBITOS DAQUELES QUE SE TREINAM NO
SEU USO. SE A FERRAMENTA É UMA
LINGUAGEM DE PROGRAMAÇÃO, ESSA
INFLUÊNCIA É, GOSTEMOS OU NÃO, UMA
INFLUÊNCIA EM NOSSO HÁBITO DE PENSAR.
Edsger W. Dijkstra

O PAPEL DA ABSTRAÇÃO NAS LINGUAGENS


DE PROGRAMAÇÃO
Abstração é o processo de identificação das qualidades e/ou propriedades
relevantes para o contexto que está sendo analisado e desprezando o que seja
irrelevante. Um modelo é uma abstração da realidade.

Um programa de computador é um modelo, pois representa a solução de um


problema em termos algorítmicos. Assim sendo, a abstração permeia toda a
atividade de programação de computadores.

Fonte: Shutterstock

A linguagem de máquina foi a primeira a ser criada para a prática de


programação. Trata-se da linguagem nativa do computador, a única que ele, de
fato, compreende. Uma linguagem muito complicada para ser entendida pelas
pessoas, em que um comando que soma 2 números, é formado por uma
sequência de 1 e 0, muito difícil de ser memorizada, usada e, mais ainda, de
ser entendida por terceiros.
As primeiras linguagens de programação, porém, não reconheciam o papel
crucial que a abstração desempenha na programação. Por exemplo, no início
da década de 1950, o único mecanismo de abstração fornecido pela linguagem
de montagem, ou Assembly, em relação às linguagens de máquina eram os
nomes simbólicos.

VOCÊ SABIA
O programador podia empregar termos relativamente autoexplicativos (nomes
simbólicos) para nomear códigos de operação (ADD = soma, SUB = subtração,
M = multiplicação e DIV = divisão) e posições de memória. A linguagem de
montagem (Assembly) melhorou a vida do programador, porém obrigava-o a
escrever 1 linha de código para cada instrução que a máquina deve executar,
forçando-o a pensar como se fosse uma máquina.

Um pouco mais adiante, visando a aumentar o poder de abstração das


linguagens de forma a permitir uma melhor performance dos programadores,
surgem as linguagens de alto nível, próximas à linguagem humana e mais
distantes das linguagens Assembly e de máquina.

A tabela, a seguir, exibe, à esquerda, um programa-fonte, escrito numa


linguagem de alto nível, a linguagem Python. Ao centro, temos o código
equivalente na linguagem Assembly para o sistema operacional Linux e, à
direita, o respectivo código na linguagem de máquina, de um determinado
processador. Observe:

Linguagem Python Assembly

def swap(self, v, k): swap:

temp = self.v[k]; Muli $2,$5,4

self.v[k] = Add $2,$4,$2

self.v[k+1]; Lw $15,0($2)
Lw $16,4($2)

Sw $16,0($2)
self.v[k+1]= temp;
Sw $15,4($2)

Jr $31

 Atenção! Para visualizaçãocompleta da tabela utilize a rolagem horizontal

LINGUAGEM PYTHON
O programa na linguagem Python tem, na verdade, 3 comandos, que estão nas
linhas 2, 3 e 4. → Linha 1 é a declaração da função Swap.

ASSEMBLY
O programa em linguagem Assembly tem 7 comandos (na linha 1, SWAP não é
um comando, mas um rótulo, nome dado a um trecho de código).

LINGUAGEM DE MÁQUINA
O programa em linguagem de máquina tem 7 comandos, a mesma quantidade
de comandos do mesmo programa em Assembly → paridade de 1 para 1 →
comandos em Assembly → comandos em linguagem de máquina.

A imagem abaixo ilustra o conceito de abstração, em que a partir da linguagem


de máquina, cria-se camadas (de abstração) para facilitar a vida do
programador.
Fonte: AutorCrescimento do nível de abstração. Fonte: Autor.

NÍVEL 1
É representado pelo hardware, conjunto de circuitos eletrônicos.

NÍVEL 2
É representado pela linguagem de máquina (1 e 0), única que o hardware
entende.

NÍVEL 3
É representado pela linguagem Assembly (mneumônicos).

NÍVEL 4
É representado pelas linguagens de alto nível, próximas à língua do usuário e
distantes da linguagem computacional. Python e Java são linguagens de
programação representativas da classe LP de alto nível (LP = Linguagem de
Programação).

POR QUE ESTUDAR LINGUAGENS DE PROGRAMAÇÃO?

O estudante e/ou programador que se dispuser a gastar seu tempo


aprendendo linguagens de programação terá as seguintes vantagens:

 Maior capacidade de desenvolver soluções em termos de programas


— compreender bem os conceitos de uma LP pode aumentar a
habilidade dos programadores para pensar e estruturar a solução de
um problema.

 Maior habilidade em programar numa linguagem, conhecendo melhor


suas funcionalidades e implementações, ajuda para que o
programador possa construir programas melhores e mais eficientes.
Por exemplo, conhecendo como as LPs são implementadas,
podemos entender melhor o contexto e decidir entre usar ou não a
recursividade, que se mostra menos eficiente que soluções iterativas.

 Maiores chances de acerto na escolha da linguagem mais adequada


ao tipo de problema em questão, quando se conhece os recursos e
como a linguagem os implementa. Por exemplo, saber que a
linguagem C não verifica, dinamicamente, os índices de acesso a
posições de vetores pode ser decisivo para sua escolha em soluções
que usem frequentemente acessos a vetores.

 Maior habilidade para aprender novas linguagens. Quem domina os


conceitos da orientação a objeto, tem mais aptidão para aprender
Python, C++, C# e Java.

 Amplo conhecimento dos recursos da LP reduz as limitações na


programação.

 Maior probabilidade para projetar novas LP, aos que se interessarem


por esse caminho profissional: participar de projetos de criação de
linguagens de programação.

 Aumento da capacidade dos programadores em expressar ideias. Em


geral, um programador tem expertise em poucas variedades de
linguagens de programação, dependendo do seu nicho de trabalho.
Isso, de certa forma, limita sua capacidade de pensar, pois ele fica
restrito pelas estruturas de dados e controle que a(s) linguagem(ns)
de seu dia a dia permitem. Conhecer uma variedade maior de
recursos das linguagens de programação pode reduzir tais limitações,
levando, ainda, os programadores a aumentar a diversidade de seus
processos mentais.

Quanto maior for o leque de linguagens que um programador dominar e


praticar, maiores as chances de conhecer e fazer uso das propriedades
superlativas da(s) linguagem(ns) em questão.

CLASSIFICAÇÃO DAS LINGUAGENS


DE PROGRAMAÇÃO
Ao longo dos anos, os autores têm criado diferentes classificações para as
linguagens de programação, usando critérios diferenciados e agrupando-as sob
diferentes perspectivas.

Veremos a seguir as classificações das linguagens por nível, por gerações e


por paradigmas.

CLASSIFICAÇÃO POR NÍVEL


A classificação por nível considera a proximidade da linguagem de
programação com as características da arquitetura do computador ou com a
comunicação com o homem.

LINGUAGEM DE BAIXO NÍVEL


São linguagens que se aproximam da linguagem de máquina, além da própria,
que se comunicam diretamente com os componentes de hardware, como
processador, memória e registradores. As linguagens de baixo nível estão
relacionadas à arquitetura de um computador.

São linguagens escritas usando o conjunto de instruções do respectivo


processador. Ou seja, cada processador diferente (ou família de processador,
como os I3, I5 e I7 da Intel) tem um conjunto de instruções específicos
(instructions set).

Abaixo, a imagem ilustra a representação de uma instrução em linguagem de


máquina ou binária de um processador específico. A instrução tem palavras
(unidade executada pelo processador) de 16 bits, sendo 4 bits para representar
a instrução (código da instrução), 6 bits para representar cada operando.

Fonte: AutorInstrução em linguagem de máquina. Fonte: Autor

Imagine, agora, uma sequência de 0 e 1 para que possamos dizer ao


processador cada ação que deve ser realizada conforme ilustrado abaixo.

0001001010001111

1010010001000010

0010101110110111

0101010000000111

Era de fato muito complexa a programação na linguagem de máquina, a


linguagem nativa dos processadores.

Essa complexidade motivou o desenvolvimento da linguagem Assembly, que


deixava de ser a linguagem nativa dos processadores, mas usava das
instruções reais dos processadores. Assim, a instrução na linguagem Assembly
precisa ser convertida para o código equivalente em linguagem de máquina.

EXEMPLO
As três linhas de código na linguagem Assembly, abaixo, que move o numeral
2 para o registrador AX (linha 1), move o numeral 1 para o registrador BX (linha
2) e soma o conteúdo dos 2 registradores (linha 3).
MOV AX, 0002
MOV BX, 0001
ADD AX, BX

Não chega a ser o ideal em termos de uma linguagem, que é ainda próxima da
máquina, mas já foi um grande avanço em relação à memorização da
sequência de 0 e 1 de uma instrução de máquina.

Linguagens de baixo nível estão distantes da língua humana (escrita).

LINGUAGEM DE ALTO NÍVEL


No outro extremo das linguagens de baixo nível, estão as linguagens de alto
nível, na medida em que se afastam da linguagem das máquinas e se
aproximam da linguagem humana (no caso, a linguagem escrita e a grande
maioria em Inglês).

VOCÊ SABIA
Quem programa em uma linguagem de alto nível não precisa conhecer
características dos componentes do hardware (processador, instruções e
registradores). Isso é abstraído no pensamento computacional.

As instruções das linguagens de alto nível são bastante abstratas e não estão
relacionadas à arquitetura do computador diretamente. As principais
linguagens são:
ASP, C, C++, C#, Pascal, Delphi, Java, Javascript, Lua, MATLAB, PHP e
Ruby, dentre outras.
EXEMPLO
Abaixo, o mesmo código expresso acima, escrito em Assembly, porém usando
variáveis, como abstração do armazenamento e codificado na linguagem
Python.
def main():

num1 = 2

num2 = 1

soma = num1 + num2

Abaixo, o mesmo código na linguagem C:

int num1, num2, soma;

int main()

num1=2;

num1=1;

soma=num1+num2;

Cada comando de uma linguagem de alto nível precisa ser convertido e


equivalerá a mais de uma instrução primária do hardware. Isso significa que,
numa linguagem de alto nível, o programador precisa escrever menos código
para realizar as mesmas ações, além de outras vantagens, aumentando
consideravelmente a sua eficiência ao programar.

 SAIBA MAIS
Há uma curiosidade: C e C++ são classificados por alguns autores como
linguagem de médio nível, na medida que estão próximas da linguagem
humana (linguagem de alto nível), mas também estão próximas da máquina
(linguagem de baixo nível), pois possuem instruções que acessam diretamente
memória e registradores. Inicialmente, a linguagem C foi criada para
desenvolver o sistema operacional UNIX, que até então era escrito em
Assembly.

Outro dado que merece ser comentado é que algumas pessoas consideram a
existência de linguagens de altíssimo nível, como Python, Ruby e Elixir, por
serem linguagens com uma enorme biblioteca de funções e que permitem a
programação para iniciantes sem muito esforço de aprendizado.
CLASSIFICAÇÃO POR GERAÇÕES
Outra forma de classificar as linguagens, amplamente difundida, é por
gerações. Não há um consenso sobre as gerações, alguns consideram 5,
outros 6. A cada geração, novos recursos facilitadores são embutidos nas
respectivas linguagens.

Fonte: Autor

Assista ao vídeo a seguir e observe a classificação das LPs em níveis e


gerações.

Veja um pouco mais sobre as gerações:

LINGUAGENS DE 1ª GERAÇÃO (LINGUAGEM DE MÁQUINA)


A 1ª geração de linguagens é representa pela linguagem de máquina, nativa
dos processadores.

LINGUAGENS DE 2ª GERAÇÃO (LINGUAGEM DE MONTAGEM –


ASSEMBLY)

As linguagens de segunda geração são denominadas Assembly e são


traduzidas para a linguagem de máquina por um programa especial
(montador), chamado Assembler. A partir dessa geração, toda linguagem vai
precisar de um processo de conversão do código nela escrito, para o código
em linguagem de máquina.

Acompanhe o exemplo abaixo para uma CPU abstrata. Considere a seguinte


sequência de 3 instruções em linguagem Assembly:

Código em Assembly

Mov #8, A Lê um valor da posição de memória

Mov #9, B Lê um valor da posição de memória

ADD A,B Soma os valores armazenados nos r

 Atenção! Para visualizaçãocompleta da tabela utilize a rolagem horizontal

Em linguagem de máquina, depois de traduzidas pelo Assembler, as instruções


poderiam ser representadas pelas seguintes sequências de palavras binárias:

Código em Assembly

Mov #8, A 01000011 1100100


Mov #9, B 01000011 1100100

ADD A,B 01010100 0110000

 Atenção! Para visualizaçãocompleta da tabela utilize a rolagem horizontal

Houve um aumento significativo no nível de abstração, mas parte da


dificuldade permanece, pois o programador, além de necessitar memorizar os
mneumônicos, precisa conhecer a arquitetura do computador como forma de
endereçamento dos registradores e memória, além de outros aspectos.

LINGUAGENS DE 3ª GERAÇÃO (LINGUAGENS PROCEDURAIS)

São as, também, linguagens de alto nível, de aplicação geral, em que uma
única instrução em uma linguagem próxima a do homem pode corresponder a
mais de uma instrução em linguagem de máquina.

Caracterizam-se pelo suporte a variáveis do tipo simples (caractere, inteiro, real


e lógico) e estruturados (matrizes, vetores, registros), comandos condicionais,
comando de iteração e programação modular (funções e procedimentos),
estando alinhadas à programação estruturada.

O processo de conversão para a linguagem de máquina ficou mais complexo e


ficaram a cargo dos interpretadores e tradutores. As primeiras linguagens de 3ª
geração que foram apresentadas ao mercado são: Fortran, BASIC, COBOL, C,
PASCAL, C, dentre outras.

Esta geração de linguagens apresenta as seguintes propriedades em comum:

 Armazenar tipos de dados estaticamente: simples, estruturados e


enumerados.

 Alocar memória dinamicamente, através de ponteiros, que são


posições de memória cujo conteúdo é outra posição de memória.
 Disponibilizar: estruturas de controle sequencial, condicional,
repetição e desvio incondicional.

 Permitir a programação modular, com uso de parâmetros.

 Operadores: relacionais, lógicos e aritméticos.

 Ênfase em simplicidade e eficiência.

LINGUAGENS DE 4ª GERAÇÃO (LINGUAGENS APLICATIVAS)

São, também, linguagens de alto nível, com aplicação e objetivos bem


específicos.

Enquanto as linguagens de 3ª geração são procedurais, ou seja, especifica-se


passo a passo a solução do problema, as de 4ª geração são não procedurais.
O programador especifica o que deseja fazer e não como deve ser feito.

O melhor exemplo de linguagens de 4ª geração é a SQL (Structured Query


Language), utilizada para consulta à manipulação de banco de dados.
PostScript e MATLAB são outros dois exemplos de linguagens de 4ª geração.

LINGUAGENS DE 5ª GERAÇÃO (VOLTADAS À INTELIGÊNCIA ARTIFICIAL)

São linguagens declarativas e não algorítmicas. Exemplos: Lisp e Prolog. As


linguagens de 5ª geração são usadas para desenvolvimento de sistemas
especialistas (área da IA), de sistemas de reconhecimento de voz e machine
learning.

A imagem a seguir ilustra as características de cada geração.

Alguns autores classificam a 6ª geração, como uma evolução da 5ª, em que


prevalecem as aplicações de redes neurais, uma outra vertente da Inteligência
Artificial.
Fonte: Autor

VERIFICANDO O APRENDIZADO
1. AVALIE AS ASSERTIVAS SOBRE AS LINGUAGENS DE
PROGRAMAÇÃO:
I. LINGUAGEM ASSEMBLY É A NATIVA DOS
COMPUTADORES.
II. UMA LINGUAGEM DEVE SER COMPATÍVEL ÚNICA E
EXCLUSIVAMENTE COM O HARDWARE A QUE SE PROPÔS
A ATENDER.
II. A ABSTRAÇÃO TRAZ FACILIDADES AO PROGRAMADOR
QUE CADA VEZ MENOS PRECISA CONHECER O AMBIENTE
ONDE A LINGUAGEM OPERA (COMPOSTO POR SISTEMA
OPERACIONAL E HARDWARE).
IV. UM COMANDO EM UMA LINGUAGEM DE ALTO NÍVEL
FAZ MAIS QUE UMA OPERAÇÃO PRIMÁRIA DO HARDWARE.
COM BASE EM SUA ANÁLISE, MARQUE A OPÇÃO QUE
APRESENTA APENAS AS ASSERTIVAS CORRETAS.
I, II, III e IV

III e IV apenas

III apenas
II e IV apenas

2. RELACIONE A COLUNA A, NA QUAL TEMOS AS


GERAÇÕES DAS LINGUAGENS DE PROGRAMAÇÃO COM A
COLUNA B, EM QUE TEMOS AS CARACTERÍSTICAS DAS
GERAÇÕES DE LINGUAGENS:

A – GERAÇÕES

1 – 1ª GERAÇÃO A – LINGUAGEM DE ALTO NÍVEL

2 – 3ª GERAÇÃO B – LINGUAGEM ASSEMBLY

3 – 4ª GERAÇÃO C – LINGUAGEM DE MÁQUINA

4 – 2ª GERAÇÃO D – LINGUAGENS NÃO PROCEDI

 ATENÇÃO! PARA VISUALIZAÇÃOCOMPLETA DA TABELA


UTILIZE A ROLAGEM HORIZONTAL

COM BASE EM SUA ANÁLISE, MARQUE A OPÇÃO QUE


RELACIONA CORRETAMENTE AS DUAS COLUNAS A E B:

1-c, 2-a, 3-d, 4-b

1-a, 2-c, 3-d, 4-b

1-d, 2-b, 3-a, 4-c

1-b, 2-c, 3-d, 4-a


GABARITO

1. Avalie as assertivas sobre as linguagens de programação:

I. Linguagem Assembly é a nativa dos computadores.


II. Uma Linguagem deve ser compatível única e exclusivamente com o
hardware a que se propôs a atender.
II. A abstração traz facilidades ao programador que cada vez menos precisa
conhecer o ambiente onde a linguagem opera (composto por sistema
operacional e hardware).
IV. Um comando em uma linguagem de alto nível faz mais que uma operação
primária do hardware.

Com base em sua análise, marque a opção que apresenta apenas as


assertivas corretas.
A alternativa "B " está correta.

Analisando cada assertiva, temos:

I. A linguagem de máquina é a que o computador entende, sendo, portanto, a


nativa – Falso.

II. A linguagem deve ser compatível com o sistema operacional principalmente


que, por sua vez, tem suas definições de hardware suportadas ‒ Falso.

III. Verdadeiro, a abstração concentra-se no que importa e deixa de lado o


irrelevante.

IV. Verdadeiro, pois os comandos são próximos do pensamento e fala do


homem, facilitando a programação.

2. Relacione a coluna A, na qual temos as gerações das linguagens de


programação com a coluna B, em que temos as características das
gerações de linguagens:
A – Gerações

1 – 1ª geração a – Linguagem de alto nível

2 – 3ª geração b – Linguagem Assembly

3 – 4ª geração c – Linguagem de máquina

4 – 2ª geração d – Linguagens não procediment

 Atenção! Para visualizaçãocompleta da tabela utilize a rolagem horizontal

Com base em sua análise, marque a opção que relaciona corretamente as


duas colunas A e B:

A alternativa "A " está correta.

Analisando cada assertiva, temos:

1ª geração – Linguagem de máquina, a nativa dos computadores. Primórdios


da computação.

2ª geração – Linguagem Assembly, na qual surgem os mneumônicos, como


abstração primeira.

3ª geração – Linguagens de alto nível, mais próximas à linguagem humana.


4ª geração – Linguagens em que se define a solução de forma não
procedimental, ao contrário das linguagens de 3ª geração.

MÓDULO 2

Descrever critérios de avaliação de linguagens de programação

Considerando as diversas linguagens de programação existentes hoje no


mercado, atendendo a propósito comuns, vamos destacar neste módulo os
domínios da programação, que são seis:

Aplicações científicas

Aplicações comerciais

Aplicações com Inteligência Artificial

Programação de sistemas

Programação para web

Programação mobile

Na sequência, apresentaremos critérios que podem ser usados para avaliação


de linguagens de programação, claro, dentro do mesmo domínio de
programação.

DOMÍNIOS DA PROGRAMAÇÃO
Fonte: Autor

O computador tem sido usado para diversos fins, na ciência, nas forças
armadas, nas empresas públicas e privadas, pelos profissionais liberais, pelas
pessoas em seus lazeres e onde mais possa ser aplicado. Seu uso vai desde
controlar robôs que fazem a montagem de automóveis em suas linhas de
montagem até jogos digitais. Em função desse uso adverso, surgiram
linguagens de programação com diferentes objetivos. A seguir, discutiremos as
principais áreas e as respectivas linguagens de programação em destaque.

APLICAÇÕES CIENTÍFICAS (MÁQUINAS DE CALCULAR COM ALTA


PRECISÃO)

O primeiro computador, o ENIAC, foi desenvolvido por 3 anos e ficou pronto no


ano de 1946. Sua principal finalidade eram cálculos balísticos. Os
computadores seguintes, nas décadas de 1940 e 1950, também focaram em
cálculos científicos complexos.

As linguagens de programação nessa época eram a linguagem de máquina e


Assembly. Na década de 1960 surgem as primeiras linguagens de
programação de alto nível, com destaque para Fortran (iniciais de FORmula
TRANslator) e posteriormente para ALGOL60. As principais características
dessas linguagens eram:

 Estruturas de dados simples.

 Alto volume de cálculos com aritmética de ponto flutuante (precisão).

 Preocupação com a eficiência, pois sucederam a linguagem


Assembly.

APLICAÇÕES COMERCIAIS

A segunda onda de aplicativos foi para suprir as demandas das empresas a


partir de meados da década de 1950. Em 1960, surge a linguagem que seria o
ícone das aplicações comerciais de computadores de grande porte, naquele
momento, o COBOL. As linguagens de programação que apoiaram o
crescimento das aplicações comerciais têm como características:

 Facilidade para produzir relatórios, fundamentais nos controles das


operações contábeis, bancárias, estoque e financeiras (primeiros
focos da época).

 Precisão com números decimais e ponto flutuante, para representar


as altas cifras das grandes empresas, as primeiras a investirem
nessas aplicações.

 Capacidade de especificar operações aritméticas comerciais.

Cabe destacar que as linguagens destinadas a aplicações comerciais ganham


força com a microcomputação a partir dos anos 1980, levando as aplicações
comerciais aos médios e pequenos empresários.

APLICAÇÕES COM INTELIGÊNCIA ARTIFICIAL

As linguagens que sustentam o desenvolvimento de aplicações apoiadas na


Inteligência Artificial (IA) ganham força nos dias de hoje.
A grande ruptura no pensamento computacional é que as linguagens que
apoiam a IA usam a computação simbólica e não numérica, como a maioria
das linguagens da época. Em 1959, surge a linguagem Lisp, primeira
linguagem projetada para apoio à computação simbólica, primeira referência da
computação funcional. Prolog, criada em 1977, foi a primeira linguagem para
apoio da computação lógica, essência dos sistemas especialistas (sistemas
que usam IA para simular o comportamento humano).

PROGRAMAÇÃO DE SISTEMAS

A programação de sistemas cabe a linguagens de programação que tenham


comandos e estruturas para acessar, diretamente, o hardware. Tais linguagens
são usadas para desenvolver softwares básicos, como sistemas operacionais,
tradutores e interpretadores de linguagens de programação. Antes de surgir a
linguagem C, usada para desenvolver o sistema operacional Linux, Assembly
era a linguagem usada para esse fim. A linguagem C++ também é usada com
essa finalidade.

PROGRAMAÇÃO PARA WEB

Com o crescimento da internet e tecnologias adjacentes, o uso dos sistemas se


desloca do ambiente desktop (domínio dos anos 1980 e 1990) para o ambiente
Web.

No contexto de programação para Web, temos 2 diferentes ambientes de


desenvolvimento: a camada de apresentação, que roda no navegador (lado
cliente) e a camada de lógica do negócio, que roda nos servidores web (lado
servidor), juntamente com a camada de persistência, considerando o modelo
de desenvolvimento em 3 camadas (apresentação, lógica do negócio e
persistência de dados).

Para a camada de apresentação, usa-se as linguagens HTML (linguagem de


marcação) e CSS (usada em conjunto com HTML para definir a apresentação
da página web), além de JavaScript (programação de scripts), no lado cliente
(navegadores).

Para o desenvolvimento das camadas de lógica do negócio, as principais LP


são: C#, PHP, ASP, .NET, Java, Ruby e Python.

PROGRAMAÇÃO MOBILE

Considerando que hoje em dia, grande parte da população, no Brasil e no


Mundo, tem acesso à internet pelo celular, cresceu vertiginosamente a
quantidade de apps (aplicativos) para uso de aplicações via celular. Os apps,
na verdade, são interfaces que rodam no lado cliente.

As principais (não todas) linguagens que apoiam o desenvolvimento de apps


para o mundo mobile, oficialmente indicadas por seus fabricantes, são:

 Android: Java e Kotlin.

 iOS: Swift (oficial da Apple) e Objective-C (código nativo para iOS).

 Windows: C#, Visual Basic (VB), C++, HTML, CSS, JavaScript e


Java.

O desenvolvimento de APP para iOS é baseado numa IDE chamada Xcode


que permite o desenvolvimento de APP em várias linguagens, como: C, C++,
Java e Python, mas oficialmente orienta o Swift e Objective-C.

A Google, por sua vez, tem por base o Android SDK, orienta a usar as
linguagens Kotlin, Java e C++, mas as linguagens Python, Shell script,
Basic4Android, LiveCode (para iOS e Windows também), App Inventor (não
necessita conhecer programação) e Unity (motor para games) e GO, também
são usadas para desenvolver app para Android.

No contexto de desenvolvimento de APP para Windows, foi lançado no


Windows 8.1 e atualizado para atender também ao Windows 10, o App Studio,
que permite a qualquer pessoa criar em poucos passos um app Windows e
publicá-lo na loja.
Importante destacar que hoje existem plataformas de desenvolvimento mobile
conectadas a nuvem que fomentam o desenvolvimento de apps nativos para
iOS, Android e Windows.

AVALIAÇÃO DE LINGUAGENS DE
PROGRAMAÇÃO
Segundo Sebesta (2018) são quatro grandes critérios para avaliação das
linguagens de programação, dentro de um mesmo domínio de programação.
Cada critério é influenciado por algumas características da linguagem.

Fonte: Shutterstock
LEGIBILIDADE
Um dos critérios mais relevantes é a “facilidade com que os programas podem
ser lidos e entendidos” pelas pessoas que não necessariamente participaram
do desenvolvimento.
Fonte: Shutterstock
FACILIDADE DE ESCRITA
O quão facilmente uma linguagem pode ser usada para desenvolver programas
para o domínio do problema escolhido.

Fonte: Shutterstock
CONFIABILIDADE
Um programa é dito confiável se ele se comporta conforme a sua
especificação, repetidas vezes.
Fonte: Shutterstock
CUSTO
O custo final de uma linguagem de programação é em função de muitas de
suas propriedades e características.

A tabela a seguir exibe as características da linguagem que influenciam cada


um dos três principais fatores de avaliação de linguagens.

Características Legibilidade

Simplicidade

Ortogonalidade

Estruturas de controle
Tipos de dados

Projeto de sintaxe

Suporte para abstração

Expressividade

Verificação de tipos

Tratamento de exceções

Aliasing

Características x Critérios de Avaliação de LPs

 Atenção! Para visualizaçãocompleta da tabela utilize a rolagem horizontal


LEGIBILIDADE
Um dos critérios mais relevantes para avaliar uma linguagem de programação
diz respeito à capacidade com que os programas podem ser lidos e entendidos
pela sintaxe e construção da linguagem, sem considerar as possíveis
influências da má programação.

As características que influenciam a legibilidade de uma linguagem de


programação são:

SIMPLICIDADE

Quanto mais simples for uma linguagem, melhor será a legibilidade do código
por ela produzido. Uma linguagem com número elevado de construções
básicas é mais difícil de ser aprendida do que uma que tenha poucas. Tende a
ser subutilizada.

Uma segunda característica que afeta negativamente a legibilidade é a


multiplicidade de recursos. Por exemplo, em Python, o programador pode
incrementar uma variável, de duas formas distintas:

 cont= cont + 1;

 cont +=1.

Nas linguagens C e Java, ainda podemos usar para incrementar variáveis as


seguintes estruturas: ++cont e cont++.

Muita simplicidade pode tornar menos legíveis os códigos escritos. Na


linguagem Assembly, a maioria das sentenças são simples, porém não são
altamente legíveis devido à ausência de estruturas de controle.

Uma terceira característica que afeta negativamente a legibilidade é a


sobrecarga de operadores, como por exemplo o “+”, usado para somar inteiros,
reais, concatenar cadeias de caracteres (strings), somar vetores, dentre outras
construções permitidas pela linguagem.
ORTOGONALIDADE

A ortogonalidade de uma linguagem refere-se a um conjunto relativamente


pequeno de construções primitivas que pode ser combinado em um número,
também, pequeno de maneiras para construir as estruturas de controle e de
dados de uma linguagem de programação.

Em outras palavras: possibilidade de combinar, entre si, sem restrições, as


construções básicas da linguagem para construir estruturas de dados e de
controle.

 Boa ortogonalidade: Permitir, por exemplo, que haja um vetor, cujos


elementos sejam do tipo registro (estrutura heterogênea).

 Má ortogonalidade: Não permitir que um vetor seja passado como


argumento para uma rotina (procedimento ou função). Ou que uma
função não possa retornar um vetor.

Uma linguagem ortogonal tende a ser mais fácil de aprender e tem menos
exceções.

A falta de ortogonalidade leva a muitas exceções às regras da linguagem e ao


excesso, o contrário (menos exceções às regras). Menos exceções implicam
um maior grau de regularidade no projeto da linguagem, tornando-a mais fácil
de ler, entender e aprender.

INSTRUÇÕES DE CONTROLE

Instruções como Goto (desvio incondicional) limitam a legibilidade dos


programas, pois essa instrução pode levar o controle do código a qualquer
ponto do programa, limitando o entendimento e, consequentemente, a
legibilidade do código escrito na linguagem. As linguagens modernas não
implementam desvio incondicional, assim sendo, o projeto de estruturas de
controle é menos relevante na legibilidade do que anos atrás, quando surgiram
as primeiras linguagens de alto nível.
TIPOS E ESTRUTURAS DE DADOS

A facilidade oferecida pela linguagem para definir tipos e estruturas de dados é


outra propriedade que aumenta a legibilidade do código escrito. Por exemplo,
uma linguagem que permita definir registros e vetores, mas não permite que
um vetor tenha registros como seus elementos, terá a legibilidade afetada.

A linguagem C não possui o tipo de dado lógico ou booleano. Muitas vezes,


usa-se variáveis inteiras, permitindo apenas que receba os valores 0 e 1 para
conteúdo, simulando o tipo booleano. Por exemplo, para localizar um elemento
em uma das posições de um vetor, usa-se uma variável lógica se a linguagem
permitir e, assim, teríamos a instrução “achou=false” em determinado trecho de
código. Em outra linguagem que não permita o tipo de dado lógico, a instrução
poderia ser “achou=0”, em que achou seria uma variável inteira. Qual das duas
sentenças é mais clara a quem lê o código? A primeira, não é? “achou=false”.

SINTAXE

A sintaxe tem efeito sobre a legibilidade. Um exemplo é a restrição do tamanho


(quantidade de caracteres) para um identificador (tipo, variável, constante,
rotina – procedimento e função), impedindo que recebam nomes significativos
sobre sua utilidade. Na linguagem Fortran, o nome do identificador pode ser até
6 caracteres.

Outra propriedade de sintaxe que afeta a legibilidade é o uso de palavras


reservadas da linguagem. Por exemplo, em Pascal, os blocos de instrução são
iniciados e encerrados com BEGIN-END, respectivamente. A linguagem C usa
chaves para iniciar e encerrar blocos de instruções. Já a linguagem Python usa
a endentação obrigatória para marcar blocos de comandos, aumentando a
legibilidade, naturalmente.

FACILIDADE DE ESCRITA
(REDIGIBILIDADE)
A facilidade de escrita é a medida do quão fácil a linguagem permite criar
programas para um domínio da aplicação.

A maioria das características que afeta a legibilidade também afeta a facilidade


de escrita, pois se a escrita do código não flui, haverá dificuldade para quem for
ler o código.

As características que influenciam na facilidade de escrita são:

SIMPLICIDADE E ORTOGONALIDADE

Quanto mais simples e ortogonal for a linguagem, melhor sua facilidade para
escrever programas. O ideal são linguagens com poucas construções
primitivas.

Imagina que uma linguagem de programação possui grande número de


construções. Alguns programadores podem não usar todas, deixando de lado,
eventualmente, as mais eficientes e elegantes.

EXPRESSIVIDADE

Uma linguagem de programação com boa expressividade contribui para o


aumento da facilidade de escrita dos códigos.

 Assembly: Baixa expressividade.

 Pascal e C, boa expressividade: Ricas estruturas de controle.


Exemplo: o comando FOR mais adequado que WHILE e REPEAT
para representar lações com número fixo de vezes. Da mesma forma
que o C, em que o FOR é mais indicado que o WHILE e DO-WHILE.
Na linguagem Python, ocorre o mesmo entre os comandos FOR e
WHILE.

 Na linguagem C, temos construções diversas para incremento de


variável: i++ é mais simples e conveniente de usar do que i=i+1,
sendo i, uma variável inteira.
Uma linguagem expressiva possibilita escrever linhas de código de uma forma
mais conveniente ao invés de deselegante.

SUPORTE PARA A ABSTRAÇÃO

O grau de abstração em uma linguagem é uma propriedade fundamental para


aumentar a facilidade de escrita. Abstração pode ser de:

 Processos, como o conceito de subprograma.

 Dados, como uma árvore ou lista simplesmente encadeada.

CONFIABILIDADE
Dizemos que um programa é confiável se ele se comportar conforme sua
especificação, sob todas as condições, todas as vezes em que for executado.

Abaixo, alguns recursos das linguagens que exercem efeito sobre a


confiabilidade de programas.

VERIFICAÇÃO DE TIPOS

Significa verificar, em tempo de compilação ou execução, se existem erros de


tipo. Por exemplo, atribuir um valor booleano a uma variável do tipo inteira, vai
resultar em erro. As linguagens fortemente tipadas, em tempo de compilação,
como Python e Java, tendem a ser mais confiáveis, pois apenas valores
restritos aos tipos de dados declarados poderão ser atribuídos e diminuem os
erros em tempo de execução. Linguagens, como C, em que não é verificado se
o tipo de dado do argumento é compatível com o parâmetro, em tempo de
compilação, podem gerar erros durante a execução, afetando a confiabilidade.
A verificação de tipos em tempo de compilação é desejável, já em tempo de
execução é dispendiosa (mais lenta e requer mais memória), e mais flexível
(menos tipada).

TRATAMENTO DE EXCEÇÃO

O tratamento de exceção em uma linguagem de programação garante a


correta execução, aumentando a confiabilidade. As linguagens Python, C++ e
Java possuem boa capacidade de tratar exceções, ao contrário da linguagem
C. A linguagem deve permitir a identificação de eventos indesejáveis (estouro
de memória, busca de elemento inexistente, overflow etc.) e especificar
respostas adequadas a cada evento. O comportamento do programa torna-se
previsível com a possibilidade de tratamento das exceções, o que tende a
aumentar a confiabilidade do código escrito na linguagem de programação.

ALIASING (APELIDOS)

Aliasing é o fato de ter dois ou mais nomes, referenciando a mesma célula de


memória, o que é um recurso perigoso e afeta a confiabilidade. Restringir
Aliasing é prover confiabilidade aos programas.

LEGIBILIDADE E FACILIDADE DE ESCRITA

Ambos influenciam a confiabilidade. A legibilidade afeta tanto na fase de


codificação como na fase de manutenção. Programas de difícil leitura são
difíceis de serem escritos também.

Uma linguagem com boa legibilidade e facilidade de escrita gera códigos


claros, que tendem a aumentar a confiabilidade.

CUSTO
O custo de uma linguagem de programação varia em função das seguintes
despesas: de treinamento, de escrita do programa, do compilador, de execução
do programa, de implementação da linguagem e o de manutenção do código.

Custo de

Custo de Treinamento para programadores varia em função da e


Treinamento
F (simplicidade de escrita, ortogonalidade, experiência do program
Custo para escrever programas na linguagem varia em função da
Escrever programa
F(Facilidade de escrita).

Esse custo varia em função do custo de aquisição do compilador,


Compilar o programa
F (custo de aquisição do compilador).

Custo para executar programas, varia em função do projeto da lin


Executar o programa
F (Projeto da linguagem).

Implementar a A popularidade da LP vai depender de um econômico sistema de


linguagem interpretadores gratuitos.

O custo da má confiabilidade: se um sistema crítico falhar, o cust


Confiabilidade
usina nuclear.

Custo de manutenção: depende de vários fatores, mas principalm


Manutenção
pessoas que não participaram do desenvolvimento do software.

 Atenção! Para visualizaçãocompleta da tabela utilize a rolagem horizontal

Os custos em treinamento e de escrever o programa podem ser minimizados


se a linguagem oferecer bom ambiente de programação.
Python é uma linguagem com alta legibilidade, facilidade de escrita, além de
confiável. Seu custo não é elevado, pois além de ser open source, é fácil de
aprender.

ATENÇÃO
Existem outros critérios, como por exemplo a portabilidade ou a capacidade
que os programas têm de rodarem em ambientes diferentes (sistema
operacional e hardware), o que é altamente desejável. A reusabilidade, ou seja,
o quanto um código pode ser reutilizado em outros programas ou sistemas
aumenta o nível de produtividade da linguagem. Além da facilidade de
aprendizado, que é fortemente afetada pela legibilidade e facilidade de escrita.

VERIFICANDO O APRENDIZADO
1. DOS DOMÍNIOS DE PROGRAMAÇÃO APRESENTADOS NA
AULA, QUAIS DEVEM CONSIDERAR, NECESSARIAMENTE, A
ARQUITETURA CLIENTE-SERVIDOR?
Programação web e Mobile.

Programação de sistemas e aplicações comerciais.

Aplicações de Inteligência Artificial e aplicações científicas.

Aplicações comerciais e programação de sistemas.

2. UM DOS CRITÉRIOS MAIS RELEVANTES NA AVALIAÇÃO


DE LINGUAGENS DE PROGRAMAÇÃO DIZ RESPEITO À
FACILIDADE COM QUE OS PROGRAMAS PODEM SER
LIDOS. ESTAMOS FALANDO DE QUAL CRITÉRIO?
Legibilidade

Redigibilidade

Confiabilidade

Custo
GABARITO

1. Dos domínios de programação apresentados na aula, quais devem


considerar, necessariamente, a arquitetura cliente-servidor?

A alternativa "A " está correta.

Dos seis domínios apresentados, aqueles em que precisamos observar a


arquitetura cliente-servidor são os relacionados com a internet: programação
Web e programação Mobile, pois teremos que nos preocupar com o lado
cliente (programação no navegador ou app) e no lado servidor (implementando
a lógica do negócio).

2. Um dos critérios mais relevantes na avaliação de linguagens de


programação diz respeito à facilidade com que os programas podem ser
lidos. Estamos falando de qual critério?

A alternativa "A " está correta.

São quatro os critérios de avaliação: legibilidade, facilidade de escrita ou


redigibilidade, confiabilidade e custo. O que expressa a facilidade de leitura do
código é a legibilidade (código legível).

MÓDULO 3

Distinguir os paradigmas e suas características


O agrupamento por paradigmas é outra forma de classificar as linguagens de
programação. Um paradigma agrupa linguagens com características
semelhantes que surgiram em uma mesma época.

A imagem a seguir ilustra os cinco paradigmas nos quais as linguagens de


programação são classificadas. Esses paradigmas são agrupados em
Imperativos e Declarativos, de acordo com a forma com que os programas são
estruturados e descritos.

Fonte: AutorClassificação dos paradigmas das linguagens de programação.


Fonte: Autor, adaptado de (VAREJÃO, 2004, p.17).

Você também pode acompanhar mais informações sobre a classificação dos


paradigmas das linguagens de programação assistindo ao vídeo:
PARADIGMA IMPERATIVO
O paradigma imperativo agrega três paradigmas: estruturado, orientado a
objeto e concorrente, os quais possuem em comum o fato de especificarem
passo a passo o que deve ser feito para a solução do problema. As linguagens
do paradigma imperativo são dependentes da arquitetura do computador, pois
especificam em seus programas como a computação é realizada.

Vamos explicar as características de cada um dos paradigmas do subgrupo


Imperativo.

PARADIGMA ESTRUTURADO
Caracteriza as principais linguagens de programação da década de 1970 e
1980 que seguiram os princípios da programação estruturada:

PRINCÍPIO 01
PRINCÍPIO 02
PRINCÍPIO 03
PRINCÍPIO 04

1
Não usar desvios incondicionais (Goto, característico de linguagens como
BASIC e versões iniciais do COBOL).

2
Desenvolver programas por refinamentos sucessivos (metodologia top down),
motivando o desenvolvimento de rotinas (procedimentos e funções) e a visão
do programa partindo do geral para o particular, ou seja, o programa vai sendo
refinado à medida que se conhece melhor o problema e seus detalhes.

3
Desenvolver programas usando três tipos de estruturas: sequenciais,
condicionais e repetição.

4
Visando eficiência, o paradigma estruturado baseia-se nos princípios da
arquitetura de Von Neumann, onde:

 Programas e dados residem, na memória (durante a execução).

 Instruções e dados trafegam da memória para CPU e vice-versa.

 Resultados das operações trafegam da CPU para a memória.

As linguagens Pascal e C caracterizam bem esse paradigma. A linguagem


Python, multiparadigma, tem o estilo básico do paradigma estruturado.

PARADIGMA ORIENTADO A OBJETOS


Com o crescimento do tamanho do código e complexidade dos programas, o
paradigma estruturado começou a apresentar limitações nos sistemas que
passaram a ter dificuldade de manutenção e reuso de programas e rotinas
padronizadas.

A orientação a objetos surge como solução a esses problemas, permitindo,


através de propriedades como abstração, encapsulamento, herança e
polimorfismo, maior organização, reaproveitamento e extensibilidade de código
e, consequentemente, programas mais fáceis de serem escritos e mantidos.
O principal foco desse paradigma foi possibilitar o desenvolvimento mais rápido
e confiável.

As classes são abstrações que definem uma estrutura que encapsula dados
(chamados de atributos) e um conjunto de operações possíveis de serem
usados, chamados métodos. Os objetos são instâncias das classes.

EXEMPLO
Por exemplo, a classe ALUNO encapsula um conjunto de dados que os
identifiquem: matrícula, nome, endereço (rua, número, complemento, bairro,
estado e CEP) e um conjunto de métodos: Incluir Aluno, Matricular Aluno,
Cancelar Matrícula, dentre outros.

O paradigma orientado a objetos, por sua vez, usa os conceitos do paradigma


estruturado na especificação dos comandos de métodos. Por isso, é
considerado uma evolução do paradigma estruturado.

ATENÇÃO
Phyton, Smalltalk, C++, Java, Delphi (oriundo do Object Pascal) são linguagens
que caracterizam o paradigma orientado a objetos. Python é orientado a objeto,
pois tudo em Python é objeto, permitindo a declaração de classes
encapsuladas, além de possibilitar herança e polimorfismo.

PARADIGMA CONCORRENTE
Caracterizado quando processos executam simultaneamente e concorrem aos
recursos de hardware (processadores, discos e outros periféricos),
características cada vez mais usuais em sistemas de informação.

O paradigma concorrente pode valer-se de apenas um processador ou vários.

UM PROCESSADOR
Os processos concorrem ao uso do processador e recursos.
VÁRIOS PROCESSADORES
Estamos caracterizando o paralelismo na medida em que podem executar em
diferentes processadores (e de fato, ao mesmo tempo), os quais podem estar
em uma mesma máquina ou distribuídos em mais de um computador.

Ada e Java são as linguagens que melhor caracterizam esse paradigma,


possibilitando suporte à concorrência.

VOCÊ SABIA
Ao contrário de Go, Python não foi originalmente projetada com foco em
programação concorrente, muito menos paralela. O modo tradicional de
programar concorrência em Python -- threads -- é limitado no interpretador
padrão (CPython) por uma trava global (a GIL), que impede a execução
paralela de threads escritas em Python. Isso significa que threads em Python
são úteis apenas em aplicações I/O bound – em que o gargalo está no I/O
(entrada e saída), como é o caso de aplicações na Internet.

I/O BOUND
Aplicações I/O bound são aquelas em que há predomínio de ações de entrada
e saída de dados.

PARADIGMA DECLARATIVO
Diferentemente do paradigma imperativo, no declarativo o programador diz o
que o programa deve fazer (qual a tarefa), ao invés de descrever como o
programa deve fazer. O programador declara, de forma abstrata, a solução do
problema.

Essas linguagens não são dependentes de determinada arquitetura de


computador. As variáveis são incógnitas, tal qual na Matemática e não células
de memória.
O paradigma declarativo agrega os paradigmas funcional e lógico.

Vamos explicar as características de cada um.

PARADIGMA FUNCIONAL
Abrange linguagens que operam tão somente funções que recebem um
conjunto de valores e retornam um valor. O resultado que a função retorna é a
solução do problema (foca o processo de resolução de problemas).

O programa resume-se em chamadas de funções, que por sua vez podem usar
outras funções. Uma função pode invocar outra, ou o resultado de uma função
pode ser argumento para outra função. Usa-se também chamadas recursivas
de funções.

Naturalmente, esse paradigma gera programas menores (pouco código).

Linguagens típicas desse paradigma são: LISP, HASKELL e ML.

LISP é a LP funcional mais usada, especialmente em programas que usem os


conceitos de Inteligência Artificial (sistemas especialistas, processamento de
linguagem natural e representação do conhecimento), devido à facilidade de
interpretação recursiva.

Exemplo: O código abaixo implementa em Python uma função que calcula


quantos números inteiros existem de 0 a n.

def conta_numeros(n):

p=0

for num in range(n+1):

if num%2 == 0:

p += 1

return p
Abaixo, o mesmo código usando o conceito de função recursiva. Repare que a
função de nome conta_numeros chama ela mesma em seu código (isso é a
recursão).

def conta_numeros(n):

if n == 0: return 1 # 0 é par

elif n%2 == 0: return 1 + conta_numeros(n-1)

else: return conta_numeros(n-1)

ATENÇÃO
Python não é uma linguagem funcional nativa, seria exagerado afirmar isso,
porém sofreu influência desse paradigma ao permitir: recursividade, uso de
funções anônimas, com a função lambda, dentre outros recursos, além, claro,
de ser uma linguagem com enorme biblioteca de funções.

PARADIGMA LÓGICO
Um programa lógico expressa a solução da maneira como o ser humano
raciocina sobre o problema: baseado em fatos, derivam-se conclusões e novos
fatos.

Quando um novo questionamento é feito, através de um mecanismo inteligente


de inferência, deduz novos fatos a partir dos existentes.

A execução dos programas escritos em linguagens de programação lógica


segue, portanto, um mecanismo de dedução automática (máquina de
inferência), sendo Prolog a linguagem do paradigma lógico mais conhecida.

O paradigma lógico é usado no desenvolvimento de linguagens de acesso a


banco de dados, sistemas especialistas (IA), tutores inteligentes etc.

Python não tem características para implementar programas que atendam ao


paradigma lógico.
VERIFICANDO O APRENDIZADO
1. AS LINGUAGENS DE PROGRAMAÇÃO PODEM SE
ENQUADRAR EM UM OU VÁRIOS PARADIGMAS, NOS QUAIS
A LINGUAGEM TEM UMA GRANDE FLEXIBILIDADE E
POTENCIAL DE APROVEITAMENTO. NESSE CONTEXTO,
PYTHON É UMA LINGUAGEM:
Compatível apenas com o paradigma estruturado.

Compatível apenas com os paradigmas estruturado e lógico.

Compatível apenas com o paradigma orientado a objetos.

Multiparadigma.

2. RELACIONE A COLUNA A, EM QUE TEMOS PARADIGMAS


DAS LINGUAGENS DE PROGRAMAÇÃO COM A COLUNA B,
EM QUE TEMOS AS CARACTERÍSTICAS DOS PARADIGMAS
DE LINGUAGENS:

A – PARADIGMAS B – CARA

1 – ESTRUTURADO A – FOMENTA A REUSABILIDADE PELOS MECANISM

2 – ORIENTADO A OBJETO B – DESENVOLVER PROGRAMAS USANDO TRÊS TI

3 – CONCORRENTE C – LISP É A LINGUAGEM MAIS SIGNIFICATIVA DES

4 – FUNCIONAL D – PROCESSOS EXECUTAM SIMULTANEAMENTE E


 ATENÇÃO! PARA VISUALIZAÇÃOCOMPLETA DA TABELA
UTILIZE A ROLAGEM HORIZONTAL
COM BASE EM SUA ANÁLISE, MARQUE A OPÇÃO QUE
RELACIONA CORRETAMENTE AS DUAS COLUNAS A E B:
1-b, 2-a, 3-d, 4-c

1-a, 2-c, 3-d, 4-b

1-d, 2-b, 3-a, 4-c

1-b, 2-c, 3-d, 4-a

GABARITO

1. As linguagens de programação podem se enquadrar em um ou vários


paradigmas, nos quais a linguagem tem uma grande flexibilidade e
potencial de aproveitamento. Nesse contexto, Python é uma linguagem:

A alternativa "D " está correta.

Python é uma linguagem multiparadigma, de forma nativa, estando compatível


com os paradigmas estruturado, orientado a objeto, funcional e concorrente.

2. Relacione a coluna A, em que temos paradigmas das linguagens de


programação com a coluna B, em que temos as características dos
paradigmas de linguagens:

A – Paradigmas B–

1 – Estruturado a – Fomenta a reusabilidade pelos mecanismos de he


2 – Orientado a objeto b – Desenvolver programas usando três tipos de estru

3 – Concorrente c – Lisp é a linguagem mais significativa desse paradig

4 – Funcional d – Processos executam simultaneamente e concorrem

 Atenção! Para visualizaçãocompleta da tabela utilize a rolagem horizontal

Com base em sua análise, marque a opção que relaciona corretamente as


duas colunas A e B:
A alternativa "A " está correta.

Analisando cada assertiva, temos:

Estruturado – Código com apenas três estruturas básicas: sequenciais, decisão


e repetição orientado a objeto – a base são os objetos que podem ser
herdados (herança) e estendidos (polimorfismo).

Concorrente – Permite escrever programas que concorrem ao uso dos


recursos de hardware (CPU e acesso a disco, por exemplo).

Funcional – Lisp é uma linguagem em que programa-se basicamente, usando


funções, sendo uma linguagem do paradigma funcional.

MÓDULO 4

Identificar métodos de implementação das linguagens.


Todo programa, a menos que seja escrito em linguagem de máquina, o que
hoje em dia está totalmente fora dos propósitos, precisará ser convertido para
linguagem de máquina antes de ser executado.

Essa conversão precisa de um programa que receba o código-fonte escrito na


linguagem e gere o respectivo código em linguagem de máquina.

Esse programa, que fará a tradução do código-fonte em linguagem de


máquina, é que vai determinar como os programas são implementados e como
vão executar.

Existem duas formas de realizar essa conversão: tradução e interpretação. É


fundamental que se saiba e se entenda qual o processo de conversão usado
na respectiva linguagem de programação.

TRADUÇÃO
Nesse processo de conversão, o programa escrito em uma linguagem de alto
nível é traduzido para uma versão equivalente em linguagens de máquina,
antes de ser executado. O processo de tradução pode ser executado em várias
fases, que podem ser combinadas e executadas em simultaneidade. O
processo de tradução é erroneamente chamado de compilação, que na
verdade é uma de suas fases.

As fases que compõem o tradutor, ou seja, iniciando na leitura do programa-


fonte (linguagem de alto nível) e terminando com a geração do código
executável (entendido pela máquina), são: Compilação, Montagem, Carga e
Ligação. A imagem abaixo ilustra o processo de tradução.

Código-fonte

Compilador
COMPILADOR
O compilador (detalhes adiante) analisa o código-fonte e estando tudo OK, o
converte para um código Assembly (da máquina hospedeira).

Código Assembly

Montador

MONTADOR
O montador traduz o código Assembly para o código de máquina intermediário
(Código-objeto), que não é executável pelo computador. O código-objeto pode
ser relocável, ou seja, carregado em qualquer posição de memória ou absoluto,
carregado em um endereço de memória específico. A opção relocável é mais
comum e mais vantajosa.

Código Assembly

Ligador

LIGADOR
O Ligador liga (ou linka) o código-objeto relocável com as rotinas bibliotecas
(outros objetos, rotinas do SO, DLLs etc.), usadas nos códigos-fontes. Essa
ligação gera o código executável.

Código-objeto relocável

Carregador
CARREGADOR
O carregador é que torna o código-objeto em relocável.

Código objeto

Código executável

Fases de tradução de um programa em linguagem de alto nível.Fonte: Autor.

COMPILADOR
É o elemento central do processo de tradução, responsável pelo custo de
compilação, visto no modulo anterior. Em função dessa relevância, muitas
vezes o processo como um todo é erroneamente chamado de compilação, uma
vez que o ambiente integrado das linguagens atuais já integra todos os
componentes (montador, compilador, carregador e ligador) quando necessário.

O projeto da linguagem tem no compilador a sua figura central.

A imagem abaixo ilustra os componentes envolvidos na compilação de um


programa fonte:
Fonte: https://johnidm.gitbooks.io/compiladores-para-humanos/content/part1/
introduction-and-overview-about-compilers.htmlFonte:
https://johnidm.gitbooks.io/compiladores-para-humanos/content/part1/
introduction-and-overview-about-compilers.html

Abaixo, vamos entender cada fase da compilação:

ANÁLISE LÉXICA

Identifica os tokens (elementos da linguagem), desconsidera partes do código-


fonte, como espaços em branco e comentários e gera a Tabela de símbolos,
com todos esses tokens, que são identificadores de variáveis, de
procedimentos, de funções, comandos, expressões etc.

ANÁLISE SINTÁTICA

Verifica se os tokens são estruturas sintáticas (exemplos: expressões e


comandos) válidas, aplicando as regras gramaticais definidas no projeto da
linguagem.

ANÁLISE SEMÂNTICA
Verifica se as estruturas sintáticas possuem sentido. Por exemplo, verifica se
um identificador de variável ou constante é usado adequadamente, se
operandos e operadores são compatíveis. Monta a árvore de derivação
conforme ilustrado abaixo para formação das expressões.

Fonte: AutorÁrvore de derivação de uma expressão. Fonte: AutorGERADOR


DE CÓDIGO INTERMEDIÁRIO, OTIMIZADOR DE CÓDIGO E GERADOR DE
CÓDIGO

Em distintas fases geram o programa-alvo ou programa-objeto.

 Gerador de código intermediário, que contém toda a informação para gerar


o código-objeto.

Na imagem a seguir, o código intermediário está representado no último quadro


– código em Assembly:

Fonte: Autor
 O otimizador tem por objetivo eliminar redundâncias do código intermediário
e tornar o objeto mais enxuto e eficiente.TRATADOR DE ERROS

Em todas as fases existem erros: léxicos, sintáticos e semânticos. Um bom


compilador apresenta uma boa tratativa de erros.

GERENCIADOR DA TABELA DE SÍMBOLOS

Mantém a tabela de símbolos atualizada a cada passo do compilador.

ATENÇÃO
As principais características dos compiladores são:

 Gerar código-objeto mais otimizado.

 Execução mais rápida que o processo de interpretação.

 Traduz um mesmo comando apenas uma vez, mesmo que usado em


várias partes do programa – tanto iterações como repetição de
código.

 Processo de correção de erros e depuração é mais demorado.

 A programação final (código-objeto) é maior.

 O programa-objeto gerado é dependente de plataforma —


processador + SO (Sistema Operacional) — necessitando de um
compilador diferente para cada família de processadores/sistema
operacional.

INTERPRETAÇÃO
A imagem abaixo ilustra o simples processo de Interpretação:
Fonte: Autor

Na conversão por interpretação, cada comando do programa-fonte é traduzido


e executado (um a um) imediatamente. O interpretador traduz um comando de
cada vez e chama uma rotina para completar a sua execução.

O interpretador é um programa que executa repetidamente a seguinte


sequência:

1
Obter a próxima instrução do código-fonte.

2
Interpretar a instrução (conversão para comandos em linguagem de máquina).

3
Executar a instrução.

Perceba que o procedimento, acima descrito, é bastante similar àquele


executado por computadores que implementam a máquina de Von Neumann,
na execução de uma instrução, conforme a seguir:

 Obter a próxima instrução.

 CI → endereço da próxima instrução. CI = contador de instruções.

 RI → instrução a ser executada. RI = registrador de instruções.

 Decodificar a instrução.

 Executar a instrução.

PRINCIPAIS CARACTERÍSTICAS DO INTERPRETADOR

Dentre as principais características do interpretador, podemos citar:

 Atua a cada vez que o programa precisa ser executado.

 Não produz programa-objeto persistente.

 Não traduz instruções que nunca são executadas.

 O resultado da conversão é instantâneo: resultado da execução do


comando ou exibição de erro – interpretador puro.

 Útil ao processo de depuração de código devido a mensagens de


erros em tempo de execução (tanto análise sintática como
semântica).

 Execução mais lenta do que outros processos de tradução


(compilação), pois toda vez que o mesmo programa é executado, os
mesmos passos de interpretação são executados.

 Consome menos memória.

 O Código-fonte é portátil.
o Não é gerado um código de máquina.

o Pode executar o comando em alto nível diretamente ou


gerar um código intermediário, que neste caso é
interpretado por uma máquina virtual (VM). – Interpretador
híbrido.

o Se a máquina virtual foi desenvolvida para diferentes


plataformas, temos a portabilidade do código-fonte. Este é o
caso da linguagem Java.

TRADUÇÃO X INTERPRETAÇÃO

Vantagens

1. Execução mais rápida 1. Vár

Tradutores 2. Permite estruturas de programas mais complexas. 2. Pro

3. Permite a otimização de código. 3. Pro

1. Depuração mais simples. 1. Exe

Interpretadores 2. Consome menos memória. 2. Est

3. Resultado imediato do programa (ou parte dele). 3. Nec

Fonte: http://codemastersufs.blogspot.com/2015/10/compiladores-versus-
interpretadores.html. Adaptado pelo autor.

 Atenção! Para visualizaçãocompleta da tabela utilize a rolagem horizontal


SISTEMAS HÍBRIDOS
O processo híbrido de implementação de uma linguagem de programação
combina a execução rápida dos tradutores (compiladores) com a portabilidade
dos interpretadores. O segredo é a geração de um código intermediário mais
facilmente interpretável, porém não preso a uma plataforma (SO/Hardware).

Esse código intermediário não é específico para uma plataforma, possibilitando


aos programas já compilados para esse código serem portados em diferentes
plataformas, sem alterar e nem fazer nada. Para cada plataforma desejada
devemos ter um interpretador desse código.

Duas importantes linguagens implementaram essa solução, com diferentes


formas usando máquinas virtuais: Python e Java.

SISTEMA DE IMPLEMENTAÇÃO DE PYTHON


Python usa um sistema híbrido, uma combinação de interpretador e tradutor
(compilador). O compilador converte o código-fonte Python em um código
intermediário, que roda numa máquina virtual, a PVM (Python Virtual Machine).

COMENTÁRIO
Curioso saber que o código Python pode ser traduzido em Bytecode Java
usando a implementação Jython.

O interpretador converte para código de máquina, em tempo de execução. O


compilador traduz o programa inteiro em código de máquina e o executa,
gerando um arquivo que pode ser executado. O compilador gera um relatório
de erros e o interpretador interrompe o processo na medida em que localiza um
erro.

CPython é uma implementação da linguagem Python, um pacote com um


compilador e um interpretador Python (Máquina Virtual Python), além de outras
ferramentas para programar em Python.
Agora, para finalizar, assista ao vídeo que explicará mais sobre a linguagem
Python:

VERIFICANDO O APRENDIZADO
1. COMO SE CHAMAM OS DOIS PROCESSOS DE
CONVERSÃO DE LINGUAGENS DE ALTO NÍVEL EM
LINGUAGENS INTELIGÍVEIS PELO COMPUTADOR?
Tradução e interpretação.

Compilação e interpretação.

Análise sintática e análise léxica.

Compilação e montagem.

2. AVALIE AS ASSERTIVAS A SEGUIR:


I. O COMPILADOR ANALISA O CÓDIGO-FONTE E O
CONVERTE PARA UM EXECUTÁVEL.
II. O MONTADOR TRADUZ O CÓDIGO ASSEMBLY PARA O
CÓDIGO DE MÁQUINA INTERMEDIÁRIO (CÓDIGO OBJETO),
QUE É EXECUTÁVEL PELO COMPUTADOR.
III. O CARREGADOR É QUE TORNA O CÓDIGO-OBJETO EM
RELOCÁVEL.
IV. O LIGADOR LIGA O CÓDIGO-OBJETO RELOCÁVEL COM
AS ROTINAS. ESSA LIGAÇÃO GERA O CÓDIGO
EXECUTÁVEL.
COM BASE EM SUA ANÁLISE, ASSINALE A ÚNICA OPÇÃO
COM TODAS AS ASSERTIVAS CORRETAS:
Estão corretas III e IV apenas.

Estão corretas II, III e IV apenas.

Está correta apenas a III.

Está correta apenas a IV.

GABARITO

1. Como se chamam os dois processos de conversão de linguagens de


alto nível em linguagens inteligíveis pelo computador?

A alternativa "A " está correta.

Embora chamemos o processo de compilação, o nome correto é Tradução, da


qual a compilação é uma das fases do processo de conversão.

2. Avalie as assertivas a seguir:

I. O compilador analisa o código-fonte e o converte para um executável.


II. O montador traduz o código Assembly para o código de máquina
intermediário (código objeto), que é executável pelo computador.
III. O carregador é que torna o código-objeto em relocável.
IV. O ligador liga o código-objeto relocável com as rotinas. Essa ligação gera o
código executável.

Com base em sua análise, assinale a única opção com todas as assertivas


corretas:
A alternativa "A " está correta.

Vamos avaliar cada assertiva.


I. Falso. O correto é: o compilador analisa o código-fonte o converte para um
código Assembly.
II. Falso. O correto é: o montador traduz o código Assembly para o código de
máquina intermediário (código-objeto), que não é executável pelo computador.
III. Verdadeiro. O carregador é responsável pela relocação do código-objeto.
IV. Verdadeiro. O ligador conecta o objeto relocável com as chamadas às
rotinas externas.

CONCLUSÃO

CONSIDERAÇÕES FINAIS
Saber classificar uma linguagem dentro do(s) paradigma(s) a que pertença(m),
assim como conhecer os domínios de programação de uma linguagem, é
fundamental para seu entendimento e correta aplicação na hora de decidir pelo
uso dessa ou aquela linguagem.

É fundamental também que se possa conhecer os critérios de avaliação de


uma linguagem e quais propriedades afetam cada um dos quatro critérios
vistos. Dessa forma, vamos saber selecionar a que melhor se aplica a
determinado contexto de uso.

Por fim, e não menos importante, conhecer o mais profundamente possível o


ambiente de desenvolvimento da linguagem, contemplando tradutores e/ou
interpretadores, para que se possa pôr em prática o desenvolvimento do
sistema, no paradigma, domínio do problema, e usando as melhores
construções para gerar códigos legíveis, com alta facilidade de escrita,
confiabilidade e, preferencialmente, ao menor custo possível.
AVALIAÇÃO DO TEMA:

REFERÊNCIAS
BORGES, Luiz Eduardo. Python para Desenvolvedores. 2. ed. Rio de
Janeiro: Edição do Autor, 2010.
SEBESTA, R. W. Conceitos de Linguagens de Programação. Tradução de
João Eduardo Nobrega Tortello. 11. ed. Porto Alegre: Bookman, 2018.
Disponível na biblioteca virtual da Estácio.
VAREJÃO, F. M. Linguagem de Programação: conceitos e técnicas. 2ª
reimpressão. Rio de Janeiro: Elsevier, 2004.
DIJKSTRA EW. A Discipline of Programming. Prentice Hall Inc;1976. 217.

EXPLORE+
Para saber mais sobre os assuntos tratados neste tema, pesquise na internet
sobre:

 Objective C, que é a linguagem utilizada para desenvolvimento de


aplicativos iOS e MacOS.

 Plataformas sobre a linguagem Python.


 Plataformas de programadores, para acompanhar as linguagens de
programação mais usadas no mercado.

 Visual Studio, que oferece uma cadeia de ferramentas em


dispositivos móveis e na nuvem.

CONTEUDISTA
Marcelo Vasques de Oliveira

CURRÍCULO LATTES
DEFINIÇÃO
Introdução à linguagem Python e suas características, apresentando as
variáveis, os tipos de dados, as expressões, os operadores e as formas de
atribuição, de entrada e saída de dados.

PROPÓSITO
Compreender os aspectos básicos de Python visando ao aprendizado da
programação nessa linguagem.

OBJETIVOS
MÓDULO 1
Descrever a linguagem Python e suas principais características

MÓDULO 2
Reconhecer o uso de variáveis em Python

MÓDULO 3
Identificar os tipos de dados e as expressões em Python

MÓDULO 4
Identificar as formas de atribuição, de entrada e saída de dados em Python

INTRODUÇÃO
Atualmente, o ensino de disciplinas relacionadas à programação vem
crescendo na educação básica e no ensino superior. Nos cursos de graduação
voltados à tecnologia da informação, como Engenharia da Computação e
Ciência da Computação, é frequente que se tenha contato com mais de uma
disciplina focada em programação. Além desses cursos, outras carreiras têm
contato com a programação em disciplinas como Introdução à Computação ou
similares. Nesses diferentes contextos, várias linguagens de programação são
usadas, tanto para o ensino como para o desenvolvimento de projetos.

Dentre as diversas linguagens de programação que existem, Python é


considerada uma das principais. Por sua simplicidade de aprendizado, ela tem
sido utilizada em diversos cursos universitários como a primeira linguagem com
que os alunos têm contato ao programar. Atualmente, conta com ampla
participação da comunidade, além de ter seu desenvolvimento aberto e
gerenciado pela organização sem fins lucrativos Python Software Foundation.

Recentemente, a IEEE Computer Society classificou-a como a linguagem


mais indicada para aprender em 2020. Isso se deve à sua eficiência no
desenvolvimento de machine learning, inteligência artificial, ciência, gestão e
análise de dados.

IEEE COMPUTER SOCIETY


Grupo voltado à ciência da computação, engenharia elétrica e eletrônica,
apoiando e organizando congressos no mundo todo e divulgando artigos
científicos dessas áreas.

MÓDULO 1

Descrever a linguagem Python e suas principais características

CONCEITOS
Python é uma linguagem de programação de alto nível, que permite ao
programador utilizar instruções de forma intuitiva, tornando seu aprendizado
mais simples do que o aprendizado de uma linguagem de baixo nível.

Nas linguagens de baixo nível, o programador precisa se expressar de forma


muito mais próxima do que o dispositivo “entende”, levando naturalmente a um
distanciamento da linguagem utilizada para comunicação entre duas pessoas.

A linguagem Python foi lançada pelo holandês Guido van Rossum no início


dos anos 1990 e desde então tem aumentado sua participação no mundo da
programação. Permite uma programação fácil e clara para escalas pequenas e
grandes, além de enfatizar a legibilidade eficiente do código, notadamente
usando espaços em branco significativos.
Fonte: WikipediaGuido van Rossum

CARACTERÍSTICAS DA LINGUAGEM
PYTHON
A linguagem Python tem se tornado cada vez mais popular porque, além de
permitir um rápido aprendizado inicial, tem características importantes, tais
como:

É MULTIPARADIGMA
Apesar de suportar perfeitamente o paradigma de programação estruturada,
Python também suporta programação orientada a objetos, tem características
do paradigma funcional, com o amplo uso de bibliotecas, assim como permite
recursividade e uso de funções anônimas.

É INTERATIVA
Permite que os usuários interajam com o interpretador Python diretamente para
escrever os programas, utilizando o prompt interativo. Esse prompt fornece
mensagens detalhadas para qualquer tipo de erro ou para qualquer comando
específico em execução, suporta testes interativos e depuração de trechos de
código.

É HÍBRIDA QUANTO AO MÉTODO DE


IMPLEMENTAÇÃO
Python usa uma abordagem mista para explorar as vantagens do interpretador
e do compilador. Assim como Java, utiliza o conceito de máquina virtual,
permitindo a geração de um código intermediário, mais fácil de ser interpretado,
mas que não é vinculado definitivamente a nenhum sistema operacional.

É PORTÁVEL
Tem a capacidade de rodar em uma grande variedade de plataformas de
hardware com a mesma interface. Ele roda perfeitamente em quase todos os
sistemas operacionais, como Windows, Linux, UNIX, e Mac OS, sem nenhuma
alteração.

É EXTENSÍVEL
Permite que os programadores adicionem ou criem módulos e pacotes de
baixo nível / alto nível ao interpretador Python. Esses módulos e pacotes de
ferramentas permitem que os desenvolvedores tenham possibilidades amplas
de colaboração, contribuindo para a popularidade da linguagem.

SUPORTA BANCOS DE DADOS


Por ser uma linguagem de programação de uso geral, Python suporta os
principais sistemas de bancos de dados. Permite escrever código com
integração com MySQL, PostgreSQL, SQLite, ElephantSQL, MongoDB, entre
outros.

SUPORTA INTERFACE COM USUÁRIO


Permite escrever código de tal maneira que uma interface do usuário para um
aplicativo possa ser facilmente criada, importando bibliotecas como Tkinter,
Flexx, CEF Python, Dabo, Pyforms ou PyGUI wxPython.

PODE SER USADO COMO LINGUAGEM DE


SCRIPT
Permite fácil acesso a outros programas, podendo ser compilado para
bytecode a fim de criar aplicativos grandes.

PERMITE DESENVOLVIMENTO DE
APLICAÇÕES WEB
Devido à escalabilidade já citada, Python oferece uma variedade de opções
para o desenvolvimento de aplicativos Web. A biblioteca padrão do Python
incorpora muitos protocolos para o desenvolvimento da web, como HTML,
XML, JSON, processamento de e-mail, além de fornecer base para FTP, IMAP
e outros protocolos da Internet.

PERMITE CRIAÇÃO DE APLICAÇÕES


COMERCIAIS
É desenvolvido sob uma licença de código aberto aprovada pela OSI,
tornando-o livremente utilizável e distribuível, mesmo para uso comercial.

INSTALAÇÃO
A linguagem Python tem seu site oficial, onde é possível encontrar as últimas
versões lançadas, notícias e documentação, entre outras informações. A
versão que utilizaremos neste tema é a 3.7.7. Por isso, recomendamos que ela
seja baixada e instalada em seu computador. Também será necessário baixar
e instalar a IDE PyCharm, usando a versão disponível em seu site.

Para conhecer o processo de instalação do Python, assista ao vídeo a seguir.


UTILITÁRIOS E MÓDULOS
Apenas como exemplo, na área de Console clique no botão Python Console.
No prompt interativo >>> que se abrirá, digite x = 5 e pressione a tecla
[ENTER] ou [RETURN] do seu teclado. Observe na figura 2 que, na área
Árvore de exibição de variáveis, agora fica disponível a informação que a
variável x é do tipo int e tem o valor 5.

Fonte: o autor (2020) Figura 2 - Exibição de variáveis

Não se preocupe ainda com o conceito de variável, nem com o seu tipo.
Veremos tudo isso com detalhes nos próximos módulos deste tema.
O utilitário dir apresenta todos os atributos e métodos disponíveis para
determinado tipo de dado. No prompt interativo >>>, digite dir(x) e pressione a
tecla [ENTER] ou [RETURN] do seu teclado.

Fonte: Freepik

No prompt interativo >>>, digite dir(x) e pressione a tecla [ENTER] ou


[RETURN] do seu teclado.
Fonte: o autor (2020) Figura 3 - Utilitários

O utilitário help apresenta a documentação relativa a determinado tipo de


dado. Caso você tenha alguma dúvida sobre o que é possível fazer com
determinado tipo, os utilitários dir e help podem ser úteis.

BLOCOS
Em Python, os blocos são definidos pela indentação. Diferente de C e Java,
que usam as chaves { e } para delimitar os blocos, em Python todos os blocos
são iniciados com o símbolo : (dois pontos) na linha superior e representados
pelo acréscimo de 4 (quatro) espaços à esquerda. Sem se preocupar por
enquanto com o significado das expressões for, if, else ou range, observe a
figura 4:

INDENTAÇÃO
Trata-se da digitação dos códigos do programa, afastados por espaço da
margem e dispostos hierarquicamente para facilitar a visualização e percepção
do programa.
Fonte: o autor (2020) Figura 4 - Blocos

A partir dessa figura, podemos destacar alguns pontos:

LINHA 1
Está mais à esquerda, assim como as linhas 2 e 11.

LINHA 2
Todas as linhas de 3 a 10 estão dentro do bloco do for da linha 2.

LINHA 3
Observe que a linha 3 tem um if abrindo um bloco, dentro do qual estão as
linhas 4 e 5.

LINHA 6
Por sua vez, a linha 6 tem um else abrindo outro bloco, composto pelas linhas
de 7 a 10. Os blocos do if (linha 3) e do else (linha 6) estão no mesmo nível.

LINHA 7
Mostra outro if abrindo outro bloco – composto apenas pela linha 8 – que está
no mesmo nível do bloco do else da linha 9 – composto apenas pela linha 10.

LINHA 11
Como a linha 11 está no mesmo nível da linha 2, ela não faz parte do bloco
do for.

COMENTÁRIOS
Em Python, os comentários podem ser de uma linha ou de várias linhas. A
tabela 1 mostra as formas de limitar um comentário, além de comparar essas
formas em Python e C.

 Atenção! Para visualização completa da tabela utilize a rolagem horizontal

Python

Comentários de uma linha Iniciados com #

Comentários com várias linhas Limitados por “”” (três aspas duplas) no início

Tabela 1 - Comentários - Fonte: o autor (2020)

ATENÇÃO
É importante lembrar que os comentários não são instruções a serem
executadas. Então, você pode escrever de forma simples e objetiva, sem
obedecer às regras de sintaxe da linguagem.

BOAS PRÁTICAS DE
PROGRAMAÇÃO
Ao começar sua jornada como programador, é importante perceber que
existem algumas práticas que não são obrigatórias, mas podem ajudar muito
no seu aprendizado. Além disso, podem permitir que você corrija mais
rapidamente erros que podem surgir no futuro e tornam seu código mais fácil
de ser compreendido por outro programador, favorecendo o trabalho em
equipe. Vamos conhecer algumas delas:

Fonte: Porcupen/shutterstock
Uma prática muito importante é utilizar comentários no seu programa,
explicando o que aquele trecho resolve.

Fonte: Porcupen/shutterstock
Uma característica marcante da comunidade de desenvolvedores Python é
manter uma lista de propostas de melhorias, chamadas PEP (Python
Enhancement Proposals). Dentre as PEPs, destaca-se a PEP8, que estabelece
um guia de estilo de programação.

Agora que já vimos os principais conceitos deste módulo, é hora de testar seus
conhecimentos.

VERIFICANDO O APRENDIZADO
1. ANALISE AS AFIRMATIVAS A SEGUIR:

I. PYTHON É UMA LINGUAGEM LIVRE DE ALTO NÍVEL,


ORIENTADA A OBJETOS E DE DIFÍCIL LEITURA, POIS NÃO
PERMITE INDENTAÇÃO DE LINHAS DE CÓDIGO.

II. PYTHON SUPORTA A MAIORIA DAS TÉCNICAS DA


PROGRAMAÇÃO ORIENTADA A OBJETOS.

III. A LINGUAGEM PYTHON E SEU INTERPRETADOR ESTÃO


DISPONÍVEIS PARA AS MAIS DIVERSAS PLATAFORMAS.

SÃO CORRETAS:
Somente II.

Somente III.

Somente II e III.

Somente I e II.

2. (2018/IF-MT/INFORMÁTICA) SOBRE A LINGUAGEM


PYTHON, É INCORRETO AFIRMAR QUE:
Suporta os paradigmas: imperativo, orientado a objetos e funcional.

Utiliza indentação para delimitar início e fim de blocos.


A linguagem Python é distribuída sob licença que proíbe sua incorporação em
produtos proprietários.

Python é um software de código aberto.

GABARITO

1. Analise as afirmativas a seguir:

I. Python é uma linguagem livre de alto nível, orientada a objetos e de


difícil leitura, pois não permite indentação de linhas de código.

II. Python suporta a maioria das técnicas da programação orientada a


objetos.

III. A linguagem Python e seu interpretador estão disponíveis para as mais


diversas plataformas.

São corretas:
A alternativa "C " está correta.

A linguagem Python é de fácil leitura, inclusive pela indentação. Isso torna a


afirmativa I falsa. As afirmativas II e III são verdadeiras.

2. (2018/IF-MT/Informática) Sobre a linguagem Python, é incorreto afirmar


que:
A alternativa "C " está correta.
A linguagem Python é desenvolvida sob uma licença de código aberto
aprovada pela OSI, tornando-a livremente utilizável e distribuível, mesmo para
uso comercial.

MÓDULO 2

Reconhecer o uso de variáveis em Python

CONCEITOS
As variáveis são abstrações para endereços de memória que permitem que os
programas fiquem mais fáceis de codificar, entender e depurar. Podemos
entender que ao nomear uma variável com o identificador x, determinado
espaço em memória passará a ter esse apelido. Em outras palavras, será
possível acessar esse espaço de memória sabendo o seu apelido e,
consequentemente, recuperar o valor guardado nele, que no nosso exemplo
é 10.

Uma analogia possível com o mundo real é com aquelas caixas de correio que
ficam em frente às casas.
Fonte: Fabio Balbi/Shutterstock

Em Python, o operador de atribuição é o = (símbolo de igual). A instrução x =


10 atribui o valor 10 à variável x.
Fonte: Freepik

No prompt interativo >>>, digite x = 10 e pressione a tecla [ENTER] ou


[RETURN] do seu teclado. Em seguida, digite x e pressione a tecla [ENTER] ou
[RETURN].
Fonte: o autor (2020) Figura 5 - Primeira variável

ATENÇÃO
Observe na figura 5 que o retorno do Python Console foi 10.

Se, posteriormente, você utilizar novamente o prompt interativo >>> para


digitar x = 20 e pressionar a tecla [ENTER], você alterará o valor da variável x.
Ou seja, você estará mudando o valor armazenado naquele espaço de
memória, mas sem alterar seu apelido. Observe a figura 6:
Fonte: o autor (2020) Figura 6 - Atualização de variável

ATENÇÃO
Diferentemente de outras linguagens, como C ou Java, não é necessário
declarar uma variável antes de utilizá-la em Python. Basta atribuir um valor
inicial à variável e utilizá-la dali em diante. Embora não seja necessário
declarar uma variável para utilizá-la, não é possível utilizar uma variável que
não tenha recebido alguma atribuição de valor.
Fonte: Freepik

No prompt interativo, digite b e pressione a tecla [ENTER] ou [RETURN].


Fonte: o autor (2020) Figura 7 - Variável não definida

Veja na figura 7 que a mensagem de erro informa que o nome b não foi


definido. Ou seja, não é possível determinar o valor atribuído a esse nome.

IDENTIFICADORES DE VARIÁVEIS
Os identificadores das variáveis podem ser compostos por letras,
o underline (_) e, com exceção do primeiro caractere, números de 0 a 9. Veja
os exemplos:

minhaVariavel, _variavel, salario1 e salario1_2 são válidos.

1variavel e salario-1 não são válidos.

minhaVariavel e minhavariavel são identificadores de duas variáveis


distintas.

Mesmo que seja um identificador permitido, nem sempre um identificador é


bom para uma variável. Tente utilizar nomes que ajudem a entender o
significado da variável para ganhar tempo quando for entender o código
posteriormente.
EXEMPLO
salario é um nome de variável melhor que s.

Algumas palavras são consideradas reservadas e não podem ser usadas como
identificadores de variáveis em Python. São
elas: and, as, assert, break, class, continue, def, del, elif, else, except, exe
c, finally, for, from, global, if, import, in, is, lambda, not, or, pass, print, rai
se, return, try, while, with e yield.

AMARRAÇÕES
Chamamos de amarração (binding) a associação entre entidades de
programação. Veja alguns exemplos:

Variável amarrada a um valor

Operador amarrado a um símbolo

Identificador amarrado a um tipo

O tempo em que a amarração ocorre é chamado de tempo de amarração.


Cada linguagem pode ter os seguintes tempos de amarração:

TEMPO DE PROJETO DA LINGUAGEM


Os símbolos são amarrados ao operador, como * (multiplicação), ou à definição
das palavras reservadas.
TEMPO DE IMPLEMENTAÇÃO

Ocorre em geral nos compiladores, como a definição de faixa de valores para


determinado tipo.

TEMPO DE COMPILAÇÃO

Associação da variável ao seu tipo. Lembre-se de que Python associa a


variável ao tipo, como foi explicado na seção anterior.

TEMPO DE LIGAÇÃO
A ligação de vários módulos compilados previamente, como a chamada a uma
função de um módulo importado. Em C, utilizamos a diretiva #include para
termos permissão de utilizar as funções de determinada biblioteca. Em Python,
utilizamos o import para isto.
TEMPO DE CARGA

Quando o programa é carregado. Por exemplo: endereços de memória


relativos são substituídos por endereços absolutos.

TEMPO DE EXECUÇÃO

Associação de valores a variáveis que dependam de entradas do usuário, por


exemplo. A variável é vinculada ao valor apenas durante a execução do
programa.

O momento em que ocorre a ligação pode ser classificado como cedo (early
binding) ou tardio (late binding). Quanto mais cedo ocorre a ligação, maior a
eficiência de execução do programa, porém menor a flexibilidade das
estruturas disponibilizadas.

AMARRAÇÃO DE TIPO
As amarrações de tipo vinculam a variável ao tipo do dado. Elas podem ser:

ESTÁTICAS
Ocorrem antes da execução e permanecem inalteradas. Em C, declaramos int
a.

DINÂMICAS
Ocorrem durante a execução e podem ser alteradas. É o caso do Python.

Veja a figura 8:
Fonte: o autor (2020) Figura 8 - Tipagem dinâmica

Perceba que a chamada type (parâmetro) retorna o tipo do parâmetro


informado entre parênteses. Observe que a variável valor recebeu 10 e, com
isso, ficou vinculada ao tipo int. Porém, ao receber o valor ‘a’, passou a estar
vinculada ao tipo str (string).

ESCOPO DE VISIBILIDADE
O escopo define em quais partes do programa uma variável é visível. Cada
nome de variável em Python tem seu escopo e fora desse escopo o nome não
existe, gerando um erro quando se tenta referenciar esse nome. Quanto ao
escopo, chamamos as variáveis de globais ou locais.
Fonte: BEST-BACKGROUNDS/Shutterstock

VARIÁVEIS GLOBAIS
Todos os nomes atribuídos no prompt interativo ou em um módulo fora de
qualquer função são considerados como de escopo global. Por exemplo, ao
executar a instrução da figura 9, a variável x é uma variável global.

Fonte: o autor (2020) Figura 9 - Variável global

VARIÁVEIS LOCAIS
Para exemplificar o uso de variáveis com escopo local, vamos utilizar uma
função definida pelo desenvolvedor. Não se preocupe com esse tipo de função
por enquanto, você aprenderá mais detalhes posteriormente. Observe a figura
10:

Fonte: o autor (2020) Figura 10 - Variáveis locais - código-fonte

As linhas 2, 3 e 4 compõem o bloco interno à função chamada multiplicador().


Embora as variáveis das linhas 2 e 7 tenham o mesmo nome, elas são
abstrações a endereços de memória diferentes. Dentro da
função multiplicador(), a chamada ao nome a recupera o valor 2. Fora da
função multiplicador(), a chamada ao nome a recupera o valor 3. Veja a
execução na figura 11:
Fonte: o autor (2020) Figura 11 - Variáveis locais - execução

Agora, observe a função multiplicador() com uma pequena alteração, em que


retiramos a inicialização da variável a dentro da função.

Fonte: o autor (2020) Figura 12 - Variáveis locais - código-fonte 2

Na linha 6, ao se chamar a função multiplicador(), a variável a será procurada.


Como não existe uma variável a no bloco interno da função, ela é procurada
como variável global. Uma vez encontrada, o valor recuperado é 3. Ao executar
esse exemplo, você verá:

Fonte: o autor (2020) Figura 13 - Variáveis locais – execução 2

Usamos este exemplo para mostrar que o interpretador Python pode procurar o
mesmo nome de variável em diferentes escopos. A ordem utilizada para a
procura é:

1
A chamada da função delimitadora

2
Variáveis globais

3
O módulo builtins

Perceba que, se a variável a é inicializada na função multiplicador(), qualquer


chamada a esse nome dentro da função resultará na referência a essa variável
local. Mas seria possível alterar a variável a global com uma instrução dentro
da função multiplicador()? Sim, utilizando-se a palavra reservada global. Veja
como isso poderia ser feito na figura 14 e o seu resultado na figura 15:

Fonte: o autor (2020) Figura 14 - Variáveis locais - código-fonte 3

Fonte: o autor (2020) Figura 15 - Variáveis locais - execução 3

TIPOS DE ESCOPO
Os tipos de escopo são:

ESTÁTICO
O escopo é baseado na descrição textual do programa e as amarrações são
feitas em tempo de compilação. É o caso de C, C++ e Java, por exemplo.

DINÂMICO

O escopo é baseado na sequência de chamada dos módulos (ou funções). Por


isso, as amarrações são feitas em tempo de execução. É o caso do Python.

O fato de Python ser de escopo dinâmico traz alguns problemas, como a perda
de eficiência – uma vez que os tipos precisam ser verificados em tempo de
execução – e a redução na legibilidade – porque é difícil determinar a
sequência exata de todas as chamadas de função.

Fonte: BEST-BACKGROUNDS/Shutterstock

TEMPO DE VIDA
Embora escopo e tempo de vida tenham uma relação próxima, eles são
conceitos diferentes. Observe:

Escopo é um conceito textual

Tempo de vida é um conceito temporal


As variáveis globais têm o tempo de vida que é o de execução do programa, ao
passo que as variáveis locais somente existem no intervalo de duração da
função ou do bloco a que se limitam.

CONSTANTES
Em Python, não existe o conceito de constante. Se você precisar de uma
constante ao longo de sua jornada como programador, atribua o valor a uma
variável e tome cuidado para não mudar esse valor.

DICA
Uma dica é iniciar o nome dessa variável com c_ ou utilizar todas as letras
maiúsculas, o que vai diferenciar essa variável das outras. Por exemplo, é
possível utilizar a expressão c_PI = 3.141592 para armazenar o valor de PI e
agilizar o cálculo de área e perímetro de um círculo, ou utilizar a
expressão PRECISION = 0.001 para armazenar a precisão a ser utilizada em
qualquer cálculo matemático no seu programa.

É importante ficar atento ao uso correto das variáveis, especialmente


observando as questões de escopo e visibilidade, para evitar que algum cálculo
seja realizado corretamente, mas com resultado diferente do esperado por
você ao programar.
Fonte: metamorworks/Shutterstock

No vídeo a seguir, assista a uma demonstração das variáveis estáticas e


dinâmicas.
VERIFICANDO O APRENDIZADO
1. (2017/IF-CE/TÉCNICO DE LABORATÓRIO/INFORMÁTICA)
CONSIDERE O TRECHO DO PROGRAMA PYTHON ABAIXO:

DEF FUNC():
X=1
PRINT(X)
X = 10
FUNC()
PRINT(X)
OS VALORES IMPRESSOS, AO SE EXECUTAR O
PROGRAMA, SÃO, RESPECTIVAMENTE:
1 e 1.

10.

1 e 10.

10 e 10.

2. (MS CONCURSOS/2016/CRECI 1° REGIÃO (RJ)/ANALISTA


DE TI) QUAL ALTERNATIVA REPRESENTA A DECLARAÇÃO
DE UMA VARIÁVEL NA LINGUAGEM DE PROGRAMAÇÃO
PYTHON?
var valor = 3;

boolean inicio = falso;

texto = ‘texto de exemplo’

int i = 1;

GABARITO

1. (2017/IF-CE/Técnico de Laboratório/Informática) Considere o trecho do


programa Python abaixo:

def func():
x=1

print(x)

x = 10

func()

print(x)

Os valores impressos, ao se executar o programa, são, respectivamente:


A alternativa "C " está correta.

A variável x da linha 2 é local da função func(), sendo visível para a


chamada print() da linha 3. Por sua vez, a variável x da linha 5 é global, sendo
visível para a chamada print() da linha 7.

2. (MS CONCURSOS/2016/Creci 1° Região (RJ)/Analista de TI) Qual


alternativa representa a declaração de uma variável na linguagem de
programação Python?

A alternativa "C " está correta.

Lembre-se de que, em Python, as variáveis não são declaradas com o tipo


vinculado. Assim, basta atribuir um valor inicial à variável para que ela possa
ser usada. Isso ocorre com a variável texto, que recebe o valor inicial “texto de
exemplo”.

MÓDULO 3

Identificar os tipos de dados e as expressões em Python


CONCEITOS
Neste módulo, você será apresentado aos tipos padrão incorporados ao
interpretador Python. Os principais tipos internos
são numéricos, sequenciais e dicionários. Classes, instâncias e exceções
também são tipos padrão, mas não entraremos em detalhes neste tema. Para
ter nosso primeiro contato com expressões em Python, use o prompt interativo
>>>.

Fonte: Freepik

Digite a expressão algébrica 5 + 8 e pressione a tecla [ENTER]. Observe o


resultado na figura 16:
Fonte: o autor (2020) Figura 16 - Expressão no console

O Python Console permite que você calcule expressões algébricas como uma
calculadora, além de executar instruções básicas em Python.

TIPOS NUMÉRICOS
Existem três tipos numéricos distintos em Python: inteiros, números de ponto
flutuante e números complexos. Além disso, os booleanos são um subtipo dos
inteiros.

O TIPO INT
É o tipo usado para manipular números inteiros. Fazendo uma analogia com a
Matemática, o tipo int é usado para elementos do conjunto dos inteiros (Z).

Diferentemente de outras linguagens, como C ou Java, a linguagem Python


não limita o tamanho de uma variável de qualquer tipo, logo, não existe um
valor inteiro máximo definido. O limite depende da quantidade de memória
disponível no computador. De volta ao Python Console, veja algumas coisas
interessantes.
Fonte: Freepik

Digite 1_000_000 e pressione a tecla [ENTER].


Fonte: o autor (2020) Figura 17 - Inteiro com underline

Python permite que você utilize o underline (_) como separador de milhar. Isso
ajuda a visualizar números com muitos dígitos. Para encerrarmos este primeiro
contato com o tipo int, verifique que o valor do exemplo anterior é inteiro.
Fonte: Freepik

Digite type(1_000_000) e pressione a tecla [ENTER].


Fonte: o autor (2020) Figura 18 - Inteiro com underline 2

O TIPO FLOAT
É o tipo usado para manipular números com parte inteira e parte decimal,
chamados de números de ponto flutuante. Fazendo uma analogia com a
Matemática, o tipo float é usado para elementos do conjunto dos reais (R).
Fonte: Freepik

Para diferenciar um número real de um inteiro, é possível utilizar a parte


decimal zerada. No prompt interativo >>>, digite type(50.0) e pressione a tecla
[ENTER].
Fonte: o autor (2020) Figura 19 - Real com parte decimal zerada

ATENÇÃO
Vale ressaltar que devemos usar o ponto para separar a parte inteira da parte
decimal, e não a vírgula.
Fonte: Freepik

No prompt, digite 50.0 (com ponto) e pressione [ENTER]. Em seguida,


digite 50,0 (com vírgula) e pressione a tecla [ENTER].
Fonte: o autor (2020) Figura 20 - Separador de número real

Ao usar a vírgula como separador em Python, o que ocorre, na verdade, é a


criação de uma tupla de dois elementos, e não o tipo float. Você verá mais
detalhes sobre tuplas em um momento posterior.
Embora os tipos int e float sejam semelhantes, por tratarem de números, eles
têm propriedades um pouco diferentes. Em expressões algébricas, sempre que
somamos, subtraímos ou multiplicamos apenas elementos do tipo int, o
resultado é int. Porém, basta um operando do tipo float para que o resultado
seja float. Observe a figura 21:
Fonte: o autor (2020) Figura 21 - Expressões com tipos diferentes

Vamos analisar a exponenciação. Para realizar essa operação matemática,


utilizamos o operador (**). Veja a figura 22:

Fonte: o autor (2020) Figura 22 - Exponenciação

Veja que basta que a base seja float para que o resultado também o seja.

ATENÇÃO
Diferentemente de outras linguagens, como C, a divisão de dois números
inteiros não necessariamente tem resultado inteiro.

Fonte: Freepik

Digite 5/2 e pressione [ENTER].


Fonte: o autor (2020) Figura 23 - Divisão de inteiros

Para obter o quociente inteiro e o resto, quando dois inteiros são divididos, é
necessário utilizar os operadores // e %, respectivamente. Ao dividir 21 por 2,
temos quociente 10 e resto 1. Observe a figura 24:

Fonte: o autor (2020) Figura 24 - Divisão inteira e resto

O TIPO COMPLEX
É o tipo utilizado para manipular números complexos, na forma x + yj,
sendo x a parte real e y a parte imaginária do complexo.

Veja dois exemplos de variáveis do tipo complex nas figuras 25 e 26, em que a


parte real é 2 e a parte imaginária é 5:

Fonte: o autor (2020) Figura 25 - complex 1

Fonte: o autor (2020) Figura 26 - complex 2


A chamada r.conjugate() retorna o conjugado do número complexo r, em que
a parte real é mantida e a parte imaginária tem o seu sinal trocado.

O TIPO BOOL
Uma expressão algébrica, como vimos nos exemplos dos tipos int e float, é
avaliada como um número, seja desses tipos ou de outro tipo numérico
admitido em Python. Porém, utilizar expressões não algébricas também é
bastante comum. E uma boa notícia é que Python pode avaliar expressões
desse tipo também. Essa é uma diferença entre Python e outras linguagens,
como C, por exemplo, em que não existe o tipo bool.

Fonte: Freepik
No prompt interativo >>>, digite a expressão 2 < 3 e pressione [ENTER].
Observe o resultado na figura 27:

Fonte: o autor (2020) Figura 27 – bool 1

Repare que o resultado dessa expressão não é um número, mas sim a


palavra True. Caso você colocasse a expressão 2 > 3, o resultado seria False,
como pode ver na figura 28.
Fonte: o autor (2020) Figura 28 - bool 2

 SAIBA MAIS
As expressões que você viu nos dois exemplos são chamadas de expressões
booleanas. Trata-se de expressões que podem ser avaliadas com um dos dois
valores booleanos: True ou False. Assim, em Python, existe o tipo bool,
utilizado para permitir o tratamento de expressões como essas.

Agora, vamos ver o operador not, que é um operador unário, ou seja, só


precisa de um operando. Esse operador inverte o valor booleano, ou seja, se o
valor original for True, not(valor) terá o valor False. E vice-versa.
Fonte: Freepik

No prompt interativo >>>, digite a expressão not(2 < 3) e pressione [ENTER].


Fonte: o autor (2020) Figura 29 - bool 3

É possível também escrever expressões booleanas compostas, utilizando


conectivos como E OU. Vamos ver mais detalhes sobre essas expressões
ainda neste módulo.

OPERADORES NUMÉRICOS

OPERADORES MATEMÁTICOS
Os operadores matemáticos são muito semelhantes àqueles que vimos ao
longo de nossa jornada como estudantes, aprendendo Álgebra e Aritmética na
escola. Existem algumas pequenas diferenças, como a divisão (que pode ser a
usual ou a divisão inteira). Mas é possível identificar operações que fizemos ao
longo de toda nossa vida. A tabela 2 lista os operadores de expressão
aritmética disponíveis em Python.

 Atenção! Para visualização completa da tabela utilize a rolagem horizontal


Operação matemática Símbolo usado

Soma +

Subtração -

Multiplicação *

Divisão /

Divisão inteira //

Resto na divisão inteira %

Valor absoluto abs(parâmetro)

Exponenciação **

Tabela 2 - Operadores matemáticos - Fonte: o autor (2020)

Além das operações algébricas, é possível realizar operações de comparação.


Os operadores de comparação têm como resultado um valor booleano
(True ou False). Observe a tabela 3:

 Atenção! Para visualização completa da tabela utilize a rolagem horizontal

Símbolo usado

< Me
<= Me

> Ma

>= Ma

== Igu

!= Nã

Tabela 3 - Operadores de comparação - Fonte: o autor (2020)

ATENÇÃO
Cabe observar que o operador utilizado para comparar se dois valores são
iguais é o ==, ou seja, duplo sinal de igual. Tome cuidado para não confundir
com o operador de atribuição, que é representado pelo sinal de igual apenas
uma vez (=).

Existe outra lista de operadores que executam operações matemáticas, mas,


além disso, atualizam o valor da variável utilizada. Eles são chamados de
operadores compostos e serão detalhados no módulo 4. Para mais funções
matemáticas, você pode utilizar os módulos matemáticos math e fractions.

OPERADORES BOOLEANOS
As expressões booleanas são aquelas que podem ter como resultado um dos
valores booleanos: True ou False. É comum utilizarmos os operadores de
comparação em expressões booleanas, mas não só eles.

Assim como é possível escrever expressões algébricas complexas


concatenando diversas expressões menores, podemos escrever expressões
booleanas grandes, com os operadores and, or e not. Observe o
comportamento dos operadores booleanos nas tabelas 4, 5 e 6.
 Atenção! Para visualização completa da tabela utilize a rolagem horizontal

True False

False True

Tabela 4 - Operador not

p q

True True

True False

False True

False False

Tabela 5 - Operador and

p q

True True

True False

False True

False False

Tabela 6 - Operador or
Fonte: kikujungboy CC/Shutterstock

TIPOS SEQUENCIAIS
Existem três tipos sequenciais básicos em Python: listas, tuplas e objetos
range. Além dos tipos básicos citados, existe um tipo especial criado para
tratamento de dados textuais: o tipo str (string).

Assim como em C ou Java, a indexação dos itens é iniciada com 0 e cada item
tem o seu índice incrementado uma unidade em relação ao item anterior.
Porém, Python também permite a indexação com valores negativos. O valor -1
é o índice do último item, e cada item anterior é decrementado de uma unidade
em relação ao sucessor. Observe a tabela 7:

 Atenção! Para visualização completa da tabela utilize a rolagem horizontal

índice 0 1

s t e

índice negativo -5 -4

Tabela 7 - Índices em tipos sequenciais - Fonte: o autor (2020)

STRINGS
Em uma variável do tipo str, é possível armazenar letras, números, espaços,
pontuação e diversos símbolos. Diferentemente da linguagem C, não existe o
tipo char. Cada caractere em Python é uma string. Para delimitar uma string,
podemos utilizar:

ASPAS SIMPLES
‘uma string'

ASPAS DUPLAS
“uma string”

ASPAS SIMPLES TRIPLAS


‘’’uma string’’’

ASPAS DUPLAS TRIPLAS


“””uma string”””

A Figura 30 ilustra um exemplo de delimitadores de strings:

Fonte: o autor (2020) Figura 30 - Delimitadores de Strings


Existem alguns métodos interessantes para tratar strings em Python. Entre
eles, ressaltamos:

UPPER
Transforma todas as letras em maiúsculas.

LOWER
Transforma todas as letras em minúsculas.

SPLIT
Quebra a string em substrings.

Veja os exemplos a seguir:

Fonte: o autor (2020) Figura 31 - Métodos de strings

 SAIBA MAIS
A lista gerada com o método split() tem três elementos, porque a string original
tinha três palavras.

LISTAS
Listas são sequências mutáveis, normalmente usadas para armazenar
coleções de itens homogêneos. Uma lista pode ser criada de algumas
maneiras, tais como:

[]
Usando um par de colchetes para denotar uma lista vazia.

[A], [A, B, C]
Usando colchetes, separando os itens por vírgulas.

[X FOR X IN ITERABLE]
Usando a compreensão de lista.

LIST() OU LIST(ITERABLE)
Usando o construtor do tipo list.

 SAIBA MAIS
iterable pode ser uma sequência, um container que suporte iteração ou um
objeto iterador. Por exemplo, list('abc') retorna ['a', 'b', 'c'] e list( (1, 2,
3) ) retorna [1, 2, 3]. Se nenhum argumento for passado, o construtor cria uma
lista vazia: [ ].

SUPORTE ITERAÇÃO OU UM OBJETO


ITERADOR
Um iterador é um objeto que contém um número contável de valores. Ele pode
ser iterado, o que significa que podemos percorrer todos os valores.

TUPLAS
Tuplas são sequências imutáveis, tipicamente usadas para armazenar
coleções de itens heterogêneos. Elas são aplicadas também quando é
necessário utilizar uma sequência imutável de dados homogêneos. Uma tupla
pode ser criada de algumas maneiras, tais como:

()
Usando um par de parênteses para denotar uma tupla vazia.

A, B, C OU (A, B, C)
Separando os itens por vírgulas.

TUPLE() OU TUPLE(ITERABLE)
Usando o construtor do tipo tuple.

Novamente, iterable pode ser uma sequência, um container que suporte


iteração ou um objeto iterador. Por exemplo, tuple('abc') retorna ('a', 'b', 'c')
e tuple( [1, 2, 3] ) retorna (1, 2, 3). Se nenhum argumento for passado, o
construtor cria uma tupla vazia: ().

 ATENÇÃO
Note que o uso das vírgulas é o que gera a tupla, e não o uso de parênteses.
Os parênteses são opcionais, exceto no caso em que queremos gerar uma
tupla vazia.

RANGE
O tipo range representa uma sequência imutável de números e
frequentemente é usado em loops de um número específico de vezes, como
o for.

Ele pode ser chamado de maneira simples, apenas com um argumento. Nesse
caso, a sequência começará em 0 e será incrementada de uma unidade até o
limite do parâmetro passado (exclusive). Por exemplo, range(3) cria a
sequência (0, 1, 2).
Para que a sequência não comece em 0, podemos informar o início e o fim
como parâmetros, lembrando que o parâmetro fim não entra na lista (exclusive
o fim). O padrão é incrementar cada termo em uma unidade. Ou seja, a
chamada range(2, 7) cria a sequência (2, 3, 4, 5, 6).

 SAIBA MAIS
Também é possível criar sequências mais complexas, indicando os parâmetros
de início, fim e passo, nessa ordem. O passo é o valor que será incrementado
de um termo para o próximo. Por exemplo, range(2, 9, 3) cria a sequência (2,
5, 8).

Fonte: BEST-BACKGROUNDS/Shutterstock

OPERADORES SEQUENCIAIS COMUNS


Os operadores sequenciais permitem a manipulação dos tipos sequenciais,
inclusive as strings. Vale ressaltar a sobrecarga dos operadores + e *, que
realizam operações diferentes quando os operandos são numéricos ou
sequenciais.

EXEMPLO
O operador == verifica se as strings dos dois lados são iguais. Porém, os
operadores < e > comparam as strings usando a ordem do dicionário.

A tabela a seguir traz um pequeno conjunto dos operadores disponíveis em


Python para manipulação de sequências. Lembre-se de que você pode utilizar
o utilitário help no Python Console para verificar a lista completa. Para isso,
basta digitar help(str) e pressionar [ENTER] no teclado.

 Atenção! Para visualização completa da tabela utilize a rolagem horizontal

Uso

x in s True se x for um subconjunto de s

x not in s False se x for um subconjunto de s

s+t Concatenação de s e t

n*s Concatenação de n cópias de s

s[i] Caractere de índice i em s

len(s) Comprimento de s

min(s) Menor item de s

max(s) Maior item de s

Tabela 8 – Operadores sequenciais

DICIONÁRIOS
Os dicionários permitem que itens de uma sequência recebam índices
definidos pelo usuário. Um dicionário contém pares de (chave, valor). O
formato geral de um objeto dicionário é:

{<chave 1>:<valor 1>, <chave 2>:<valor 2>, ..., <chave i>:<valor i>}

EXEMPLO
Poderíamos criar um dicionário em que cada pessoa fosse representada pelo
seu CPF, com nome e sobrenome. Para isso, teríamos:

Fonte: o autor (2020) Figura 32 - Dicionários - Fonte: o autor (2020)

Na figura 32, o dicionário tem 3 entradas. Observe como foi possível recuperar
nome e sobrenome de uma entrada, baseado na chave informada ‘111222333-
44’.

Para ver uma demonstração no Python dos tipos sequenciais e


dos dicionários, assista ao vídeo a seguir.
PRECEDÊNCIA DE OPERADORES
Ao escrever uma expressão algébrica, o programador pode utilizar a
precedência de operadores existente em Python (implícita) ou explicitar a
ordem em que ele deseja que a expressão seja avaliada.

EXEMPLO
Por exemplo, a expressão 3 + 2 * 5 tem como resultado 25 ou 13? Aprendemos
no ensino fundamental que as operações de produto e divisão têm precedência
sobre as operações de soma e subtração. Ou seja, um produto será realizado
antes de uma soma, na mesma expressão. Assim, a expressão acima tem
como resultado 13. Isso ocorre sempre que não forem explicitadas outras
relações de precedência com o uso de parênteses. Caso o programador
quisesse forçar que a soma ocorresse primeiro, ele deveria escrever assim: (3
+ 2) * 5.

Sempre que o programador quiser forçar a ocorrência de uma operação antes


de outras, ele pode utilizar os parênteses para aumentar a prioridade sobre ela.
A tabela a seguir traz as relações de precedência entre os operadores, com as
linhas mais altas tendo prioridade sobre as linhas mais baixas. Ou seja, elas
ocorrem primeiro. Dentro da mesma linha, a precedência é da esquerda para a
direita.

 Atenção! Para visualização completa da tabela utilize a rolagem horizontal

Operador

[expressões ...] Definição de list

x[ ], x[índice : índice] Operador de ind

** Exponenciação
+x, -x Sinal de positivo

*, /, //, % Produto, divisão

+, - Soma, subtraçã

in, not in, <, <=, >, >=, <>, !=, == Comparações, i

not x Booleano NOT (

and Booleano AND (

or Booleano OR (o

Tabela 9 - Precedência de operadores

ATENÇÃO
É importante ficar atento ao uso correto dos operadores, respeitando a
precedência entre eles, para evitar que algum cálculo seja realizado
corretamente, mas com resultado diferente do esperado por você ao
programar.

CONVERSÕES DE TIPOS
Quando temos tipos diferentes envolvidos na mesma expressão, o Python
converte implicitamente cada operando para o tipo mais abrangente envolvido
na expressão. Estamos usando a palavra abrangente, mas poderíamos falar
que existem tipos que englobam (ou contêm) outros.

EXEMPLO
Um número do tipo int pode ser visto como um float com a parte decimal nula.
Porém, o inverso não é verdade. Ou seja, o conjunto dos inteiros (int) é um
subconjunto do conjunto dos reais (float). Assim, a expressão 5 + 0.68 – que
envolve um int e um float – tem como resultado 5.68. O inteiro 5 é convertido
pelo Python para o número de ponto flutuante 5.0 antes que a soma (de dois
valores float) seja realmente efetuada.

Uma conversão implícita não intuitiva é a dos valores


booleanos True e False em inteiros, respectivamente, 1 e 0. Veja os exemplos
a seguir:

Fonte: o autor (2020) Figura 33 - Conversão de tipos

Com isso, podemos perceber a seguinte relação entre os


tipos bool, int e float:
Fonte: o autor (2020) Figura 34 - Relação entre os tipos bool, int e float

Além das conversões implícitas, o programador também pode usar as


conversões explícitas, quando ele força que o valor seja tratado como de
determinado tipo. Para isso, é necessário usar o construtor do tipo desejado,
com o valor passado como parâmetro (entre parênteses). Veja o exemplo a
seguir:

Fonte: o autor (2020) Figura 35 - Conversão explícita


O int 2 pode ser tratado naturalmente como o float 2.0, basta acrescentar a
parte decimal nula. Porém, ao tentar tratar um float como int, ocorre a
remoção da parte decimal.

ATENÇÃO
Fique atento, porque não é uma aproximação para o inteiro mais próximo, e
sim o truncamento.

Agora que você já viu os principais tipos de dados suportados em Python,


vamos exercitar e verificar o aprendizado.

VERIFICANDO O APRENDIZADO
1. CONSIDERE A EXPRESSÃO A SEGUIR: 2 + 3 – 4 ** 2 + 5 / 2
– 5 // 2

ASSINALE A OPÇÃO COM O VALOR CORRETO DESSA


EXPRESSÃO EM PYTHON.
-10.5

-1

1.5

2. (ADAPTADA DE COMPERVE/2019/UFRN/ENGENHARIA DA
COMPUTAÇÃO) PYTHON É UMA LINGUAGEM
INTERPRETADA MUITO UTILIZADA. NÃO REQUER TIPAGEM
DE VARIÁVEIS E SUA SINTAXE INDENTADA FAVORECE A
ORGANIZAÇÃO DO CÓDIGO. UMA DAS SUAS
FUNCIONALIDADES MAIS PODEROSAS SÃO AS LISTAS.
CONSIDERE O CÓDIGO EM PYTHON DO QUADRO ABAIXO:
FONTE: O AUTOR (2020)
A SAÍDA CORRETA CORRESPONDENTE ÀS LINHAS 2 E 4
DO CÓDIGO É:
2 e 4.

4 e 16.

2 e 16.

4 e 4.

GABARITO

1. Considere a expressão a seguir: 2 + 3 – 4 ** 2 + 5 / 2 – 5 // 2

Assinale a opção com o valor correto dessa expressão em Python.


A alternativa "A " está correta.

Lembre-se que o operador ** tem precedência maior do que os operadores /


e //, os quais, por sua vez, têm precedência sobre + e -. Ou seja, primeiro será
efetuada a exponenciação (4**2), depois as divisões, comum (5/2) e inteira
(5//2), para posteriormente serem efetuadas as somas e subtrações.

2. (Adaptada de COMPERVE/2019/UFRN/Engenharia da Computação)


Python é uma linguagem interpretada muito utilizada. Não requer tipagem
de variáveis e sua sintaxe indentada favorece a organização do código.
Uma das suas funcionalidades mais poderosas são as listas. Considere o
código em Python do quadro abaixo:
Fonte: o autor (2020)

A saída correta correspondente às linhas 2 e 4 do código é:


A alternativa "A " está correta.

O operador + realiza operações de soma para tipos numéricos e concatenação


para tipos sequenciais. Assim, a variável a na linha 1 passa a ser composta
dos itens ‘UF’ e ‘RN’. Assim, a chamada len(a) retorna o tamanho 2, número de
elementos de a. De forma semelhante, o operador * realiza operações de
multiplicação para tipos numéricos e concatenação de cópias para tipos
sequenciais. Assim, a variável b na linha 3 passa a ser a lista ['4', '4', '4', '4']. E
a chamada len(b) retorna o tamanho 4, número de elementos de b.

MÓDULO 4

Identificar as formas de atribuição, de entrada e saída de dados em Python

CONCEITOS
Já vimos, de maneira básica, como podemos atribuir valor a uma variável, no
módulo 2. Vamos agora conhecer outras formas de atribuição.
Fonte: BEST-BACKGROUNDS/Shutterstock

SENTENÇAS DE ATRIBUIÇÃO

ATRIBUIÇÃO SIMPLES
Chamamos de atribuição simples a forma que já utilizamos neste tema, com
uma expressão parecida com x = 10. Nessa atribuição, a variável x recebe o
valor 10.

ATRIBUIÇÃO MÚLTIPLA
Python também permite a atribuição múltipla, ou seja, mais de uma variável
receber atribuição na mesma linha. Veja o exemplo na figura 36:
Fonte: o autor (2020) Figura 36 - Atribuição múltipla

ATENÇÃO
Observe que as variáveis x e y receberam atribuição na mesma instrução, com
a variável x armazenando o valor 2, e a variável y armazenando o valor 5.

OPERADORES DE ATRIBUIÇÃO COMPOSTOS


Os operadores de atribuição compostos executam operações matemáticas e
atualizam o valor da variável utilizada. Por exemplo, veja a figura 37:
Fonte: o autor (2020) Figura 37 - Atribuição e atualização de variável

A variável x inicialmente recebeu o valor 10. Em seguida, a instrução x = x + 1,


que causa estranheza quando lembramos da matemática aprendida ao longo
da vida, é muito comum quando estamos programando. Essa instrução
significa “acrescente uma unidade ao valor de x e guarde este resultado na
própria variável x”. Como x valia 10, o resultado do lado direito do operador (=)
é 11. Esse resultado é, então, armazenado na própria variável x.
Essa operação de acrescentar determinado valor a uma variável e armazenar o
resultado na própria variável poderia ser feita com o operador += (mais igual).
Veja a figura 38:
Fonte: o autor (2020) Figura 38 - Operador mais igual

Na tabela 10, estão os operadores compostos disponíveis em Python.


Considere a variável x, com o valor inicial 10, para verificar os resultados.

 Atenção! Para visualização completa da tabela utilize a rolagem horizontal

Nome Símbolo usado

Mais igual += x

Menos igual -= x

Vezes igual *= x

Dividido igual /= x

Módulo igual %= x
Tabela 10 - Operadores compostos

ATENÇÃO
Diferente de C, em Python não é possível incrementar ou decrementar uma
variável com um operador unário, como o ++ ou --.

TROCA DE VARIÁVEIS
Um dos problemas iniciais que envolvem atribuição de valores a variáveis é a
troca entre duas delas. Suponha que as variáveis a e b armazenem,
respectivamente, os valores 1 e 2. Caso quiséssemos inverter os valores em
linguagens como C ou Java, seria necessário usar uma variável auxiliar, com
uma sequência de instruções exibida na figura a seguir:

Fonte: o autor (2020) Figura 39 - Troca de variáveis 1

Em Python, é possível fazer essa troca de uma maneira muito mais fácil. Veja o
uso da atribuição múltipla, nesse caso, na figura a seguir:
Fonte: o autor (2020) Figura 40 - Troca de variáveis 2

O PRIMEIRO PROGRAMA EM
PYTHON
Para escrever um programa em Python, será essencial utilizar as formas
de saída de dados para exibir ao usuário mensagens e resultados de
operações. Caso você deseje que o usuário informe algum dado para que seu
programa processe, será necessário utilizar as formas de entrada de dados.
Fonte: Freepik

Para criar seu primeiro programa, clique com o botão direito do mouse no
nome do projeto, na guia de navegação do lado esquerdo. Em seguida,
escolha a opção New > File.
Fonte: o autor (2020) Figura 41 - Novo arquivo no PyCharm

Atribua um nome ao seu arquivo. Neste primeiro exemplo, vamos chamar


de primeiro_programa.py

Fonte: o autor (2020) Figura 42 - primeiro_programa.py

Ao nomear o arquivo, será aberta uma nova aba, do lado direito, com o espaço
para que você efetivamente digite as instruções.
Fonte: o autor (2020) Figura 43 - Aba de codificação

SAÍDA DE DADOS COM A FUNÇÃO PRINT()


A função print() em Python atua de forma semelhante à printf() em C. Para um
programador iniciante, as maiores diferenças entre elas são:

Duas chamadas da print() em Python são impressas na tela em linhas


diferentes, sem a necessidade do uso do caractere ‘\n’ para pular a linha, como
ocorre na printf() em C.

Uma chamada da print() em Python permite a impressão de valores de


variáveis sem a indicação do formato, como ocorre na printf() em C, quando
precisamos escrever %c, %d ou %f, por exemplo.
Fonte: Freepik

Para escrever seu Hello World em Python, digite a seguinte linha, exatamente
como está escrita:

print(“Hello World”)

Em seguida, clique com o botão direito do mouse sobre o nome do programa e


escolha a opção Run ‘primeiro_programa’. Também é possível executar com
a combinação de teclas CTRL+Shift+ F10. Após executar, observe o console
na figura 44:
Fonte: o autor (2020) Figura 44 - Execução do Hello World em Python

Veja que foi impresso no console exatamente o que colocamos entre aspas, ao
chamar a função print(). Essa é a primeira forma de saída de dados: usar a
função print() com uma string sendo passada como parâmetro (entre os
parênteses). É importante perceber que a função print(), além de imprimir a
string, também salta o cursor para a próxima linha.

Como você deve ter percebido, o que a função print() recebeu entre


parênteses foi uma string. Ou seja, poderíamos ter passado para ela uma string
definida anteriormente, como no exemplo a seguir:
Fonte: o autor (2020) Figura 45 - Hello World com string

Também poderíamos ter passado como parâmetro uma variável definida


anteriormente. A função print() vai trabalhar com o valor dessa variável.
Observe as figuras 46 e 47:

Fonte: o autor (2020) Figura 46 - Print de variável


Fonte: o autor (2020) Figura 47 - Execução do print com variável

ENTRADA DE DADOS COM A


FUNÇÃO INPUT()
Quando o programador quiser que o usuário entre com algum valor, ele deverá
exibir na tela o seu pedido. Em C, é necessário utilizar a função printf() para
escrever a solicitação ao usuário e a função scanf() para receber a entrada e
armazenar em uma variável. Em Python, é possível utilizar a função input().
Ela tanto exibe na tela o pedido, como permite que o valor informado pelo
usuário seja armazenado em uma variável do seu programa. Analise a figura
48:
Fonte: o autor (2020) Figura 48 - A função input()

A linha 1 fará com que a frase Entre com seu nome: seja exibida no console,
mas a execução do programa fica travada até que o usuário aperte [ENTER] no
teclado. Tudo o que foi digitado até o [ENTER] vai ser armazenado na
variável nome. A linha 2 fará a exibição do conteúdo da variável nome. Veja o
resultado no console, com o usuário tendo digitado Fulano de Tal.

Fonte: o autor (2020) Figura 49 - Execução da entrada de dados


ATENÇÃO
É importantíssimo perceber que a função input() trata tudo o que for digitado
pelo usuário como uma string, armazenando na variável designada pelo
programador para isso. Mesmo que o usuário entre com apenas uma letra ou
um número, isso será armazenado como uma string na variável.

Vamos analisar o exemplo a seguir:

Fonte: o autor (2020) Figura 50 - A função input() e operação numérica

Veja o console quando o programa é executado:

Fonte: o autor (2020) Figura 51 - Erro com a função input()

O usuário digitou 3 e [ENTER]. Mesmo sendo um valor, a


variável numero trata como a string ‘3’. Isso impede que seja realizada a
operação de soma com o inteiro 2, por exemplo. Poderíamos também usar a
instrução print(type(numero)) na linha 2 para confirmar. Veja:

Fonte: o autor (2020) Figura 52

Fonte: o autor (2020) Figura 53

A FUNÇÃO EVAL()
A função eval() recebe uma string, mas trata como um valor numérico. Veja o
exemplo a seguir:

Fonte: o autor (2020) Figura 54

Mesmo tendo recebido a string ‘1+2’ como parâmetro, a função eval() efetuou


a soma de 1 com 2. Observe que confirmamos que s é uma string com a
instrução type(s).
Para tratar a entrada do usuário como um número e, com isso, realizar
operações algébricas, por exemplo, é necessário utilizar a função eval() em
conjunto com a input(). Veja o próximo exemplo:
Fonte: o autor (2020) Figura 55

Fonte: o autor (2020) Figura 56

MÃO NA MASSA
COMO EXERCÍCIO PRÁTICO, TENTE
ESCREVER UM PROGRAMA PARA
CALCULAR E INFORMAR O IMC (ÍNDICE
DE MASSA CORPÓREA) DO USUÁRIO,
QUE DEVERÁ FORNECER SEU PESO E
SUA ALTURA. LEMBRE-SE QUE O IMC É
CALCULADO PELA
FÓRMULA: IMC=PESOALTURA2

RESPOSTA
Uma solução simples é a da figura 57:

Fonte: o autor (2020) Figura 57


Fonte: o autor (2020) Figura 58

SAÍDA FORMATADA DE DADOS


Quando desejamos que a saída siga determinado padrão – por exemplo, de
hora ou de data – existem algumas possibilidades para usar a função print(). É
sempre possível utilizar a concatenação de strings, com o operador +, para
montar a frase como quisermos. Suponha que tenhamos as seguintes
variáveis:
hora = 10 minutos = 26 segundos = 18
Poderíamos chamar a função print() com o separador : da seguinte forma:
Fonte: o autor (2020) Figura 59

Porém, existe outra possibilidade, usando o método format(). Ele permite que


a chamada à função print() fique muito parecida com as chamadas à
função printf() em C, com passagem de parâmetros a serem colocados em
ordem na string. Com o método format(), podemos montar a string com as
chaves {} indicando onde entrarão valores, passados como parâmetros
separados por vírgulas.

Fonte: o autor (2020) Figura 60

É importante observar que a quantidade de chaves precisa ser igual à


quantidade de variáveis passadas como parâmetros no método format(). Seria
muito bom se não precisássemos nos preocupar com essa correspondência
para evitar erros bobos. E isso é possível! Para tornar a saída formatada ainda
mais intuitiva, basta utilizar a letra ‘f’ no início dos parâmetros da
função print() e colocar cada variável dentro das chaves na posição em que
deve ser impressa. Veja como fica ainda mais fácil entender:

Fonte: o autor (2020) Figura 61

Também é possível especificar a largura de campo para exibir um inteiro. Se a


largura não for especificada, ela será determinada pela quantidade de dígitos
do valor a ser impresso. Veja a figura 62:

Fonte: o autor (2020) Figura 62

Observe que os valores 10 e 100 foram impressos com espaços em branco à


esquerda. Isso ocorreu porque definimos que a primeira variável deveria ser
impressa com 4 espaços com {:4} (2 foram ocupados e 2 ficaram em branco), e
que a segunda variável deveria ser impressa com 5 espaços com {:5} (3 foram
ocupados e 2 ficaram em branco).

 SAIBA MAIS
Também é válido perceber que o padrão é alinhar os valores à direita do
espaço reservado para a impressão da variável.

O método format() também pode ser usado para imprimir valores de ponto


flutuante com a precisão definida. Veja a figura 63:

Fonte: o autor (2020) Figura 63

Ao usar {:8.5}, estamos determinando que a impressão será com 8 espaços,


mas apenas 5 serão utilizados.

IMPRESSÃO DE SEQUÊNCIAS
Python também permite a impressão de sequências com mais possibilidades
que C, incluindo as strings. Para imprimir um vetor em C, por exemplo,
precisamos chamar a printf() item a item. Em Python, basta chamar a
função print() passando como parâmetro a sequência. Veja a figura 64:

Fonte: o autor (2020) Figura 64

Para imprimir uma substring, por exemplo, basta utilizar os colchetes para
indicar o intervalo de índices que deve ser impresso. Vale lembrar que o
primeiro caractere da string é indexado com 0. Veja a figura 65:
Fonte: o autor (2020) Figura 65

ATENÇÃO
Usar [0:4] provoca a impressão dos índices 0, 1, 2 e 3, mas não do índice 4.
Analogamente, usar [2:8] provoca a impressão dos índices de 2 a 7, mas não
do 8.

Também é possível imprimir a string como lida da direita para a esquerda. Para
isso, deve-se utilizar [: : -1]. Esse valor -1 indica que a leitura dos caracteres
será feita no sentido oposto ao tradicional. Observe a figura 66:
Fonte: o autor (2020) Figura 66

ATENÇÃO
Fique atento quando utilizar o intervalo na impressão no sentido inverso,
porque os limites do intervalo devem respeitar esse sentido.

Para ver uma demonstração dos procedimentos de entrada e saída no


Python, assista ao vídeo a seguir.

VERIFICANDO O APRENDIZADO
1. (2015/PGE-RO/TÉCNICO DA
PROCURADORIA/TECNOLOGIA DA INFORMAÇÃO) NA
LINGUAGEM PYTHON, UM COMANDO COMO

A=INPUT("XXX")

PROVOCA:
A associação à variável “a" de uma função denominada “XXX" que pertence à
biblioteca “input".

A criação de uma lista de valores denominada “a" cujo elemento inicial é a


string “XXX".

A leitura de um valor do arquivo de entrada correntemente designado de


acordo com um formato expresso pela string “XXX".

Um prompt no dispositivo de saída e a leitura de um valor que é armazenado


na variável “a".

2. (2015/TJ-BA/ANALISTA JUDICIÁRIO/TECNOLOGIA DA
INFORMAÇÃO/REAPLICAÇÃO) ANALISE O TRECHO DE
PROGRAMA PYTHON APRESENTADO A SEGUIR.

L = [1,2,3,4,5,6,7,8]
PRINT L[::-1]

AO SER EXECUTADO, O RESULTADO EXIBIDO É:


[1, 2, 3, 4, 5, 6, 7, 8]

[8]

[]

[8, 7, 6, 5, 4, 3, 2, 1]

GABARITO

1. (2015/PGE-RO/Técnico da Procuradoria/Tecnologia da Informação) Na


linguagem Python, um comando como

a=input("XXX")
provoca:
A alternativa "D " está correta.

A função input() tanto exibe na tela a string “XXX”, como permite que o valor


informado pelo usuário seja armazenado na variável a.

2. (2015/TJ-BA/Analista Judiciário/Tecnologia da Informação/Reaplicação)


Analise o trecho de programa Python apresentado a seguir.

L = [1,2,3,4,5,6,7,8]
print L[::-1]

Ao ser executado, o resultado exibido é:


A alternativa "D " está correta.

A impressão da sequência L com a chamada L[::-1] é feita percorrendo toda a


sequência L, em sentido inverso.

CONCLUSÃO

CONSIDERAÇÕES FINAIS
Neste tema, você conheceu as principais características da linguagem Python
e alguns conceitos relativos ao uso de variáveis, bem como aspectos
concernentes à vinculação, como tempo e ambientes. Além disso, viu o
conceito de escopo de visibilidade, tanto estático como dinâmico.
Nos módulos, foi feita uma referência a tipos de dados,
como int, float ou string. Você estudou ainda as formas de atribuição, além de
ter escrito seu primeiro programa em Python, utilizando o que aprendeu e,
também, as formas de entrada e saída de dados que a linguagem oferece.

O uso correto desses conceitos é essencial na sua jornada de formação como


programador. Recomendamos que fique atento aos detalhes e procure sempre
programar de forma organizada. Isso vai evitar erros bobos e tornar sua
experiência mais agradável.

AVALIAÇÃO DO TEMA:

REFERÊNCIAS
BELANI, G. Programming Languages You Should Learn in 2020.
Consultado em meio eletrônico em: 26 mai. 2020.
PERKOVIC, L. Introdução à computação usando Python: um foco no
desenvolvimento de aplicações. Rio de Janeiro: LTC, 2016.
PYCHARM. The Python IDE for Professional Developers. Consultado em
meio eletrônico em: 15 jun. 2020.
PYTHON. PEP 0 – Index of Python Enhancement Proposals (PEPs).
Consultado em meio eletrônico em: 2 jun. 2020.
PYTHON. Fractions – Rational Number. Consultado em meio eletrônico em:
16 jun. 2020.
PYTHON. Math – Mathematical Functions. Consultado em meio eletrônico
em: 16 jun. 2020.

EXPLORE+
 Se você quiser ter mais exercícios para treinar e desafios mais
complexos, recomendamos a visita ao site da Python Brasil.
 Como vimos, dentre as PEPs, destaca-se a PEP8, que estabelece
um guia de estilo de programação. Sugerimos que você pesquise
mais sobre isso.
 Para mais funções matemáticas, você pode utilizar os módulos
matemáticos math e fractions.

CONTEUDISTA
Humberto Henriques de Arruda

CURRÍCULO LATTES
DEFINIÇÃO
Identificação de estruturas de controle, de decisão e de repetição na linguagem
Python, bem como de conceitos e da implementação de subprogramas e
bibliotecas e das formas de tratamento de exceções e eventos.

PROPÓSITO
Reconhecer, na linguagem Python, as estruturas de decisão e de repetição, a
utilização de subprogramas e de bibliotecas e as formas de tratamento de
exceção e eventos.

PREPARAÇÃO
Antes de iniciar o conteúdo deste tema, é necessário que tenha o interpretador
Python na versão 3.7.7 e o ambiente de desenvolvimento PyCharm ou outro
ambiente que suporte o desenvolvimento na linguagem Python.

É necessário conhecer tipos de variáveis em Python, como também realizar a


entrada e saída de dados em Python.

OBJETIVOS
MÓDULO 1
Descrever as estruturas de decisão e repetição em Python

MÓDULO 2
Definir os principais conceitos de subprogramas e a sua utilização em Python

MÓDULO 3
Identificar o uso correto de recursos de bibliotecas em Python

MÓDULO 4
Analisar as formas de tratamento de exceções e eventos em Python
Fonte: BEST-BACKGROUNDS | Shutterstock

INTRODUÇÃO
Programar significa, como em qualquer disciplina, aprender ferramentas que
permitam desenvolver melhor a sua atividade. Ao aprender os conceitos
básicos de programação, o estudante desenvolve habilidades iniciais para
escrever seus primeiros programas. Porém, é difícil imaginar que aplicações
profissionais sejam feitas totalmente baseadas apenas nesses conceitos
básicos.
Ao pensarmos em aplicações mais complexas, é essencial considerar a
necessidade de ganhar tempo, com o computador executando as tarefas
repetitivas, e as demandas de manutenção e tratamento de erros. Para
avançar no aprendizado da programação, você conhecerá novas ferramentas,
entre elas as estruturas de controle, como decisão e repetição, além
dos subprogramas e bibliotecas, bem como as formas de tratar exceções e
eventos.
Vamos começar nossa jornada acessando os códigos-fontes originais
propostos para o aprendizado de Python estruturado. Baixe o arquivo aqui,
descompactando-o em seu dispositivo. Assim, você poderá utilizar os códigos
como material de apoio ao longo do tema!

MÓDULO 1
Descrever as estruturas de decisão e repetição em Python

Fonte: dTosh | Shutterstock

As estruturas de controle permitem selecionar quais partes do código serão


executadas – chamadas de estruturas de decisão – e repetir blocos de
instruções com base em algum critério, como uma variável de controle ou a
validade de alguma condição – chamadas de estruturas de repetição. Neste
módulo, vamos conhecer as estruturas de decisão e de repetição em Python.

TRATAMENTO DAS CONDIÇÕES


As estruturas de decisão e de repetição possuem sintaxes bastante
semelhantes em C e em Python. Mesmo com essa grande semelhança, existe
uma diferença crítica no tratamento das condições. Diferentemente da
linguagem C, Python oferece o tipo bool. Por isso, cabe ressaltar a diferença
de comportamento das duas linguagens nesse tratamento.

Python

Existe o tipo bool Não existe o tipo bool

True Qualquer valor diferente de 0 (


False 0 (zero) ou vazio

 Atenção! Para visualização completa da tabela utilize a rolagem horizontal

Tabela 1 - Tratamento das condições - Fonte: O autor (2020)

ATENÇÃO
Observe que o fato de haver o tipo bool em Python permite que as condições
sejam tratadas como verdadeiras ou falsas, o que não é exatamente igual em
C.

AS ESTRUTURAS DE DECISÃO IF,


IF-ELSE E ELIF
Em Python, é possível utilizar as estruturas de decisão if e if-else da mesma
forma que em C. A diferença principal é o modo de delimitar os blocos de
instruções relativos a cada parte da estrutura. Observe a Tabela 2 e a Tabela
3:

Python

if <condição>:

    Instruções com 4 espaços de indentação

Instrução fora do if

 Atenção! Para visualização completa da tabela utilize a rolagem horizontal

Tabela 2 - Estruturas de decisão simples - Fonte: O autor (2020)

Python
if <condição>:

    Instruções com 4 espaços de indentação (caso a condição seja verdadeira)

else:

    Instruções com 4 espaços de indentação (caso a condição seja falsa)

Instrução fora do if

 Atenção! Para visualização completa da tabela utilize a rolagem horizontal

Tabela 3 - Estruturas de decisão compostas - Fonte: O autor (2020)

Python também oferece a estrutura elif, que permite o teste de duas condições


de forma sequencial. Essa estrutura não existe em C, sendo necessário o
encadeamento de estruturas if-else. Em geral, o formato da estrutura elif é:
1     if <condição 1>:

2     Bloco de código que será executado caso condição seja True

3     elif <condição 2>:

4     Bloco de código que será executado caso condição 1 seja False e condição 2 seja True

5     else:

6     Bloco de código que será executado caso condição 1 seja False e condição 2 seja False

7     Instrução fora do if

Veja uma implementação possível com a estrutura elif na Figura 1:


  1 idade = eval(input('Informe a idade da criança: '))

  2 if idade < 5:

  3 print('A criança deve ser vacinada contra a gripe.')


  4 print('Procure o posto de saúde mais próximo.')

  5 elif idade == 5:

  6 print('A vacina estará disponível em breve.')

  7 print('Aguarde as próximas informações.')

  8 else:

  9 print('A vacinação só ocorrerá daqui a 3 meses.')

10  print('Informe-se novamente neste prazo.')

11 print('Cuide da saúde sempre. Até a próxima.')

Figura 1 - A estrutura elif - Fonte: O autor (2020)

Perceba que a indentação precisa ser ajustada, uma vez que o último else
é relativo ao elif. Por isso, eles precisam estar alinhados.

ESTRUTURA DE REPETIÇÃO FOR


A estrutura de repetição for tem funcionamento muito semelhante nas
linguagens C e Python. Porém, a sintaxe é diferente nas duas linguagens. Além
disso, em Python existe maior flexibilidade, já que a repetição pode ser
controlada por uma variável não numérica.
Antes de detalhar o for, vamos conhecer uma função de Python que gera
uma lista de valores numéricos. Essa lista ajudará a verificar a repetição e
deixará mais claro o entendimento do laço.
AS LISTAS DO TIPO RANGE()
Ao chamar o método range(), Python cria uma sequência de números
inteiros, de maneira simples à mais complexa. Veja a seguir:
SIMPLES
NÃO INICIADAS EM 0
INDICANDO INÍCIO, FIM E PASSO
SIMPLES
Ela pode ser chamada de maneira simples, apenas com um argumento.
Nesse caso, a sequência começará em 0 e será incrementada de uma unidade
até o limite do parâmetro passado (exclusive).
Por exemplo: range(3) cria a sequência (0, 1, 2).

NÃO INICIADAS EM 0
Para que a sequência não comece em 0, podemos informar o início e o fim
como parâmetros, lembrando que o parâmetro fim não entra na lista (exclusive
o fim). O padrão é incrementar cada termo em uma unidade. Ou seja, a
chamada range(2, 7) cria a sequência (2, 3, 4, 5, 6).

INDICANDO INÍCIO, FIM E PASSO


Também é possível criar sequências mais complexas, indicando os
parâmetros de início, fim e passo, nessa ordem. O passo é o valor que será
incrementado de um termo para o próximo.
Por exemplo, range(2, 9, 3) cria a sequência (2, 5, 8).
A SINTAXE DA ESTRUTURA FOR
A estrutura for tem a seguinte sintaxe em Python:
1 for <variável> in <sequência>:

2 Bloco que será repetido para todos os itens da sequência

3 Instrução fora do for

Cabe ressaltar a diferença de sintaxe entre as linguagens C e Python. Veja a


Tabela 4:

Python

for <variável> in <sequência>: for (inicialização; c


    Instruções com 4 espaços de indentação Bloco de instruçõe

Instrução fora do for }

 Atenção! Para visualização completa da tabela utilize a rolagem horizontal

Tabela 4 - A estrutura for - Fonte: O autor (2020)

Vamos analisar um exemplo simples em Python: imprimir todos os elementos


de uma sequência criada com a chamada range(). Veja uma possível
implementação desse exemplo na Figura 2:
1 for item in range(2, 9, 3):

2 print(item)

Figura 2 - Um exemplo do for em Python - Fonte: O autor (2020)

 A linha 1 mostra a criação do laço, com a variável item percorrendo a

sequência (2, 5, 8), criada pela chamada range(2, 9, 3);

 A linha 2 indica a instrução que será executada para cada repetição deste

laço. O laço for executa a instrução da linha 2 três vezes, uma para cada

elemento da sequência (2, 5, 8); o resultado está exemplificado na Tabela 5.

sequên

Iteração 1 do laço item =

Iteração 2 do laço item =

Iteração 3 do laço item =

 Atenção! Para visualização completa da tabela utilize a rolagem horizontal

Tabela 5 - Um exemplo do for em Python - Fonte: O autor (2020))


O LAÇO FOR COM UMA STRING
Python também permite que a repetição aconteça ao longo de uma string.
Para isso, basta lembrar que a string é uma sequência de caracteres
individuais. Suponha que você queira soletrar o nome informado pelo usuário.
Uma possível implementação está na Figura 3:
1 nome = input("Entre com seu nome: ")

2 for letra in nome:

3 print(letra)

Figura 3 - Uso do for com uma string - Fonte: O autor (2020)

 A linha 1 faz com que a palavra inserida pelo usuário seja armazenada na

variável nome;

 A linha 2 mostra a criação do laço, com a variável letra percorrendo a

sequência de caracteres armazenada na variável nome;

 A linha 3 indica a instrução que será executada para cada repetição desse

laço. O laço for executa a instrução da linha 3 tantas vezes quantos forem

os elementos da sequência que está na variável nome.

Veja um exemplo de execução na Figura 4:

1 Entre com o seu nome: Laura

2 L

3 a

4 u

5 r

6 a

Figura 4 - Execução do for com uma string - Fonte: O autor (2020)

USO DO LAÇO FOR COM QUALQUER


SEQUÊNCIA
Até agora, estudamos o uso do laço for com iterações sobre strings e sobre
sequências numéricas, mas Python permite ainda mais que isso!
PODEMOS UTILIZAR O LAÇO FOR COM
ITERAÇÕES SOBRE QUALQUER SEQUÊNCIA, NÃO
SOMENTE AS NUMÉRICAS E AS STRINGS.
Observe o exemplo da Figura 5:

1 nomes = ['Laura', 'Lis', 'Guilherme', 'Enzo', 'Arthur']

2 for nome in nomes:

3 print(nome)

Figura 5 - Uso do for com qualquer sequência - Fonte: O autor (2020)

Veja o resultado da execução na Figura 6:

1 Laura

2 Lis

3 Guilherme

4 Enzo

5 Arthur

Figura 6 - Exemplo de execução do for com qualquer sequência - Fonte: O autor

(2020)

ESTRUTURA DE REPETIÇÃO WHILE


A estrutura de repetição while tem funcionamento e sintaxe muito semelhantes
nas linguagens C e Python. Observe a comparação entre as duas linguagens
na Tabela 6:

Python

while <condição>: while <condição>{

    Instruções com 4 espaços de indentação Bloco de instruçõe


Instrução fora do while }

 Atenção! Para visualização completa da tabela utilize a rolagem horizontal

Tabela 6 - Comparação do while em Python e em C - Fonte: O autor (2020)

Como exemplo inicial do uso do laço while, vamos analisar um programa em


que o usuário precisa digitar a palavra “sair” para que o laço while seja
encerrado.

Uma possível implementação desse exemplo em Python está na Figura 7:

1 palavra = input('Entre com uma palavra: ')

2 while palavra != 'sair':

3 palavra = input('Digite sair para encerrar o laço: ')

4 print('Você digitou sair e agora está fora do laço')

Figura 7 - Um exemplo de implementação do while em Python - Fonte: O autor (2020)

 A linha 1 representa a solicitação ao usuário para que ele insira uma

palavra, que será armazenada na variável palavra;

 A linha 2 cria o laço while, que depende da condição <valor da

variável palavra ser diferente de ‘sair’>;

 A linha 3 será repetida enquanto a condição for verdadeira, ou seja,

enquanto o valor da variável palavra for diferente de ‘sair’. Quando esses

valores forem iguais, a condição do laço while será falsa e o laço será

encerrado;

 A linha 4 representa a impressão da mensagem fora do laço while.

Veja uma execução desse programa na Figura 8:

1 Entre com uma palavra: teste

2 Digite sair para encerrar o laço: Oi?

3 Digite sair para encerrar o laço: Estou tentando...

4 Digite sair para encerrar o laço: Aff...


5 Digite sair para encerrar o laço: Blz, entendi...

6 Digite sair para encerrar o laço: Sair

7 Digite sair para encerrar o laço: Ah! o 'S' foi maiúsculo

8 Digite sair para encerrar o laço: sair

9 Você digitou sair e agora está fora do laço

Figura 8 - Uma execução do while em Python - Fonte: O autor (2020)

Observe agora outra execução do mesmo programa na Figura 9:

1 Entre com uma palavra: sair

2 Você digitou sair e agora está fora do laço

Figura 9 - Outra execução do while em Python - Fonte: O autor (2020)

Perceba que ao digitar ‘sair’ logo na primeira solicitação, a linha 3 do nosso
programa não é executada nenhuma vez. Ou seja, o programa nem chega a
entrar no laço while.
Em C, existe outra estrutura muito semelhante ao while, chamada do-while. A
diferença básica entre elas é o momento em que a condição é testada, como
vemos a seguir:
No laço while, a condição é testada antes da iteração.
O laço while testa e executa caso a condição seja verdadeira.
No laço do-while, a condição é testada após a iteração.
O laço do-while executa e testa.
Infelizmente, a estrutura do-while não existe em Python. Isso não chega a
ser um grande problema, porque podemos adaptar nosso programa e controlar
as repetições com o laço while.
O LAÇO WHILE INFINITO
Laços infinitos são úteis quando queremos executar um bloco de instruções
indefinidamente.

O laço while infinito tem o seguinte formato:


1 while True:

2 Bloco que será repetido indefinidamente

EXEMPLO
Suponha que você deseje criar uma aplicação que permaneça por meses ou
anos sendo executada, registrando a temperatura ou a umidade de um
ambiente. Logicamente, estamos supondo que você tenha essa informação
disponível a partir da leitura de algum sensor.

Deve-se tomar cuidado e ter certeza de que seu uso é realmente necessário
para evitar problemas de consumo excessivo de memória.

No vídeo a seguir, o professor nos apresenta exemplos práticos do uso das


estruturas de decisão e repetição. Vamos assistir!

AS INSTRUÇÕES AUXILIARES
BREAK, CONTINUE E PASS
A INSTRUÇÃO BREAK
A instrução break funciona da mesma maneira em C e em Python. Ela
interrompe as repetições dos laços for e while. Quando a execução do
programa chega a uma instrução break, a repetição é encerrada e o fluxo do
programa segue a partir da primeira instrução seguinte ao laço.
Para exemplificar o uso da instrução break, vamos voltar ao primeiro exemplo
do laço while, utilizando o laço infinito. O laço será encerrado quando o usuário
inserir a palavra ‘sair’. Veja a Figura 10:
1 while True:

2 palavra = input('Entre com uma palavra: ')

3 if palavra == 'sair':

4 break

5 print('Você digitou sair e agora está fora do laço')

Figura 10 - Um exemplo de uso do break em Python - Fonte: O autor (2020)

Caso haja vários laços aninhados, o break será relativo ao laço em que estiver
inserido. Veja a Figura 11:
1 while True:

2 print('Você está no primeiro laço.')

3 opcao1 = input('Deseja sair dele? Digite SIM para isso. ')

4 if opcao1 == 'SIM':

5 break # este break é do primeiro laço

6 else:

7 while True:

8 print('Você está no segundo laço.')

9 opcao2 = input('Deseja sair dele? Digite SIM para isso. ')

10 if opcao2 == 'SIM':

11 break # este break é do segundo laço

12 print('Você saiu do segundo laço.')

13 print('Você saiu do primeiro laço')

14

Figura 11 - Uso do break em laços aninhados - Fonte: O autor (2020)

A INSTRUÇÃO CONTINUE
A instrução continue também funciona da mesma maneira em C e em Python.
Ela atua sobre as repetições dos laços for e while, como a instrução break,
mas não interrompe todas as repetições do laço. A instrução continue
interrompe apenas a iteração corrente, fazendo com que o laço passe
para a próxima iteração.

O exemplo a seguir imprime todos os números inteiros de 1 até 10, pulando


apenas o 5. Veja sua implementação na Figura 12:

1 for num in range(1, 11):

2 if num == 5:

3 continue

4 else:

5 print(num)

6 print('Laço encerrado')

Figura 12 - Exemplo de uso do continue em Python - Fonte: O autor (2020)

Para ressaltar a diferença entre as instruções break e continue, vamos alterar


a linha 3 do nosso programa, trocando a instrução continue pela
instrução break. Veja a nova execução na Figura 13:
1

Laço encerrado

Figura 13 - Troca do continue pelo break - Fonte: O autor (2020)

A INSTRUÇÃO PASS
A instrução pass atua sobre a estrutura if, permitindo que ela seja escrita sem
outras instruções a serem executadas caso a condição seja verdadeira. Assim,
podemos concentrar as instruções no caso em que a condição seja falsa.
Suponha que queiramos imprimir somente os números ímpares entre 1 e 10.
Uma implementação possível está na Figura 14:
1 for num in range(1, 11):

2 if num % 2 == 0:

3 pass

4 else:

5 print(num)

6 print('Laço encerrado')

Figura 14 - Exemplo de uso do pass em Python - Fonte: O autor (2020)

Veja a execução desse programa na Figura 15:

Laço encerrado

Figura 15 - Exemplo de execução com uso do pass em Python - Fonte: O autor (2020)

Claramente, seria possível reescrever a condição do if-else para que


pudéssemos transformá-lo em um if simples, sem else. Porém, o objetivo aqui
é mostrar o uso da instrução pass.

Agora que já vimos os principais conceitos relativos às estruturas de decisão e


de repetição, vamos testar seus conhecimentos.

VERIFICANDO O APRENDIZADO
1. CONSIDERE O SEGUINTE TRECHO DE UM PROGRAMA
ESCRITO EM PYTHON:
1 S = 0
2 FOR I IN RANGE(5):
3 S += 3*I
4 PRINT(S)
ASSINALE A OPÇÃO QUE APRESENTA CORRETAMENTE O
QUE SERÁ IMPRESSO NA TELA.

0   3   9   18   30

0   3   6     9   12

30

45

2. CONSIDERE O SEGUINTE TRECHO DE UM PROGRAMA


ESCRITO EM PYTHON:

1 S = 0
2 A = 1
3 WHILE S < 5:
4 S = 3*A
5 A += 1
6 PRINT(S)
ASSINALE A OPÇÃO QUE APRESENTA CORRETAMENTE O
QUE SERÁ IMPRESSO NA TELA.

3 6

3 3

3   6   9   12

GABARITO

1. Considere o seguinte trecho de um programa escrito em Python:


1 s = 0

2 for i in range(5):

3 s += 3*i

4 print(s)

Assinale a opção que apresenta corretamente o que será impresso na tela.

A alternativa "C " está correta.

O laço for vai ser repetido 5 vezes, já que range(5) retorna a sequência (0, 1,


2, 3, 4). Vale observar que a instrução print(s) está fora do laço for, o que a
leva a ser executada apenas uma vez quando o laço se encerrar. Isso elimina
as opções A e B. A variável s começa com valor zero e é acrescida, a cada
iteração, do valor 3*i, sendo que i pertence à sequência (0, 1, 2, 3, 4). Ou
seja, s recebe os acréscimos: 0 + 3 + 6 + 9 + 12. Assim, ela termina o laço
com o valor 30, que será impresso pela instrução print(s).
2. Considere o seguinte trecho de um programa escrito em Python:

1 s = 0

2 a = 1

3 while s < 5:

4 s = 3*a

5 a += 1

6 print(s)

Assinale a opção que apresenta corretamente o que será impresso na tela.

A alternativa "B " está correta.


Ao ser testada pela primeira vez, a condição do while é verdadeira, já
que s vale zero. Assim, a variável s recebe o valor 3 (3x1) e a variável a é
acrescida de uma unidade, ficando com o valor 2. Em seguida, é impresso o
valor de s (3). A condição do while é, então, testada novamente, sendo mais
uma vez verdadeira, porque s tem o valor 3 (menor que 5). Nessa iteração, a
variável s recebe o valor 6 (3x2) e a variável a é acrescida de uma unidade,
ficando com o valor 3. Em seguida, é impresso o valor de s (6). A condição
do while é, então, testada novamente e é falsa, já que s tem o valor 6, maior
que 5. Com isso, o laço while é encerrado e nada mais é impresso. Logo,
foram impressos os valores 3 e 6.

MÓDULO 2

Definir os principais conceitos de subprogramas e a sua utilização em Python

Fonte: dTosh | Shutterstock

Os subprogramas são elementos fundamentais dos programas e por isso são


importantes no estudo de linguagens de programação. Neste módulo,
abordaremos os conceitos de subprogramas, como características gerais,
passagem de parâmetros e recursividade, além da utilização de subprogramas
em Python.
CARACTERÍSTICAS GERAIS DOS
SUBPROGRAMAS
Todos os subprogramas estudados neste módulo, com base em Sebesta
(2018), têm as seguintes características:

Cada subprograma tem um único ponto de entrada.

A unidade de programa chamadora é suspensa durante a execução do


subprograma chamado, o que significa que existe apenas um subprograma em
execução em determinado momento.

Quando a execução do subprograma termina, o controle sempre retorna para o


chamador.

DEFINIÇÕES BÁSICAS
As definições básicas, conforme Sebesta (2018), estabelecem que:

1
Um subprograma é definido quando o desenvolvedor descreve a interface e
as ações da abstração desse subprograma.
2
O subprograma foi chamado quando uma instrução traz um pedido explícito
para sua execução.

3
O subprograma está ativo após o início de sua execução, a partir da sua
chamada e enquanto ele não foi concluído.
O cabeçalho do subprograma é a primeira parte da definição, em que podem
ser especificados o nome, os parâmetros e o tipo de retorno do subprograma.
Em C, o cabeçalho dos subprogramas – sendo chamados de funções – traz,
em ordem: o tipo de retorno, o nome e a lista de parâmetros, como a seguir:
FLOAT CALCULAIMC (INT PESO, FLOAT ALTURA)
Em Python, as funções definidas pelo desenvolvedor devem ser precedidas
pela palavra reservada def. Não são especificados o tipo de retorno nem os
tipos dos parâmetros, como no exemplo a seguir:
DEF CALCULAIMC (PESO, ALTURA)
Em Python, as sentenças de função def são executáveis. Isso implica que a
função só pode ser chamada após a execução da sentença def. Veja o
exemplo na Figura 16:
 1 escolha = input("Escolha uma opção de função: 1 ou 2")

 2 if escolha == 1:

 3 def func1(x):

 4 return x + 1

 5 else:

 6 def func2(x):

 7 return x + 2

 8

 9 s = func1(10)

10 print(s)

Figura 16 - Funções em Python - Fonte: O autor (2020)

 A função func1() só pode ser chamada caso a variável escolha seja igual a

1. Ou seja, o usuário deverá inserir 1 quando solicitado (na linha 1), para

que a linha 9 possa ser executada sem que seja gerado um erro.

PARÂMETROS
Usualmente, um subprograma executa cálculos e operações a partir de dados
que ele deve processar. Existem duas maneiras de o subprograma obter esses
dados: acessando variáveis não locais, mas visíveis para o subprograma,
ou pela passagem de parâmetros.
Quando o subprograma recebe os parâmetros adequados, ele pode ser
executado com quaisquer valores recebidos. Porém, quando ele manipula
variáveis não locais, uma forma de evitar alterações indevidas nessas variáveis
é fazendo cópias locais delas. De acordo com Sebesta (2018), o acesso
sistemático a variáveis não locais pode diminuir a confiabilidade do programa.
São denominados parâmetros formais aqueles do cabeçalho do
subprograma.
Quando o subprograma é chamado, é necessário escrever o nome do
subprograma e a lista de parâmetros a serem vinculados aos parâmetros
formais dele, que são denominados parâmetros reais ou argumentos.
No exemplo da Figura 16, existe o cabeçalho da função func1 na linha 3, com
o parâmetro formal x. Na linha 9, a função func1 é chamada com o parâmetro
real 10.
Em Python, é possível estabelecer valores padrão para os parâmetros
formais. O valor padrão é usado quando a chamada da função ocorre sem
nenhum parâmetro real. Veja o exemplo de definição e chamada da
função taxímetro na Figura 17:
1 def taximetro(distancia, multiplicador=1):

2 largada = 3

3 km_rodado = 2

4 valor = (largada + distancia * km_rodado) * multiplicador

5 return valor

8 pagamento = taximetro(3.5)

9 print(pagamento)

Figura 17 - Exemplo de função com valor padrão - Fonte: o autor (2020)


 Observe que mesmo com a definição da linha 1 de dois parâmetros

formais, a chamada da função na linha 8 ocorre apenas com um parâmetro

real.

 A palavra reservada return indica que a função retorna algum valor. Isso

implica que o valor retornado seja armazenado em uma variável do

programa chamador (como ocorre na linha 8), ou utilizado como parâmetro

para outra função.


ATENÇÃO
Retornar um valor é diferente de imprimir na tela. Ao utilizar a função print(),
ocorre apenas a impressão de algo na tela, o que não significa que tenha
havido retorno de qualquer função definida pelo usuário.

PROCEDIMENTOS E FUNÇÕES
Os subprogramas podem ser, distintamente, procedimentos e funções. De
acordo com Sebesta (2018):

Procedimentos

São aqueles que não retornam valores.

Funções

São aquelas que retornam valores.

Na maioria das linguagens que não explicita a diferença entre eles, as funções
podem ser definidas sem retornar qualquer valor, tendo comportamento de
procedimento. Esse é o caso de Python. Veja o exemplo da Figura 18:

 1 def func1(x):

 2 x = 10

 3 print(f'Função func1 - x = {x}')

 4

 5
 6 def func2(x):

 7 x = 20

 8 print(f'Função func2 - x = {x}')

 9

10

11 x = 0

12 func1(x)

13 func2(x)

14 print(f'Programa principal - x = {x}')

Figura 18 - Procedimentos e funções - Fonte: O autor (2020)

As funções func1(x) e func2(x) não possuem qualquer retorno. Ou seja, são


funções com comportamento de procedimentos.

AMBIENTES DE
REFERENCIAMENTO LOCAL
VARIÁVEIS LOCAIS
Quando um subprograma define suas próprias variáveis, estabelece ambientes
de referenciamento local. Essas variáveis são chamadas de variáveis locais,
com seu escopo usualmente sendo o corpo do subprograma. As variáveis
locais podem ser:
DINÂMICAS DA PILHA
ESTÁTICAS

DINÂMICAS DA PILHA
São vinculadas ao armazenamento no início da execução do subprograma e
desvinculadas quando essa execução termina. As variáveis locais dinâmicas
da pilha têm diversas vantagens, e a principal delas é a flexibilidade. Suas
principais desvantagens são o custo do tempo – para alocar, inicializar (quando
necessário) e liberar tais variáveis para cada chamada ao subprograma – e o
fato de que os acessos a essas variáveis locais devem ser indiretos, enquanto
os acessos às variáveis estáticas podem ser diretos.

ESTÁTICAS
São vinculadas a células de memória antes do início da execução de um
programa e permanecem vinculadas a essas mesmas células até que a
execução do programa termine. Elas são um pouco mais eficientes que as
variáveis locais dinâmicas da pilha, já que não é necessário tempo para alocar
ou liberar essas variáveis. Sua maior desvantagem é a incapacidade de
suportar recursão, como vai ser explicado adiante.

ATENÇÃO
Nas linguagens C e C++, as variáveis locais são dinâmicas da pilha, a menos
que sejam especificamente declaradas como static. Todas as variáveis locais
em Python são dinâmicas da pilha. As variáveis globais são declaradas em
definições de método, e qualquer variável declarada global em um método
precisa ser definida fora dele. Caso haja uma atribuição à variável local com
mesmo nome de uma variável global, esta é implicitamente declarada como
local.
Voltando ao exemplo da Figura 18, vamos detalhar as
funções func1(x) e func2(x):
 As linhas 1, 2 e 3 definem a função func1(x), que recebe o parâmetro x,

mas tem uma variável local de nome x, cujo valor atribuído é 10;

 Analogamente, a função func2(x) – definida nas linhas 6, 7 e 8 – que

recebe o parâmetro x e tem uma variável de mesmo nome, mas com valor

atribuído 20;

 O programa principal tem uma variável global de mesmo nome x, cujo valor

atribuído é 0, na linha 11;


 Veja que as chamadas às funções func1(x) e func2(x) ocorrem nas linhas

12 e 13, quando a variável x global já recebeu o valor 0. Porém, ao serem

executadas, cada uma dessas funções tem a sua própria variável local, a

quem todas as referências internas são feitas.

Confira a execução desse exemplo na Figura 19:

Função func1 - x = 10

Função func2 - x = 20

Programa principal - x = 0

Figura 19 - Execução de subprograma com variáveis locais - Fonte: O autor (2020)

 Mesmo com a variável global tendo valor nulo, cada variável local das

funções func1(x) e func2(x) tem seu próprio valor, e não ocorrem

alterações na variável global mesmo com as atribuições das linhas 2 e 7.

Para alterar a variável global x, seria necessário explicitar dentro de cada


função que o nome x é referente a ela. Isso pode ser feito com a palavra
reservada global. Além de explicitar a referência à variável global, as
funções func1(x) e func2(x) não recebem mais os parâmetros de mesmo
nome, já que fazem referência à variável global. Veja como ficaria o nosso
exemplo com essa pequena alteração na Figura 20:
 1 def func1():

 2 global x

 3 x = 10

 4 print(f'Função func1 - x = {x}')

 5

 6

 7 def func2():

 8 global x

 9 x = 20

10 print(f'Função func2 - x = {x}')

11
12

13 x = 0

14 func1()

15 func2()

12 print(f'Programa principal - x = {x}')

Figura 20 - Exemplo de subprogramas com referência à variável global - Fonte: O

autor (2020)

Observe agora a execução desse exemplo alterado na Figura 21:

Função func1 - x = 10

Função func2 - x = 20

Programa principal - x = 20

Figura 21 - Execução do exemplo alterado de subprogramas com variável global.

Fonte: O autor (2020)

 Percebe-se que o print() do programa principal está na linha 16, depois da

chamada à função func2(x). Dessa forma, a variável global x foi alterada na

execução da func2(x) e fica com o valor 20 quando a execução volta ao

programa principal.

SUBPROGRAMAS ANINHADOS
Em Python, e na maioria das linguagens funcionais, é permitido aninhar
subprogramas. Porém, as linguagens C e C++ não permitem essa prática. Veja
o exemplo da Figura 22:

  1 def taximetro(distancia)::

  2 def calculaMult():

  3 if distancia < 5:

  4 return 1.2

  5 else:

  6 return 1

  7 multiplicador = calculaMult()
  8 largada = 3

  9 km_rodado = 2

10 valor = (largada + distancia * km_rodado) * multiplicador

11 return valor

12

13

14 dist = eval(input("Entre com a distancia a ser percorrida em km: "))

15 pagamento = taximetro(dist)

16 print(f'O valor a pagar é R$ {pagamento}')

Figura 22 - Exemplo de subprogramas aninhados. Fonte: O autor (2020))

 A função taximetro() tem, dentro de sua definição, a definição de outra

função denominada calculaMult(). Na linha 7, a função calculaMult() é

chamada e o seu retorno é armazenado na variável multiplicador.

MÉTODOS DE PASSAGENS DE
PARÂMETROS
Os métodos de passagem de parâmetros são as maneiras que existem para
transmiti-los ou recebê-los dos subprogramas chamados. Os parâmetros
podem ser passados principalmente por:

VALOR
REFERÊNCIA

VALOR
O parâmetro formal funciona como uma variável local do subprograma, sendo
inicializado com o valor do parâmetro real. Dessa maneira, não ocorre
alteração na variável externa ao subprograma, caso ela seja passada como
parâmetro.
REFERÊNCIA
Em vez de passar o valor do parâmetro real, é transmitido um caminho de
acesso (normalmente um endereço) para o subprograma chamado. Isso
fornece o caminho de acesso para a célula que armazena o parâmetro real.
Assim, o subprograma chamado pode acessar o parâmetro real na unidade de
programa chamadora.

 SAIBA MAIS
Na linguagem C, utilizamos ponteiros para fazer a passagem de parâmetros
por referência. As transmissões de parâmetros que não sejam ponteiros
utilizam a passagem por valor.

O método de passagem de parâmetros de Python é chamado passagem por


atribuição. Como todos os valores de dados são objetos, toda variável é uma
referência para um objeto. Ao se estudar orientação a objetos, fica mais clara a
diferença entre a passagem por atribuição e a passagem por referência. Por
enquanto, podemos entender que a passagem por atribuição é uma
passagem por referência, pois os valores de todos os parâmetros reais
são referências.

RECURSIVIDADE
Uma função recursiva é aquela que chama a si mesma. Veja o exemplo da
função regressiva(), como mostrado na Figura 23:
1 def regressiva(x):

2 print(x)

3 regressiva(x - 1)

Figura 23 - Exemplo de função recursiva - Fonte: O autor (2020)


Na implementação da função regressiva(), tendo x como parâmetro, ela
própria é chamada com o parâmetro x – 1. Vamos analisar a chamada
regressiva(2):
Ao chamar regressiva(2), o valor 2 é exibido na tela pela linha 2, e ocorre uma
nova chamada da função regressiva() na linha 3, com o parâmetro 1. Vamos
continuar com esse caminho de execução da regressiva(1).
Ao chamar regressiva(1), o valor 1 é exibido na tela pela linha 2, e ocorre uma
nova chamada da função regressiva() na linha 3, com o parâmetro 0.

Ao chamar regressiva(0), o valor 0 é exibido na tela e ocorre uma nova


chamada da função regressiva, com o parâmetro -1, e assim sucessivamente.

ATENÇÃO
Conceitualmente, essa execução será repetida indefinidamente até que haja
algum erro por falta de memória. Perceba que não definimos adequadamente
uma condição de parada para a função regressiva(), o que leva a esse
comportamento ruim.

Em Python, o interpretador pode interromper a execução indefinida, mas essa


não é uma boa prática. Uma forma de contornar esse problema é definir
adequadamente uma condição de parada, como no exemplo da Figura 24:

1 def regressiva(x):

2 if x <= 0:

3 print("Acabou")

4 else:

5 print(x)

6 regressiva(x-1)

Figura 24 - Função recursiva com condição de parada - Fonte: O autor (2020)

Uma função recursiva que termina tem:

Um ou mais casos básicos, que funcionam como condição de parada da


recursão.
Uma ou mais chamadas recursivas, que têm como parâmetros valores mais
próximos do(s) caso(s) básico(s) do que o ponto de entrada da função.

Alguns exemplos clássicos de funções que podem ser implementadas de forma


recursiva são o cálculo do fatorial de um inteiro não negativo e a
sequência de Fibonacci, que serão explorados a seguir.
A FUNÇÃO RECURSIVA FATORIAL
A função matemática fatorial de um inteiro não negativo n é calculada por:

n! = 1, se n = 0 ou  n=1n.(n−1).(n−2)...3.2.1, s
e  n≥2n! = 1, se n = 0 ou  n=1n.(n-1).(n-
2)...3.2.1, se  n≥2
 Atenção! Para visualização completa da equação utilize a rolagem horizontal

Além disso, ela pode ser definida recursivamente por:

n! = 1, se n = 0 ou  n=1n.[(n−1)!], se n≥2n! = 
1, se n = 0 ou  n=1n.[(n-1)!], se n≥2
 Atenção! Para visualização completa da equação utilize a rolagem horizontal

Uma implementação recursiva da função fatorial em Python está na Figura 25:

1 def fatorial(n):

2 if n == 0 or n == 1:

3 return 1

4 else:

5 return n*fatorial(n-1)

Figura 25 - Função recursiva fatorial - Fonte: O autor (2020)

Vale ressaltar que a função fatorial também poderia ter sido implementada de
forma não recursiva, como mostrado na Figura 26:
1 def fatorial(n):

2 fat = 1
3 if n == 0 or n == 1:

4 return fat

5 else:

6 for x in range(2, n + 1):

7 fat = fat*x

8 return fat

Figura 26 - Função fatorial com laço for - Fonte: O autor (2020)

Porém, neste tópico, o intuito principal é explorar a recursividade.

A SEQUÊNCIA DE FIBONACCI
A sequência de Fibonacci é: 1, 1, 2, 3, 5, 8, 13, 21... Os dois primeiros termos
são 1 e, a partir do 3º termo, cada termo é a soma dos dois anteriores.

Uma possível implementação recursiva de função que determina o n-ésimo


termo da sequência de Fibonacci está na Figura 27:

1 def fibo(n):

2 if n == 1 or n == 2:

3 return 1

4 else:

5 return fibo(n - 1) + fibo(n - 2)

Figura 27 - Função recursiva para sequência de Fibonacci - Fonte: O autor (2020)

 A linha 2 traz as condições de parada.

 A linha 5 traz as chamadas recursivas para calcular os dois termos

anteriores da sequência.

DOCSTRINGS
Em Python, é possível definir uma string que serve como documentação
de funções definidas pelo desenvolvedor. Ao chamar o
utilitário help() passando como parâmetro a função desejada, essa string é
exibida. Veja a Figura 28 e a Figura 29:
1 def fibo(n):

2 'Determina o n-ésimo termo da sequência de Fibonacci'

3 if n == 1 or n == 2:

4 return 1

5 else:

6 return fibo(n - 1) + fibo(n - 2)

8 print(help(fibo))

Figura 28 - Docstring da função fibo() - Fonte: O autor (2020)

1 fibo(n)

2 Determina o n-ésimo termo da sequência de Fibonacci

Figura 29 - Exibição da docstring da função fibo() - Fonte: O autor (2020)

 Na Figura 28, a linha 2 mostra a declaração da docstring.

 A linha 8 mostra a impressão na tela da chamada help(fibo). Na Figura 29,

está o resultado da execução desse programa.

No vídeo a seguir, o professor nos apresenta exemplos práticos do uso de


procedimentos e funções. Vamos assistir!

VERIFICANDO O APRENDIZADO
1. CONSIDERE O SEGUINTE TRECHO DE UM PROGRAMA
ESCRITO EM PYTHON:

1DEF FUNC1(X):
2X = 10
3PRINT(X)
4
5
6X = 0
7PRINT(X)
8FUNC1(X)
9PRINT(X)
O QUE ACONTECERÁ QUANDO O USUÁRIO TENTAR
EXECUTAR ESSE PROGRAMA?

Ocorrerá um erro e o programa não será executado.

Ocorrerá um erro durante a execução.

Será impresso na tela: 0   10   0

Será impresso na tela: 0   10   10

2. CONSIDERE O SEGUINTE TRECHO DE UM PROGRAMA,


COM UMA IMPLEMENTAÇÃO DE FUNÇÃO RECURSIVA,
ESCRITO EM PYTHON:

1DEF REC(N):
2IF N < 2:
3RETURN REC(N - 1)
4
5
6PRINT(REC(1))
QUANDO O USUÁRIO TENTOU EXECUTAR ESSE
PROGRAMA, HOUVE UM ERRO. QUAL É A CAUSA?
Na linha 2, o if está escrito de maneira errada.
A função não tem condição de parada.

A função está sem retorno.

A função não poderia ter sido definida com uma chamada a ela própria.

GABARITO

1. Considere o seguinte trecho de um programa escrito em Python:

1def func1(x):

2x = 10

3print(x)

6x = 0

7print(x)

8func1(x)

9print(x)

O que acontecerá quando o usuário tentar executar esse programa?

A alternativa "C " está correta.

A variável x da linha 6 é global. Mas, como existe outra variável com o mesmo
nome dentro da função func1() – na linha 2, apenas dentro da função
func1(), x vale 10 –, chamamos essa variável de local. Assim, o print da linha 7
recebe o valor da variável global (0). A execução da linha 8 chama a
função func1(), que imprime o valor de x válido dentro dela (10). Em seguida, a
execução do programa sai da função func1() e o print da linha 9 volta a
enxergar a variável global x, cujo valor é 0.
2. Considere o seguinte trecho de um programa, com uma implementação
de função recursiva, escrito em Python:

1def rec(n):

2if n < 2:

3return rec(n - 1)

6print(rec(1))

Quando o usuário tentou executar esse programa, houve um erro. Qual é a causa?

A alternativa "B " está correta.

A função é recursiva, mas não apresenta parada. Ao ser chamada com o


parâmetro 1, o if da linha 2 tem condição verdadeira. Então, ocorre a chamada
a rec(0). Mas rec(0) não é definido e ocorrerá a chamada a rec(-1). E assim
sucessivamente.

MÓDULO 3

Identificar o uso correto de recursos de bibliotecas em Python


Fonte: dTosh | Shutterstock

Python oferece, em seu núcleo, algumas funções que já utilizamos,


como print() e input(), além de classes como int, float e str. Logicamente, o
núcleo da linguagem Python disponibiliza muitas outras funções (ou métodos) e
classes além das citadas. Mas, ainda assim, ele é pequeno, com objetivo de
simplificar o uso e ganhar eficiência. Para aumentar a disponibilidade de
funções, métodos e classes, o desenvolvedor pode usar a biblioteca padrão
Python. Neste módulo, apresentaremos alguns dos principais recursos dessa
biblioteca e a forma de utilizá-los.

BIBLIOTECA PADRÃO PYTHON


A biblioteca padrão Python consiste em milhares de funções, métodos e
classes relacionados a determinada finalidade e organizados em componentes
chamados módulos. São mais de 200 módulos que dão suporte, entre outras
coisas, a:

Operações matemáticas.

Interface gráfica com o usuário (GUI).

Funções matemáticas e geração de números pseudoaleatórios.

ATENÇÃO
É importante lembrar dos conceitos de classes e objetos, pois eles são os
principais conceitos do paradigma de programação orientada a objeto. As
classes são fábricas, que podem gerar instâncias chamadas objetos. Uma
classe Pessoa, por exemplo, pode ter como atributos nome e CPF. Ao gerar
uma instância de Pessoa, com nome João da Silva e CPF 000.000.000-00,
temos um objeto.
 SAIBA MAIS
Para melhor compreensão dos conceitos de classe e objeto, pesquise sobre
paradigma orientado a objeto.

COMO USAR UMA FUNÇÃO DE


MÓDULO IMPORTADO
Para usar as funções e os métodos de um módulo, são necessários dois
passos:

Fazer a importação do módulo desejado com a instrução:

import nome_modulo

Chamar a função desejada, precedida do nome do módulo, com a instrução:

nome_modulo.nome_funcao(paramêtros)
Como exemplo, vamos importar o módulo math (dedicado a operações
matemáticas) e calcular a raiz quadrada de 5, por meio da função sqrt().
Observe a Figura 30:
>>> import math

>>> math.sqrt(5)

2.23606797749979

Figura 30 - Exemplo de uso do módulo math - Fonte: O autor (2020)

A partir desse ponto, serão apresentados os principais aspectos dos seguintes


módulos:

MATH
usado para operações matemáticas.

RANDOM
usado para gerar números pseudoaleatórios.

SMTPLIB
usado para permitir envio de e-mails.

TIME
usado para implementar contadores temporais.

TKINTER
usado para desenvolver interfaces gráficas.

MÓDULO MATH
Esse módulo provê acesso a funções matemáticas de argumentos reais.
As funções não podem ser usadas com números complexos.
O módulo math tem as funções listadas na Tabela 7, entre outras:

Função

sqrt(x) Raiz quadrada de x

ceil(x) Menor inteiro maior ou igual a x

floor(x) Maior inteiro menor ou igual a x

cos(x) Cosseno de x

sin(x) Seno de x
log(x, b) Logaritmo de x na base b

pi Valor de Pi (3.141592...)

e Valor de e (2.718281...)

 Atenção! Para visualização completa da tabela utilize a rolagem horizontal

Tabela 7 - Principais funções do módulo math - Fonte: O autor (2020)

 SAIBA MAIS
Para mais informações sobre o módulo math, visite a biblioteca Python.

MÓDULO RANDOM
Esse módulo implementa geradores de números pseudoaleatórios para
várias distribuições.
NÚMEROS INTEIROS
SEQUÊNCIAS

NÚMEROS INTEIROS
Para inteiros, existe:

 Uma seleção uniforme a partir de um intervalo.

SEQUÊNCIAS
Para sequências, existem:
 Uma seleção uniforme de um elemento aleatório;

 Uma função para gerar uma permutação aleatória das posições na lista;

 Uma função para escolher aleatoriamente sem substituição.

DISTRIBUIÇÕES DE VALORES REAIS


A Tabela 8 mostra algumas das principais funções disponíveis para
distribuições de valores reais no módulo random.

Função

random() Número de ponto flutuante no intervalo [0

uniform(a, b) Número de ponto flutuante N tal que a ≤

gauss(mu, sigma) Distribuição gaussiana. mu é a média e 

normalvariate(mu, sigma) Distribuição normal. mu é a média e sigm

 Atenção! Para visualização completa da tabela utilize a rolagem horizontal

Tabela 8 - Principais distribuições de valores reais - Fonte: O autor (2020)

FUNÇÕES PARA NÚMEROS INTEIROS


A Tabela 9 mostra algumas das principais funções disponíveis para inteiros no
módulo random.

Função

randrange(stop) Um elemento selecionado aleatório de range(start, s

randrange(start, stop [,step])


randint(a, b) Número inteiro N tal que a ≤ N ≤ b

 Atenção! Para visualização completa da tabela utilize a rolagem horizontal

Tabela 9 - Principais funções do módulo random para inteiros - Fonte: O autor (2020)

FUNÇÕES PARA SEQUÊNCIAS


A Tabela 10 mostra algumas das principais funções disponíveis para
sequências no módulo random.

Função

choice(seq) Elemento aleatório de uma sequência não vazia seq.

shuffle(x[, random]) Embaralha a sequência x no lugar.

sample(pop, k) Uma sequência de tamanho k de elementos escolhidos da população p

 Atenção! Para visualização completa da tabela utilize a rolagem horizontal

Tabela 10 - Principais funções do módulo random para sequências - Fonte: O autor

(2020)

 SAIBA MAIS
Para mais informações sobre o módulo random, visite a biblioteca Python.

MÓDULO SMTPLIB
Esse módulo define um objeto de sessão do cliente SMTP que pode ser
usado para enviar e-mail para qualquer máquina da internet com um
serviço de processamento SMTP ou ESMTP. O exemplo a seguir vai permitir
que você envie um e-mail a partir do servidor SMTP do Gmail.
Como a Google não permite, por padrão, realizar o login com a utilização
do smtplib por considerar esse tipo de conexão mais arriscada, será
necessário alterar uma configuração de segurança. Para resolver isso, siga as
instruções a seguir:

Acesse sua conta no Google.

Depois Segurança.
Acesso a app menos seguro.

Mude para "ativada" a opção de "Permitir aplicativos menos seguros".

ACESSO A APP MENOS SEGURO


Atenção!
Em algumas contas, os nomes estarão escritos no idioma inglês (Allow less
secure apps).

Para fazer seu primeiro envio, crie um programa novo no seu projeto. A Figura
31 mostra as importações necessárias para o envio:

 1 #import dos pacotes necessários

 2 from email.mime.multipart import MIMEMultipart

 3 from email.mime.text import MIMEText

 4 import smtplib

 5

Figura 31 - Envio de e-mail com módulo smtplib 1 - Fonte: O autor (2020)

A Figura 32 mostra a criação da mensagem, com o corpo e seus parâmetros.

 6 #criação de um objeto de mensagem

 7 msg = MIMEMultipart()

 8 texto = "Estou enviando um email com Python"


 9

10 #parâmetros

11 senha = "SUA SENHA"

12 msg['From'] = "SEU E-MAIL"

13 msg['To'] = "E-MAIL DESTINO"

14 msg['Subject'] = "ASSUNTO"

15

16 #criação do corpo da mensagem

17 msg.attach(MIMEText(texto, 'plain'))

18

Figura 32 - Envio de e-mail com módulo smtplib 2 - Fonte: O autor (2020)

 A linha 7 mostra a criação de um objeto de mensagem.

 A linha 8 mostra o corpo da mensagem em uma string.

 As linhas de 11 a 14 devem ser preenchidas com os valores adequados

para que seu programa seja executado com sucesso.

 A linha 17 anexa o corpo da mensagem (que estava em uma string) ao

objeto msg.

A Figura 33 mostra os passos necessários para o envio em si.

19 #criação do servidor

20 server = smtplib.SMTP('smtp.gmail.com: 587')

21 server.starttls()

22

23 #Login na conta para envio

24 server.login(msg['From'], senha)

25

26 #envio da mensagem

27 server.sendmail(msg['From'], msg['To'], msg.as_string())

28

29 #encerramento do servidor
30 server.quit()

31

32 print('Mensagem enviada com sucesso')

33

Figura 33 - Envio de e-mail com módulo smtplib 3 - Fonte: O autor (2020)

 As linhas 20 e 21 mostram a criação do servidor e a sua conexão no modo

TLS.

 A linha 24 mostra o login na conta de origem do e-mail.

 A linha 27 representa o envio propriamente dito.

 A linha 30 mostra o encerramento do servidor.


 SAIBA MAIS
Para mais informações sobre o módulo smtplib, visite a biblioteca Python.

MÓDULO TIME
Esse módulo provê diversas funções relacionadas a tempo. Também
pode ser útil conhecer os módulos datetime e calendar. A Tabela 11
mostra algumas das principais funções disponíveis no módulo time.

Função

time() Número de segundos passados desde o início da contagem (epoch).

ctime(segundos) Uma string representando o horário local, calculado a partir do núme

gmtime(segundos) Converte o número de segundos em um objeto struct_time descrito

localtime(segundos) Semelhante à gmtime(), mas converte para o horário local.


sleep(segundos) A função suspende a execução por determinado número de segundo

 Atenção! Para visualização completa da tabela utilize a rolagem horizontal

Tabela 11 - Principais funções do módulo time - Fonte: O autor (2020)

A Figura 34 mostra um exemplo de chamada das funções time() e ctime().


>>> x = time.time()

>>> print(f'Local time: {time.ctime(x)}')

Local time: Tue Jun 30 23:38:55 2020

Figura 34 - Exemplo de uso das funções time() e ctime() - Fonte: O autor (2020)

A variável x recebe o número de segundos desde 00:00:00 de 01/01/1970 pela


função time(). Ao executar ctime(x), o número de segundos armazenado
em x é convertido em uma string, com o horário local.
A classe time.struct_time gera objetos sequenciais com valor de tempo
retornado pelas funções gmtime() e localtime(). São objetos com interface
de tupla nomeada: os valores podem ser acessados pelo índice e pelo nome
do atributo. Existem os seguintes valores que estão apresentados na Tabela
12:

TUPLA
Tupla é uma sequência finita de objetos. Uma tupla é similar à estrutura de
dados lista, porém, a principal diferença é que uma tupla, após definida, não
permite a adição ou remoção de elementos.

Índice Atributo

0 tm_year Por exemplo, 2020


1 tm_mon range [1, 12]

2 tm_mday range [1, 31]

3 tm_hour range [0, 23]

4 tm_min range [0, 59]

5 tm_sec range [0, 61]

6 tm_wday range [0, 6], Domin

7 tm_yday range [1, 366]

8 tm_isdst 0, 1 ou -1

N/A tm_zone abreviação do nom

 Atenção! Para visualização completa da tabela utilize a rolagem horizontal

Tabela 12 - Atributos da classe struct_time - Fonte: O autor (2020)

 SAIBA MAIS
Para mais informações sobre o módulo time, visite a biblioteca Python.

MÓDULO TKINTER
O pacote tkinter é a interface Python padrão para o Tk GUI (interface gráfica
com o usuário) toolkit. Na maioria dos casos, basta importar o próprio tkinter,
mas diversos outros módulos estão disponíveis no pacote. A
biblioteca tkinter permite a criação de janelas com elementos gráficos, como
entrada de dados e botões, por exemplo.

O exemplo a seguir vai permitir que você crie a primeira janela com alguns
elementos. Para isso, crie um programa novo no seu projeto. A Figura 35
mostra a criação da sua primeira janela, ainda sem qualquer elemento gráfico.

1 from tkinter import *

3 janelaPrincipal = Tk()

4 janelaPrincipal.mainloop()

Figura 35 - Primeira janela com tkinter 1 - Fonte: O autor (2020)

 A linha 1 mostra a importação de todos os elementos disponíveis

em tkinter. O objeto janelaPrincipal é do tipo Tk. Um objeto Tk é um

elemento que representa a janela GUI. Para que essa janela apareça, é

necessário chamar o método mainloop();

 Para exibir textos, vamos usar o elemento Label. A Figura 36 mostra

as linhas 4 e 5, com a criação do elemento e o seu posicionamento. O

tamanho padrão da janela é 200 X 200 pixels, com o canto superior

esquerdo de coordenadas (0,0) e o canto inferior direito de coordenadas

(200,200).

1 from tkinter import *

3 janelaPrincipal = Tk()

4 texto = Label(master = janelaPrincipal, text = "Minha janela exibida")

5 texto.place(x = 50 y = 100)

6 janelaPrincipal.mainloop()

Figura 36 - Primeira janela com tkinter 2 - Fonte: O autor (2020)

Veja o resultado de sua primeira janela, apenas com o texto, na Figura 37.
Fonte:ShutterstockFigura 37 - Exibição da primeira janela com tkinter - Fonte: O autor

(2020)

Vamos agora incrementar um pouco essa janela. Para isso, vamos acrescentar
uma imagem e um botão. A imagem precisa estar na mesma pasta do seu
arquivo .py.
1 from tkinter import *

3 def funcClicar():

4 print("Botão pressionado")

6 janelaPrincipal = Tk()
7 texto = Label(master = janelaPrincipal, text = "Minha janela exibida")

8 texto.pack()

10 pic = PhotoImage(file="logoEstacio.gif")

11 logo = Label(master = janelaPrincipal, image = pic)

12 logo.pack()

13

14 botao = Button(master = janelaPrincipal, text = 'Clique', command = funcClicar)

15 botao.pack()

16

17 janelaPrincipal.mainloop()

18

Figura 38 - Segunda janela com tkinter - Fonte: O autor (2020)

 Na Figura 38, temos a inserção do elemento de imagem e o botão.

Nas linhas 10, 11 e 12, é feita a criação do objeto Label para conter a

imagem e seu posicionamento. Observe que passamos a utilizar o

método pack(), que coloca o elemento centralizado e posicionado o mais

perto possível do topo, depois dos elementos posicionados anteriormente.

 O elemento botão é criado na linha 14, com os atributos text e command,

que, respectivamente, são o texto exibido no corpo do botão e a função a

ser executada quando o botão for clicado.

 Para o funcionamento correto do botão, precisamos definir a

função funcClicar(), nas linhas 3 e 4. Essa função serve apenas para

imprimir na tela a string “Botão pressionado”.

Veja o resultado na Figura 39 e, depois de implementar sua própria janela,


clique no botão para ver o resultado no console, como na Figura 40.
Fonte:ShutterstockFigura 39 - Segunda janela com tkinter exibida - Fonte: O autor

(2020)

Botão pressionado

Figura 40 - Resultado do clique no botão da segunda janela - Fonte: O autor (2020)

 SAIBA MAIS
Para mais informações sobre o tkinter, visite a biblioteca Python.

USANDO PACOTES EXTERNOS


Além dos módulos fornecidos de forma integrada pela biblioteca padrão do
Python, a linguagem possui uma grande vantagem: sua característica open-
source permite que qualquer desenvolvedor, com o conhecimento adequado,
desenvolva sua própria biblioteca e os seus próprios módulos, que
chamaremos a partir de agora de pacotes.
DICA
Veremos como criar módulos mais adiante neste conteúdo.

Com um pacote pronto, o desenvolvedor pode disponibilizar esse material na


internet, de forma que qualquer pessoa possa aproveitar o código
implementado. Isso foi um dos fatores que fez com que o Python se tornasse
uma das linguagens mais utilizadas no mundo atualmente.

Como forma de facilitar a distribuição dos pacotes entre os usuários, existe um


grupo dentro da comunidade Python que mantém o chamado Python Package
Index, ou PyPI, que é um grande servidor no qual os desenvolvedores podem
hospedar os seus pacotes, contendo bibliotecas e/ou módulos para que sejam
baixados e instalados por outras pessoas.
É possível acessar o PyPI através do pip, um programa que pode ser instalado
juntamente com a distribuição do Python. Para isso, certifique-se de que a
caixa “pip” está marcada durante a instalação, conforme ilustrado a seguir.

Instalação do pip.
DICA
Para verificar se a sua instalação Python incluiu o pip, procure pela
pasta Scripts dentro do diretório de instalação que você escolheu para o
Python. Dentro dessa pasta, localize o arquivo pip.exe. Caso não o encontre,
pesquise sobre como instalar o pip. O mais recomendado é tentar reinstalar o
Python, lembrando de marcar a opção de incluir o pip durante o processo de
instalação.
Além do pip, é necessário termos o endereço para acessar o pip dentro da
variável de ambiente PATH. O processo de instalação do python também
permite incluir automaticamente o Python no seu PATH, porém, caso não
tenha feito isso, siga os passos abaixo:
1
Clique na tecla do Windows e escreva “Editar as variáveis de ambiente para a
sua conta”.

Na janela que abrir, procure pela variável Path, selecione-a e clique no botão


“Editar”.
2

3
Clique no botão “Novo” e digite o endereço da sua instalação do Python (por
exemplo, D:\Python).

Clique no botão “Novo” uma segunda vez e digite o endereço da


pasta Scripts dentro da sua instalação do Python (por exemplo, D:\Python\
Scripts).
4
5
Aperte Ok até fechar todas as janelas.
É importante que você se certifique de que a opção “Add Python to PATH” está
marcada durante a instalação, como ilustrado a seguir.

Adicionando o Python ao Path.

Com essas etapas concluídas, já conseguimos instalar nossos pacotes


externos!

ATENÇÃO
Quando estiver trabalhando com pacotes externos, é extremamente
recomendado o uso de ambientes virtuais (em inglês virtual environments ou
simplesmente virtualenvs). Esses ambientes isolam o projeto em que você está
trabalhando, e uma das vantagens disso é que você consegue saber
exatamente quais pacotes externos estão sendo usados no projeto.

É possível usar pacotes externos sem o uso de ambientes virtuais, porém isso
pode causar uma confusão caso você tenha vários projetos Python no seu
computador.
Pesquise mais sobre ambientes virtuais e configure um em cada projeto. Não é
muito difícil e vai te ajudar a deixar o seu código mais profissional!

Para instalar um pacote externo disponível no PyPI, basta abrir o seu terminal
(clique no botão do Windows e digite “cmd” ou “prompt de comando”), ative
o seu ambiente virtual (se você estiver usando um) e digite o seguinte
comando: d: \Projects\exemplo_pacotes>pip install <nome_do_pacote>

Instalando um pacote usando pip.

Substitua <nome_do_pacote> pelo pacote que você deseja usar. Temos


inúmeros pacotes prontos à nossa disposição. Cada pacote normalmente
possui um site que apresenta a sua documentação, de forma similar à
documentação oficial do Python.

Abaixo você encontra uma lista com alguns dos pacotes externos mais comuns
e utilizados no mercado:

Nome do módulo

numpy Cálculos, operações matemáticas e simulações

pandas Manipulação de dados

scikit-learn Modelos de aprendizado de máquina

matplotlib Visualização de dados


requests Biblioteca de comandos de comunicação pelo pr

flask Construção de aplicações web

 Atenção! Para visualizaçãocompleta da tabela utilize a rolagem horizontal

Pacotes externos mais comuns e utilizados no mercado.

DICA
Antes de começar o seu próprio módulo, é sempre recomendado pesquisar se
o que você quer fazer já existe em algum pacote popular. Se existir, procure
pela documentação e instale esse pacote.

O uso de módulos oriundos de pacotes externos é idêntico ao uso dos módulos


da biblioteca padrão, basta utilizar o import nome_do_modulo no seu código.

CRIAÇÃO DO PRÓPRIO MÓDULO


Os desenvolvedores podem criar seus próprios módulos de forma a reutilizar
as funções que já escreveram e organizar melhor seu trabalho. Para isso,
basta criar um arquivo .py e escrever nele suas funções. É importante
observar que o arquivo do módulo precisa estar na mesma pasta do
arquivo para onde ele será importado.

No vídeo a seguir, o professor nos apresenta exemplos práticos do uso das


bibliotecas de Python. Vamos assistir!
VERIFICANDO O APRENDIZADO
1. SABEMOS QUE É POSSÍVEL IMPORTAR MÓDULOS E
CHAMAR FUNÇÕES DESSES MÓDULOS EM PYTHON.
CONSIDERE O MÓDULO MATH, QUE OFERECE DIVERSAS
FUNÇÕES MATEMÁTICAS. UMA DESSAS FUNÇÕES É
A CEIL(X), QUE RETORNA O MENOR INTEIRO MAIOR OU
IGUAL A X. SUPONHA QUE UM ESTUDANTE QUEIRA USAR
UMA VARIÁVEL N, QUE RECEBE O VALOR 5.9, E EM
SEGUIDA IMPRIMIR NA TELA O MENOR INTEIRO MAIOR OU
IGUAL A ELA.
1import math

2n = 5.9

3print(ceil(n))

1import math

2n = 5.9

3math.ceil(n)

4print(n)

1import math

2n = 5.9

3print(ceil.math(n))

1import math

2n = 5.9

3print(math.ceil(n))
2. SOBRE A LINGUAGEM PYTHON E SUA BIBLIOTECA
PADRÃO, É CORRETO AFIRMAR QUE:

Só permite a utilização dos módulos contidos na biblioteca padrão Python.

Tem o módulo de interface gráfica tkinter, que não permite a criação de


janelas com botões.
Tem módulo de interface de e-mails smtplib, que não permite envio de e-mails
por servidores gratuitos.
Tem módulo de operações matemáticas math, que não permite operações com
números complexos.

GABARITO

1. Sabemos que é possível importar módulos e chamar funções desses


módulos em Python. Considere o módulo math, que oferece diversas
funções matemáticas. Uma dessas funções é a ceil(x), que retorna o
menor inteiro maior ou igual a x. Suponha que um estudante queira usar
uma variável n, que recebe o valor 5.9, e em seguida imprimir na tela o
menor inteiro maior ou igual a ela.
A alternativa "D " está correta.

A maneira correta de usar uma função de um módulo importado é: (i) importar


o módulo e (ii) chamar a função com a sintaxe nomeModulo.nomeFuncao().

2. Sobre a linguagem Python e sua biblioteca padrão, é correto afirmar


que:

A alternativa "D " está correta.

O módulo math não permite operações com números complexos.


MÓDULO 4

 Analisar as formas de tratamento de exceções e eventos em Python.

Fonte: dTosh | Shutterstock

Até agora, consideramos que nossos programas tiveram seu fluxo de execução
normal. Neste módulo, vamos analisar o que acontece quando o fluxo de
execução é interrompido por uma exceção, além de controlar esse fluxo
excepcional.

ERROS E EXCEÇÕES
Dois tipos básicos de erros podem acontecer em um programa em Python.
Os erros de sintaxe são aqueles que ocorrem devido ao formato incorreto de
uma instrução. Esses erros são descobertos pelo componente do interpretador
Python, chamado analisador ou parser. Veja exemplos na Figura 41 e na
Figura 42:
>>> print 'hello'

File "<input>", line 1

print 'hello'

SyntaxError: Missing parenthesesin call to 'print'. Did you mean print('hello')?

Figura 41 - Erro de sintaxe 1 - Fonte: O autor (2020)


>>> lista = [1 ; 2 ; 4]

File "<input>", line 1"

lista = [1 ; 2 ; 4]

SyntaxError: invalid sytax

Figura 42 - Erro de sintaxe 2 - Fonte: O autor (2020)

Além desses, existem os erros que ocorrem em tempo de execução do


programa, que não são devidos a uma instrução escrita errada, mas sim ao
fato de que o programa entrou em um estado indevido. Temos os exemplos:

A divisão por 0.

A tentativa de acessar um índice indevido em uma lista.

Um nome de variável não atribuído.

Um erro causado por tipos incorretos de operando.

Em cada caso, quando o programa atinge um estado inválido, dizemos que o


interpretador Python levanta uma exceção. Isso significa que é criado um
objeto que contém as informações relevantes sobre o erro. A Tabela 13 traz
alguns tipos comuns de exceção:

Exceção

KeyboardInterrupt Levantado quando o usuário pressiona CTRL + C, a combinação

OverflowError Levantado quando uma expressão de ponto flutuante é avaliada

ZeroDivisionError Levantado quando se tenta dividir por 0.

IOError Levantado quando uma operação de entrada/saída falha por um


IndexError Levantado quando um índice sequencial está fora do intervalo de

NameError Levantado quando se tenta avaliar um identificador (nome) não a

TypeError Levantado quando uma operação da função é aplicada a um obj

ValueError Levantado quando a operação ou função tem um argumento com

 Atenção! Para visualização completa da tabela utilize a rolagem horizontal

Tabela 13 - Tipos comuns de exceção - Extraído de Perkovic (2016)

Em Python, as exceções são objetos. A classe Exception é derivada


de BaseException, classe base de todas as classes de
exceção. BaseException fornece alguns serviços úteis para todas as classes
de exceção, mas normalmente não se torna uma subclasse diretamente.

CAPTURA E MANIPULAÇÃO DE
EXCEÇÕES
Para evitar que os programas sejam interrompidos quando uma exceção for
levantada, é possível planejar um comportamento alternativo. Assim, o
programa não será interrompido e a exceção poderá ser tratada. Chamamos
esse processo de captura da exceção.
Vamos considerar um exemplo de programa que solicita ao usuário, com a
função input(), um número inteiro. Embora essa função trate a entrada do
usuário como string, é possível utilizá-la em conjunto com a função eval() para
que os dados inseridos sejam avaliados como números. A Figura 43 mostra
uma implementação simples desse exemplo.
1 num = eval(input("Entre com um número inteiro: "))

2 print(num)

Figura 43 - Exemplo simples de input - Fonte: O autor (2020)

Mas o que aconteceria se o usuário digitasse uma palavra em vez de


números?

Veja a Figura 44.

Entre com um número inteiro: dez

Traceback (most recent call last):

File "C:/Users/Humberto/PycharmProjects/estacio_ead/excessoes.py", line 1, in <module>

num = eval(input("Entrecom um número inteiro: "))

File "<string>, line 1, in <module>

NameError: name 'dez'is not defined

Figura 44 - Exemplo de inserção de dados inválida sem tratamento - Fonte: O autor

(2020)

Veja que o programa foi encerrado com uma exceção sendo levantada. Uma
forma de fazer a captura e a manipulação de exceções é usar o par de
instruções try / except.
O bloco try é executado primeiro, no qual devem ser inseridas as instruções do
fluxo normal do programa.
O bloco except somente será executado se houver o levantamento de alguma
exceção.

Isso permite que o fluxo de execução continue de maneira alternativa. A Figura


45 mostra uma implementação possível desse exemplo:

1 try:

2 num = eval(input("Entre com um número inteiro: "))

3 print(num)
4 except:

5 print("Entre com o valor numérico e não letras")

Figura 45 - Exemplo de uso de try/except - Fonte: O autor (2020)

A execução pode ser conferida na Figura 46:

Entre com um número inteiro: dez

Entre com valor numérico e não letras

Figura 46 - Execução com uso de try/except - Fonte: O autor (2020)

O formato padrão de uso do par try/except é:


1 try:

2 Bloco 1

3 except:

4 Bloco 2

5 Instrução fora do try/except

O bloco 1 representa o fluxo normal do programa. Caso uma exceção seja


levantada, o bloco 2 será executado, permitindo o tratamento adequado dela.
Esse bloco 2 é chamado de manipulador de exceção.
ATENÇÃO
Em Python, o manipulador de exceção padrão é quem executa o trabalho de
captura da exceção caso não haja um tratamento explícito feito pelo
desenvolvedor. É esse manipulador padrão o responsável pela exibição das
mensagens de erro no console, como visto na Figura 44.

CAPTURA DE EXCEÇÕES DE
DETERMINADO TIPO
Python permite que o bloco relativo ao except só seja executado caso a
exceção levantada seja de determinado tipo. Para isso, o except precisa trazer
o tipo de exceção que se deseja capturar. A Figura 47 traz uma possível
variação do exemplo anterior, com a captura apenas das exceções do
tipo NameError.
1 try:

2 num = eval(input("Entre com um número inteiro: "))

3 print(num)

4 except NameError:

5 print("Entre com o valor numérico e não letras")

Figura 47 - Exemplo de captura de exceção de determinado tipo - Fonte: O autor

(2020)

CAPTURA DE EXCEÇÕES DE
MÚLTIPLOS TIPOS
Python permite que haja diversos tratamentos para diferentes tipos
possíveis de exceção. Isso pode ser feito com mais de uma
cláusula except vinculada à mesma cláusula try. A Figura 48 mostra um
exemplo de implementação da captura de exceções de múltiplos tipos.
1 try:

2 num = eval(input("Entre com um número inteiro: "))

3 print(num)

4 except ValueError:

5 print("Mensagem 1")

6 except IndexError:

7 print("Mensagem 2")

8 except:

9 print("Mensagem 3")

Figura 48 - Captura de múltiplos tipos de exceção - Fonte: O autor (2020)

 A instrução da linha 5 somente será executada se a exceção levantada no

bloco try for do tipo ValueError, e se, na instrução da linha 7, a exceção for

do tipo IndexError.

 Caso a exceção seja de outro tipo, a linha 9 será executada.


O TRATAMENTO COMPLETO DAS
EXCEÇÕES
A forma geral completa para lidar com as exceções em Python é:

try:

2 Bloco 1

3 except Exception1:

4 Bloco tratador para Exception1

5 except Exception2:

6 Bloco tratador para Exception1

7 ...

8 else:

9 Bloco 2 – executado caso nenhuma exceção seja levantada

10 finally:

11 Bloco 3 – executado independente do que ocorrer

12 Instrução fora do try/except

As cláusulas else e finally são opcionais, como foi possível perceber nos


exemplos iniciais.

TRATAMENTO DE EVENTOS
O tratamento de eventos é similar ao tratamento de exceções. Assim como
podemos tratar as exceções ocorridas em tempo de execução, podemos tratar
os eventos criados por ações externas, como interações de usuário realizadas
por meio de uma interface gráfica de usuário (GUI).
UM EVENTO É A NOTIFICAÇÃO DE QUE ALGUMA
COISA ACONTECEU, COMO UM CLIQUE DE MOUSE
SOBRE UM ELEMENTO BOTÃO. O TRATADOR DO
EVENTO É O SEGMENTO DE CÓDIGO QUE SERÁ
EXECUTADO EM RESPOSTA À OCORRÊNCIA DO
EVENTO.
No vídeo a seguir, o professor nos apresenta exemplos práticos do tratamento
das exceções. Vamos assistir!

VERIFICANDO O APRENDIZADO
1. CONSIDERE O SEGUINTE TRECHO DE UM PROGRAMA
ESCRITO EM PYTHON:

1 TRY:
2 NUM = EVAL(INPUT("ENTRE COM UM NÚMERO INTEIRO: "))
3 PRINT(NUM)
4 EXCEPT VALUEERROR:
5 PRINT("MENSAGEM 1")
6 EXCEPT INDEXERROR:
7 PRINT("MENSAGEM 2")
8 EXCEPT:
9 PRINT("MENSAGEM 3")
SUPONHA QUE DURANTE A EXECUÇÃO O USUÁRIO ENTRE
COM A PALAVRA NUMERO QUANDO SOLICITADO.
ASSINALE A OPÇÃO QUE MOSTRA O RESULTADO
IMEDIATO DESSA AÇÃO.

O programa deixará de ser executado.

Será impresso na tela Mensagem 1.


Será impresso na tela Mensagem 2.
Será impresso na tela Mensagem 3.
2. SOBRE O TRATAMENTO DE EXCEÇÕES EM PYTHON, É
INCORRETO AFIRMAR QUE:

É possível implementar tratamentos diferentes de acordo com a exceção


levantada.

Não é possível utilizar a cláusula finally.


Não é possível utilizar a cláusula catch.

É possível implementar um tratamento geral para todas as exceções


levantadas.

GABARITO

1. Considere o seguinte trecho de um programa escrito em Python:

1 try:

2 num = eval(input("Entre com um número inteiro: "))

3 print(num)

4 except ValueError:

5 print("Mensagem 1")

6 except IndexError:

7 print("Mensagem 2")

8 except:

9 print("Mensagem 3")

Suponha que durante a execução o usuário entre com a palavra numero quando

solicitado. Assinale a opção que mostra o resultado imediato dessa ação.


A alternativa "D " está correta.

Como o usuário inseriu uma palavra e não um número, a exceção não será do
tipo ValueError nem do tipo IndexError. Assim, a cláusula except a ser
executada é a da linha 8, imprimindo Mensagem 3.

2. Sobre o tratamento de exceções em Python, é incorreto afirmar que:

A alternativa "B " está correta.

A cláusula finally pode ser usada, embora não seja obrigatória.

CONCLUSÃO

CONSIDERAÇÕES FINAIS
Neste tema, você aprendeu a usar as estruturas de controle, sejam de decisão
ou de repetição, foi apresentado aos conceitos de subprogramas em Python,
implementou suas próprias funções, além de conhecer e utilizar as bibliotecas.
Por fim, analisou as formas de tratamento de exceções e eventos. Com esse
conteúdo, você com certeza terá condições de desenvolver aplicações muito
mais complexas e com muito mais recursos.
AVALIAÇÃO DO TEMA:

REFERÊNCIAS
PERKOVIC, L. Introdução à computação usando Python: um foco no
desenvolvimento de aplicações. Rio de Janeiro: LTC, 2016.
SEBESTA, R. W. Conceitos de linguagens de programação. 11. ed. São
Paulo: Bookman, 2018.

EXPLORE+
Para ter desafios mais complexos e exercícios para treinar, recomendamos
uma visita ao website Python Brasil.

Acesse o site das bibliotecas apresentadas e busque pela documentação para


que você possa conhecer todas as funcionalidades que estão disponíveis.

CONTEUDISTA
Humberto Henriques de Arruda
CURRÍCULO LATTES

DEFINIÇÃO
Introdução aos conceitos da orientação a objetos; Classes e Encapsulamento;
Herança e Polimorfismo; Construtores; Atributos e Métodos; Implementação de
Herança; Implementação de Polimorfismo; Classes Abstratas; Tratamento de
Exceções; Python e linguagens OO.
PROPÓSITO
Compreender o desenvolvimento de software orientado a objetos, utilizando
uma linguagem de programação como Python com grande aceitação no meio
comercial e acadêmico. Entender os conceitos e pilares da orientação a objetos
e saber contextualizar o Python entre as outras linguagens tradicionais
orientadas a objetos como Java e C++.

PREPARAÇÃO
Para este módulo, é necessário conhecimentos de programação em linguagem
Python, incluindo modularização e utilização de bibliotecas em Python. Antes
de iniciar o conteúdo deste tema é necessário que tenha o interpretador Python
na versão 3.7.7 e o ambiente de desenvolvimento PyCharm ou outro ambiente
que suporte o desenvolvimento na linguagem Python.

OBJETIVOS
MÓDULO 1
Definir os conceitos gerais da orientação a objetos

MÓDULO 2
Descrever os conceitos básicos da programação orientada a objetos na
linguagem Python

MÓDULO 3
Descrever os conceitos da orientação a objetos como Herança e Polimorfismo

MÓDULO 4
Comparar a implementação dos conceitos orientados a objetos aplicados a
Python com outras linguagens orientadas a objetos existentes no mercado
INTRODUÇÃO
O paradigma de programação orientado a objetos é largamente utilizado para o
desenvolvimento de software devido à sua implementação ser próxima dos
conceitos do mundo real. Essa proximidade facilita a manutenção dos
softwares orientados a objetos. A linguagem Python implementa os conceitos
do paradigma orientado a objetos e, devido à sua sintaxe simples e robusta,
torna-se uma ferramenta poderosa para a implementação de sistemas
orientados a objetos.

Na apostila, serão apresentados os conceitos da orientação a objetos, como


implementá-los em Python e uma comparação com as linguagens Java e C++ -
em relação às principais características da orientação a objetos.

MÓDULO 1

Definir os conceitos gerais da orientação a objetos

CONCEITOS DE POO -
PROGRAMAÇÃO ORIENTADA A
OBJETOS
A programação orientada a objetos foi considerada uma revolução na
programação, pois mudou completamente a estruturação dos programas de
computador. Essa mudança se estendeu, inclusive, para os modelos de análise
do mundo real e depois para a implementação dos respectivos modelos nas
linguagens de programação orientadas a objetos.

Conforme apresentado por Rumbaugh et al (1994):


“A TECNOLOGIA BASEADA EM OBJETOS É
MAIS DO QUE APENAS UMA FORMA DE
PROGRAMAR. ELA É MAIS IMPORTANTE
COMO UM MODO DE PENSAR EM UM
PROBLEMA DE FORMA ABSTRATA,
UTILIZANDO CONCEITOS DO MUNDO REAL E
NÃO IDEIAS COMPUTACIONAIS”.
Jaeger, 1995.

Muitas vezes, analisamos um problema do mudo real pensando no projeto,


que, por sua vez, é influenciado por ideias sobre codificação, que são
fortemente influenciadas pelas linguagens de programação disponíveis. A
abordagem baseada em objetos permite que os mesmos conceitos e a mesma
notação sejam usados durante todo o processo de desenvolvimento de
software, ou seja, não existem conceitos de análise de projetos diferentes dos
conceitos de implementação dos projetos. A abordagem procura refletir os
problemas do mundo real através de interação de objetos modelados
computacionalmente. Portanto, o desenvolvedor do software não necessita
realizar traduções para outra notação em cada etapa do desenvolvimento de
um projeto de software (COSTA, 2015).
Fonte: Freepik

O software é organizado como uma coleção de objetos separados que


incorporam, tanto a estrutura, quanto o comportamento dos dados. Contrasta
com a programação convencional, segundo a qual a estrutura e o
comportamento dos dados têm pouca vinculação entre si. Os modelos
baseados em objetos correspondem mais aproximadamente ao mundo real.
Em consequência, são mais adaptáveis às modificações e evoluções dos
sistemas.

PILARES DA ORIENTAÇÃO A
OBJETOS
OBJETOS
Um objeto é a representação computacional de um elemento ou processo do
mundo real. Cada objeto possui suas características (informações) e uma série
de operações (comportamento) que alteram as suas características (estado do
objeto). Todo o processamento das linguagens de programação orientadas a
objetos se baseia no armazenamento e na manipulação das informações
(estados). São exemplos de objetos do mundo real e computacional: Aluno,
Professor, Livro, Empréstimo e Locação. (Costa, 2015)

É importante, durante a etapa de levantamento dos objetos, analisar apenas os


objetos relevantes (abstrair) com as respectivas características mais
importantes para o problema a ser resolvido. Por exemplo, as características
de uma pessoa para um sistema acadêmico podem ser formação, nome do pai
e da mãe, enquanto as características de um indivíduo para o sistema de
controle de uma academia são altura e peso.

ATRIBUTOS
São propriedades do mundo real que descrevem um objeto. Cada objeto
possui suas respectivas propriedades do mundo real, os quais possuem
valores. A orientação a objetos define as propriedades como atributos. O
conjunto de valores dos atributos de um objeto definem o seu estado naquele
momento (RUMBAUGH, 1994).

Veja nas tabelas a seguir a diferença entre os atributos de duas mulheres:


Fonte: drobotdean / Freepik

Atributos V

Nome Maria

Idade 35
Peso 63kg

Altura 1,70m

 Atenção! Para visualização completa da tabela utilize a rolagem horizontal

Fonte: katemangostar / Freepik

Atributos V
Nome Joana

Idade 30

Peso 60kg

Altura 1,65m

 Atenção! Para visualização completa da tabela utilize a rolagem horizontal

OPERAÇÕES
Uma operação é uma função ou transformação que pode ser aplicada a objetos
ou dados pertencentes a um objeto. Importante dizer que todo objeto possui
um conjunto de operações, que podem ser chamadas por outros objetos de
modo a colaborarem entre si. Esse conjunto de operações é conhecido
como interface. A única forma de colaboração entre os objetos é por meio das
suas respectivas interfaces (FARINELLI, 2020).

Utilizando o exemplo acima, podemos alterar nome, idade e peso da pessoa


por meio de um conjunto de operações. Portanto, normalmente, essas
operações alteram o estado do objeto. Vamos ver a seguir outros exemplos de
operações:

EXEMPLO
Classe empresa = Contratar_Funcionario, Despedir_Fucionario;

Classe janela = Abrir, fechar, ocultar.


O desenvolvimento de um sistema orientado a objetos consiste em realizar um
mapeamento, conforme apresentado na imagem a seguir.

Fonte: AutorFigura 1 - Mapeamento de objetos do mundo real.

Basicamente, deve-se analisar o mundo real e identificar quais objetos devem


fazer parte da solução do problema. Para cada objeto identificado, levantam-se
os atributos que descrevem as propriedades dos objetos e as operações que
podem ser executadas sobre esses objetos.

CLASSES
A classe descreve as características e os comportamento de um conjunto de
objetos. De acordo com a estratégia de classificação, cada objeto pertence a
uma única classe e possuirá os atributos e as operações definidos na classe.
Durante a execução de um programa orientado a objetos, são instanciados os
objetos a partir da classe, portanto, um objeto é chamado de instância de
sua classe.

A classe é o bloco básico para a construção de programas OO – Orientados a


Objetos (COSTA, 2015).

ATENÇÃO
Importante ressaltar que cada nome de atributo é único dentro de uma classe,
no entanto, essa premissa não é verdadeira quando se consideram todas as
classes. Por exemplo, as classes Pessoa e Empresa podem ter um atributo
comum chamado de Endereço.

Com base na Tabela 1, vista anteriormente, deve ser definida uma classe
Pessoa com os atributos Nome, Idade, Peso e Altura. A partir da classe
Pessoa, pode-se instanciar uma quantidade ilimitada de objetos contendo os
mesmos atributos. Os objetos de uma classe sempre compartilham o conjunto
de operações que atuam sobre seus dados, alterando o estado do objeto.

Um programa orientado a objetos consiste basicamente em um conjunto de


objetos que colaboram entre si, por meio de uma troca de mensagens, para a
solução de um problema computacional. Cada troca de mensagens significa a
chamada de uma operação feita pelo objeto receptor da mensagem. (COSTA,
2015)

COMUNICAÇÃO ENTRE OBJETOS


DIFERENTES

Fonte: AutorFigura 2 – Colaboração motorista e carro.

De acordo com a Figura 2, vista anteriormente, um objeto motorista 1,


instanciado a partir da classe Motorista, envia a mensagem “Freia” para um
objeto carro 1, instanciado a partir da classe Carro. O objeto carro 1, ao
receber a mensagem, executa uma operação para acionar os freios do
automóvel. Essa operação também diminuirá o valor do atributo velocidade do
objeto carro 1.

ENCAPSULAMENTO
O conceito de encapsulamento consiste na separação dos aspectos externos
(operações) de um objeto acessíveis a outros objetos, além de seus detalhes
internos de implementação, que ficam ocultos dos demais objetos
(RUMBAUGH, 1994). Algumas vezes, é conhecido como o princípio do
ocultamento de informação, pois permite que uma classe encapsule atributos e
comportamentos, ocultando os detalhes da implementação. Partindo desse
princípio, a interface de comunicação de um objeto deve ser definida de modo
a revelar o menos possível sobre o seu funcionamento interno.

EXEMPLO
Foi desenvolvido um objeto ApresentaçãoMapa, pertencente a um aplicativo de
entrega móvel, que possui a responsabilidade de apresentar um mapa com o
menor caminho entre dois pontos. Porém, o objeto não “sabe” como calcular a
distância entre os dois pontos.

Para resolver esse problema, ele precisa colaborar com um objeto Mapa que
“sabe” calcular e, portanto, possui essa responsabilidade. O objeto Mapa
implementa essa responsabilidade por meio da operação Calcula Melhor
Caminho, cujo resultado é a menor rota entre duas coordenadas geográficas.

Utilizando o encapsulamento, o objeto Mapa calcula e retorna o melhor


caminho para o objeto ApresentaçãoMapa de maneira transparente,
escondendo a complexidade da execução dessa tarefa.

Fonte: AutorFigura 3 – Encapsulamento da Classe Mapa.

Uma característica importante do encapsulamento é que pode surgir um modo


diferente de se calcular o melhor caminho entre dois pontos. Por conta disso, o
objeto Mapa deverá mudar o seu comportamento interno para implementar
esse novo cálculo. Porém, essa mudança não afetará o objeto
ApresentaçãoMapa, pois a implementação foi realizada isoladamente
(encapsulamento) no objeto Mapa, sem impacto para outros objetos no
sistema.

RESUMINDO
Os objetos clientes têm conhecimento apenas das operações que podem ser
requisitadas e precisam estar cientes apenas do que as operações realizam, e
não de como elas estão implementadas.

HERANÇA
Na orientação a objetos, a herança é um mecanismo por meio do qual classes
compartilham atributos e comportamentos, formando uma hierarquia. Uma
classe herdeira recebe as características de outra classe para reimplementá-
las ou especializar de uma maneira diferente da classe pai. A herança permite
capturar similaridades entre classes, dispondo-as em hierarquias. As
similaridades incluem atributos e operações sobre as classes (FARINELLI,
2020).

Essa estrutura reflete um mapeamento entre classes, e não entre objetos,


conforme esquema a seguir:

Fonte: AutorFigura 4 – Exemplo de herança.

No esquema anterior, as classes Carro, Moto, Caminhão e Ônibus herdam


características em comum da classe Veículo, como os atributos chassis, ano,
cor e modelo.

Uma classe pode ser definida genericamente como uma superclasse e, depois,
especializada em classes mais específicas (subclasses). A herança permite a
reutilização de código em larga escala, pois possibilita que se herde todo o
código já implementado na classe pai e se adicione apenas o código específico
para as funcionalidades novas implementadas pela classe filha.

A evolução dos sistemas orientados a objetos também é facilitada, pois, caso


surja uma classe nova com atributos e/ou operações comuns a outra, basta
inseri-la na hierarquia, acelerando a implementação.

Veja a seguir os tipos de herança:


HERANÇA SIMPLES

A herança é considerada simples quando uma classe herda as características


existentes apenas de uma superclasse.

Na figura a seguir, temos uma superclasse Pessoa que possui os atributos


CPF, RG, Nome e Endereço. Em seguida, a classe Professor precisa herdar os
atributos da superclasse Pessoa, além de adicionar atributos específicos do
contexto da classe Professor, como titularidade e salário.

Fonte: AutorFigura 5 – Exemplo de herança Pessoa -> Professor.

Considerando um sistema acadêmico, a classe Aluno também se encaixaria na


hierarquia acima, tornando-se uma subclasse de Pessoa. Porém, precisaria de
outros atributos associados a seu contexto, como curso e Anoprevformatura.
Fonte: AutorFigura 6 – Exemplo de herança Pessoa -> Professor e Pessoa ->
Aluno.

HERANÇA MÚLTIPLA

A herança é considerada múltipla quando uma classe herda características de


duas ou mais superclasses. Por exemplo, no caso do sistema acadêmico, o
docente também pode desejar realizar um outro curso de graduação na mesma
instituição em que trabalha. Portanto, ele possuirá os atributos da classe
Professor e os da classe Aluno. Além disso, haverá também um atributo
DescontoProfessor, o qual apenas quando houver a associação professor e
aluno com a universidade.

Para adaptar essa situação no mundo real, deve ser criada uma modelagem de
classes. Uma nova subclasse ProfessorAluno precisa ser adicionada, herdando
atributos e operações das classes Professor e Aluno. Isso configura uma
herança múltipla. Essa nova subclasse deverá ter o atributo
DescontoProfessor, que faz sentido apenas para essa classe.
Fonte: AutorFigura 7 – Exemplo de herança Pessoa -> Professor e Pessoa ->
Aluno e Professor/Aluno ->ProfessorAluno.

POLIMORFISMO
O Polimorfismo é a capacidade de um mesmo comportamento diferente em
classes diferentes. Uma mesma mensagem será executada de maneira
diversa, dependendo do objeto receptor. O polimorfismo acontece quando
reimplementamos um método nas subclasses de uma herança (FARINELLI,
2020).

Fonte: AutorFigura 8 – mover() – método polimórfico.

Como exemplificado na figura 1.8, o comportamento mover() em um objeto


instanciado pela classe Aereo será diferente do mover() em um objeto da
classe Terrestre. Um objeto poderá enviar uma mensagem para se mover e o
objeto receptor decidirá como isso será feito.
CONCEITOS GERAIS DE
ORIENTAÇÃO OBJETO
Agora o Prof Marcelo Costa irá apresentar alguns exemplos dos conceitos de
orientação objeto:

VERIFICANDO O APRENDIZADO
1. NA PROGRAMAÇÃO ORIENTADA A OBJETOS, TEMOS
CONCEITOS COMO HERANÇA E POLIMORFISMO. SOBRE
ESSES CONCEITOS ANALISE AS ASSERTIVAS E ASSINALE
A ALTERNATIVA QUE APONTA A(S) CORRETA(S).
I. PARA EVITAR CÓDIGO REDUNDANTE, O PARADIGMA DE
ORIENTAÇÃO A OBJETOS OFERECE UMA ESTRUTURA
HIERÁRQUICA E MODULAR PARA REUTILIZAÇÃO DE
CÓDIGO ATRAVÉS DE UMA TÉCNICA CONHECIDA COMO
HERANÇA.
II. HERANÇA PERMITE PROJETAR CLASSES GENÉRICAS
QUE PODEM SER ESPECIALIZADAS EM CLASSES MAIS
PARTICULARES, ONDE AS CLASSES ESPECIALIZADAS
REUTILIZAM O CÓDIGO DAS MAIS GENÉRICAS.
III. LITERALMENTE, “POLIMORFISMO” SIGNIFICA “MUITAS
FORMAS”. NO CONTEXTO E PROJETO ORIENTADO A
OBJETOS, ENTRETANTO, REFERE-SE À HABILIDADE DE
UMA VARIÁVEL DE OBJETO DE ASSUMIR FORMAS
DIFERENTES.
IV. POLIMORFISMO PERMITE QUE OS ATRIBUTOS DE UMA
CLASSE NÃO TENHAM ACESSO DIRETAMENTE.
Apenas I.

Apenas I e III.

Apenas I, II e III.

Apenas II, III e IV.

2. OS BANCOS SÃO INSTITUIÇÕES QUE INVESTEM


FORTEMENTE NA ÁREA DE TECNOLOGIA DA
INFORMAÇÃO, INCLUSIVE COM A CONTRATAÇÃO DE
MILHARES DE PROFISSIONAIS E A CONSTRUÇÃO DE
GRANDES AMBIENTES DE DATACENTER. POR ISSO, É UM
DOMÍNIO DE CONHECIMENTO BASTANTE IMPORTANTE E
QUE DEVE SER UTILIZADO COMO EXEMPLO DURANTE UM
CURSO DE GRADUAÇÃO. SABENDO DISSO, ANALISE A
SEGUINTE SITUAÇÃO EM UM SISTEMA BANCÁRIO: A
CONTABANCARIA(CB) ESPECIALIZA AS CLASSES
ITEMSUPORTADO (IS) E ITEMSUJEITOAJUROS (ISJ) E
GENERALIZA AS CLASSES CONTACORRENTE (CC) E
POUPANÇA (PP). NESSE SENTIDO, É CORRETO AFIRMAR
QUE OCORRE (0,5)
Relação de dependência entre IS e ISJ.

Relação de dependência entre CC e PP.

Herança múltipla de CB em relação a CC e PP.

Herança múltipla de CB em relação a IS e ISJ.

GABARITO

1. Na programação orientada a objetos, temos conceitos como Herança e


Polimorfismo. Sobre esses conceitos analise as assertivas e assinale a
alternativa que aponta a(s) correta(s).
I. Para evitar código redundante, o paradigma de orientação a objetos
oferece uma estrutura hierárquica e modular para reutilização de código
através de uma técnica conhecida como herança.
II. Herança permite projetar classes genéricas que podem ser
especializadas em classes mais particulares, onde as classes
especializadas reutilizam o código das mais genéricas.
III. Literalmente, “polimorfismo” significa “muitas formas”. No contexto e
projeto orientado a objetos, entretanto, refere-se à habilidade de uma
variável de objeto de assumir formas diferentes.
IV. Polimorfismo permite que os atributos de uma classe não tenham
acesso diretamente.
A alternativa "C " está correta.

A questão aborda 3 conceitos importantes da orientação a objetos: Herança,


Polimorfismo e Encapsulamento. O item IV acima está errado devido a troca
com o conceito de encapsulamento visto na seção “Encapsulamento”.

2. Os bancos são instituições que investem fortemente na área de


Tecnologia da Informação, inclusive com a contratação de milhares de
profissionais e a construção de grandes ambientes de datacenter. Por
isso, é um domínio de conhecimento bastante importante e que deve ser
utilizado como exemplo durante um curso de graduação. Sabendo disso,
analise a seguinte situação em um sistema bancário: A
ContaBancaria(CB) especializa as classes ItemSuportado (IS) e
ItemSujeitoAJuros (ISJ) e generaliza as classes ContaCorrente (CC) e
Poupança (PP). Nesse sentido, é correto afirmar que ocorre (0,5)

A alternativa "D " está correta.

A questão aborda uma implementação prática de herança múltipla, onde a


Classe ContaBancaria recebe herança de ItemSuportado e ItemSujeitoAJuros.
MÓDULO 2

Descrever os conceitos básicos da programação orientada a objetos na


linguagem Python

CLASSES E OBJETOS EM PYTHON


Uma classe é uma declaração de tipo que encapsula constantes, variáveis e
métodos que realizam manipulação dos valores dessas variáveis. Cada classe
deve ser única em um sistema orientado a objetos.

DEFINIÇÃO DE CLASSE
Como boa prática, cada classe deve fazer parte de um único arquivo.py para
ajudar na estruturação do sistema orientado a objetos em Python. Outra boa
prática consiste no nome da classe semelhante ao do arquivo. Por exemplo,
definir no ambiente de desenvolvimento Python a classe Conta. O nome final
do arquivo deve ser Conta.py.

Deve-se ressaltar que todos esses exemplos podem ser executados no


terminal do Python.

class Conta:

pass

Uma classe é definida utilizando a instrução class e : para indicar o início do


bloco de declaração da classe. A palavra reservada pass indica que a classe
será definida posteriormente, servindo apenas para permitir que o interpretador
execute a classe até o final sem erros.

RECOMENDAÇÃO
É recomendável que você reproduza e execute todos os exemplos que serão
apresentados a seguir.
CONSTRUTORES E SELF

A classe conta foi criada, porém não lhe foram definidos atributos e
instanciados objetos, característica básica dos programas orientados a objetos.
Nas linguagens orientadas a objetos, para se instanciar objetos, devemos criar
os construtores da classe.

Em Python, a palavra reservada __init__() serve para inicialização de classes,


como abaixo:
class Conta:

def__init__(self, numero, cpf, nomeTitular, saldo):

self.numero = numero

self.cpf = cpf

self.nomeTitular = nomeTitular

self.saldo = saldo

Diferentemente de outras linguagens de programação orientadas a objetos, o


Pyhton constrói os objetos em duas etapas. A primeira etapa é utilizada com a
palavra reservada __new__, que, em seguida, executa o método __init__.
O __new__ cria a instância e é utilizado para alterar as classes dinamicamente
para casos de sistemas que envolvam metaclasses e frameworks.
Após __new__ ser executado, este método chama o __init__ para inicialização
da classe como seus valores iniciais (MENEZES, 2019).
Para efeitos de comparação com outras linguagens de programação, e por
questões de simplificação, consideraremos o __init__ como o construtor da
classe. Portanto, toda vez que instanciarmos objetos da classe conta, será
chamado o método __init__.
Analisando o nosso exemplo anterior, vimos a utilização da palavra self como
parâmetro no construtor. Como o objeto já foi instanciado implicitamente
pelo __new__, o método __init__ recebe uma referência do objeto instanciado
como self.
Analisando o restante do construtor da Figura 9, o código possui diversos
comandos self, o qual indica referência ao próprio objeto. Por exemplo, o
comando self.numero indica que o número é um atributo do objeto, ao qual é
atribuído um valor. O restante dos comandos self indicam que foram criados os
atributos cpf, nomeTitular e saldo referentes a classe Conta.
Vamos instanciar o nosso objeto com o método __init__:
>>>from Conta import Conta
>>>c1 = Conta(1,1,"Joao",1000)

Importante ressaltar que, em Python, não é obrigatório ter um método


construtor na classe, apenas se for necessária alguma ação na construção do
objeto, como inicialização e/ou atribuição de valores. Segue um exemplo de
uma classe sem um método construtor:

class A():

def f():

print ‘foo’

MÉTODOS

Toda classe deve possuir um conjunto de métodos para manipular os atributos


e, por consequência, o estado do objeto. Por exemplo, precisamos depositar
dinheiro na conta para aumentar o valor da conta corrente:

def __depositar__(self,valor)
     self.saldo += valor

No código acima, foi definido um método __depositar__ que recebe a própria


instância do objeto através do self e de um parâmetro valor. O número passado
por meio do parâmetro será adicionado ao saldo da conta do cliente. Vamos
supor que o estado anterior do objeto representasse o saldo com o valor zero
da conta. Após a chamada desse método passando como parâmetro o valor
300, através da referência self, o estado da conta foi alterado com o novo saldo
de 300 reais.
Segue o novo código:

class Conta:

def__init__(self, numero, cpf, nomeTitular, saldo):

self.numero = numero

self.cpf = cpf

self.nomeTitular = nomeTitular

self.saldo = saldo

def depositar(self, valor):

self.saldo += valor

def sacar(self, valor):

self.saldo -= valor

No exemplo anterior, adicionamos mais um método sacar(self, valor), onde


subtraímos o valor, passado como parâmetro, do saldo do cliente. Pode ser
adicionado um método extrato para avaliar os valores atuais da conta corrente,
ou seja, o estado atual do objeto. Por exemplo, a conta tinha saldo de 300 reais
após o primeiro depósito. Após a chamada de sacar (100), o saldo da conta
será 200 reais.

>>>from Conta import Conta


>>>c1 = Conta(1,1,"Joao",0)
.....c1.depositar(300)
.....c1.sacar(100)
class Conta:

def__init__(self, numero, cpf, nomeTitular, saldo):

self.numero = numero

self.cpf = cpf

self.nomeTitular = nomeTitular

self.saldo = saldo

def depositar(self, valor):

self.saldo += valor
def sacar(self, valor):

self.saldo -= valor

def gerarextrato(self):

print(f"numero: {self.numero} \n cpf: {self.cpf}\nsaldo: {self.saldo")

Se o método gerarextrato() for executado, o valor impresso será:

....c1.geratextrato()
200
MÉTODOS COM RETORNO

Em Python, não é obrigatório um comando para indicar quando o método deve


ser finalizado. Porém, na orientação a objetos, como na programação
procedural, é bastante comum retornar um valor a partir da análise do estado
do objeto. Conforme exemplificado a seguir, não é permitido o saque de um
valor maior do que o saldo atual do cliente, portanto, retorna a resposta “False”
para o objeto que está executando o saque. O método deve ficar da seguinte
forma:

def sacar(self,valor):

if self.saldo < valor:

return False

else:

self.saldo -= valor

return True

....c1.sacar(100)
True

Agora, questione-se: ao executar o comando c1.sacar(300), qual será o


retorno?

REFERÊNCIAS ENTRE OBJETOS NA MEMÓRIA

Uma classe pode ter mais de uma ou várias instâncias de objetos na memória,
como exemplificado na imagem a seguir:
from Conta import Conta

conta1 = Conta(1, 123, ‘Joao’,0)

conta2 = Conta(3, 456, ‘Maria’,0)

O Resultado na memória após a execução é apresentado na Figura 15:

Fonte: AutorFigura 15 – Estado da memória conta1 e conta2.

Na memória, foram criados dois objetos diferentes referenciados pelas


variáveis conta1 e conta2 do tipo conta. Os operadores “==” e “!=” comparam
se as duas variáveis de referência apontam para o mesmo endereço de
memória (CAELUM, 2020).

>>>if (conta1 != conta2):


... print("Endereços diferentes de memória")

Pelo esquema da memória, apresentado na Figura 15, realmente conta1 e


conta2 apontam para endereços diferentes de memória.

O comando “=” realiza o trabalho de igualar a posição de duas referências na


memória.

Fazendo conta1 = conta2, podemos ver o resultado:

conta1 = conta2
if (conta1 == conta2):
... print("enderecos iguais de memoria")
Fonte: AutorFigura 16 – Estado da memória conta1 e conta2 no mesmo
endereço.

Se executarmos os comandos referenciando o CPF da conta, verificamos que


possuem os mesmos valores, conforme mostrado acima.

>>>conta1.cpf
456
>>> conta2.cpf
456

Esse exemplo pode ser estendido para realizar uma transferência de valores
de uma conta para outra. A segunda conta deve ser passada como parâmetro
do método para ser executada a transferência. O método deve ficar da
seguinte maneira:

class Conta:

def__init__(self, numero, cpf, nomeTitular, saldo):

self.numero = numero

self.cpf = cpf

self.nomeTitular = nomeTitular

self.saldo = saldo

def depositar(self, valor):

self.saldo += valor

def sacar(self,valor):

if self.saldo < valor:


return False

else

self.saldo -= valor

return True

def gerarextratp(self):

print(f"numero:{self.numero}\n cpf:{self.cpf}\nsaldo:{selfsaldo}")

def transfereValor(self,contaDestino,valor):

if self.saldo < valor:

return ("Não existe saldo suficiente")

else:

contaDestino.depositar(valor)

self.saldo -= valor

return("Transferencia Realizada")

>>>from Conta import Conta


... conta1 = Conta(1, 123,'Joao',0)
... conta2 = Conta(3, 456,'Maria',0)
... conta1.depositar(1000)
... conta1.transfereValor(conta2,500)
... print(conta1.saldo)
... print(conta2.saldo)
500
500

Em resumo, foi depositado 1000 na conta1 e realizada uma transferência de


valor de 500 para conta2. No final, o saldo ficou 500 para conta1 e 500 para
conta2.

Importante ressaltar que, no comando conta1.transfereValor(conta2,500), é


passada uma referência da conta2 para o objeto contaDestino por meio de um
operador “=”. O comando contaDestino = conta2 é executado internamente no
Python.
AGREGAÇÃO
Para atender novas necessidades do sistema de conta corrente do banco,
agora se faz necessário adicionar uma funcionalidade para gerenciamento de
conta conjunta, ou seja, uma conta corrente pode ter um conjunto de clientes
associados. Isto pode ser representado como uma agregação, conforme
apresentado no esquema a seguir. Uma observação: o losango na imagem tem
a semântica da agregação.

Fonte: AutorFigura 18 – Classe agrega 1 ou vários clientes

Para agregação, devemos criar dois arquivos contas.py e cliente.py:

class Conta:

def__init__(self,cpf,nome,endereco):

self.cpf = cpf

self.nome = nome

self.endereco = endereco

class Conta:

def__init__(self, clientes, numero, saldo):

self.clientes = clientes

self.numero = numero

self.saldo = saldo

def depositar(self, valor):

self.saldo += valor

def sacar(self,valor):

if self.saldo < valor:

return False

else:

self.saldo -= valor

return True
def transfereValor(self,contaDestino,valor):

if self.saldo < valor:

return ("Não existe saldo suficiente")

else:

contadestino.depositar(valor)

self.saldo -= valor

return("Transferencia Realizada")

def gerarsaldo(self):

print(f"numero:{self.numero\n saldo: {self.saldo}")

Um programa testecontas.py deve ser criado para o usarmos na instanciação


dos objetos das duas classes e gerarmos as transações realizadas nas contas
dos clientes.

from contas import Conta

from clientes import Cliente

cliente1 = Cliente(123, “Joao”, “Rua 1”)

cliente2 = Cliente(345, “Maria”,”Rua 2”)

cliente1 = Conta([cliente1,cliente2], 1,0) (1)

conta1.gerarsaldo()

conta1.depositar(1500)

conta1.sacar(500)

conta1.gerarsaldo()

ATENÇÃO
Em (1) foi instanciado um objeto conta1 com dois clientes agregados: cliente1 e
cliente2. Esses dois objetos são passados como parâmetros em (1).

Qual o resultado dessa execução? Qual valor final na conta?

Sugestão: altere o programa do código anterior para criar mais uma conta para
dois clientes diferentes. Como desafio, tente, através do objeto conta, imprimir
o nome e o endereço dos clientes associados às contas.
COMPOSIÇÃO
A classe conta ainda não está completa de acordo com as necessidades do
sistema de conta corrente do banco. Isso ocorre porque o banco precisa gerar
extratos contendo o histórico de todas as operações realizadas para conta
corrente. Para isso, o sistema deve ser atualizado para adicionar uma
composição de cada conta com o histórico de operações realizadas. O
diagrama a seguir representa a composição entre as classes Conta e Extrato.
Esta composição representa que uma conta pode ser composta por vários
extratos. Uma observação: o losango preenchido tem a semântica da
composição.

Fonte: AutorFigura 22 – Classe Conta composta de 1 ou mais extratos

A classe Extrato tem as responsabilidades de armazenar todas as transações


realizadas na conta e de conseguir imprimir um extrato com a lista dessas
transações.

class Extrato:

def__init_(self):

self.transacoes = []

def extrato(self, numeroconta):

print(f”Extrato : {numeroconta} \n”)

for p in self.transacoes:

print(f”{p[0]:15s} {p[1]:10.2f} {p[2]:10s} {p[3].strftime(‘%d/%b/%y)}”)

A classe conta possui todas as transações como sacar, depositar e


transferir_valor. Cada transação realizada deve adicionar uma linha ao extrato
da conta. Inclusive, a composição Conta->Extrato deve ser inicializada no
construtor da classe Conta, conforme exemplificado na Figura 23. No
construtor de Extrato, foi adicionado um atributo transações, o qual foi
inicializado para receber um array de valores – transações da conta.

A classe Conta alterada deve ficar da seguinte maneira:

ARRAY DE VALORES
Um array ou vetor é uma estrutura que permite que sejam armazenados um
conjunto de valores do mesmo tipo.

import datetime

from Extrato import Extrato

class Conta:

def__init__(self,clientes,numero,saldo):

self.clientes = clientes

self.numero = numero

self.saldo = saldo

self.sata abertura = datetime.satetime.today()

self.extrato = Extrato () (1)

def depositar(self, valor):

self.saldo += valor

self.extrato.trasacoes.append(["DEPOSITO", valor, "Data",datetime.datetime.today ()])(2)

def sacar(self, valor):

if self.saldo < valor:

return False

else:

self.saldo -= valor

self.extrato.transacoes.append(["SAQUE", valor, "Data", datetime.datetime.today()]) (3)

return True

def transfereValor(self, contadestino, valor):

if self.saldo < valor:


return "Não existe saldo suficiente"

else:

contadestino.depositar(valor)

self.saldo -= valor

self.extrato.transacoes.append(["TRANSFERENCIA", valor, "Data", datetime.datetime.today()])

(4)

return "Transferencia Realizada"

def gerarsaldo(self):

print(f"numero: {self.unmero}\n saldo:{self.saldo}")

Alterações da classe conta:

Adição da linha (1) – criação de um atributo extrato, fazendo referência a um


objeto Extrato

Adição das linhas (2), (3) e (4) – adição de linhas ao array de transações do
objeto Extrato através do atributo extrato.

Execução no terminal:

>>>from clientes import Cliente


... from ContasClientesExtrato import Conta
... cliente1 = Cliente("123","Joao","Rua X")
... cliente2 = Cliente ("456","Maria","Rua W")
... conta1 = Conta([cliente1,cliente2],1,2000)
... conta1.depositar(1000)
... conta1.sacar(1500)
conta1.extrato.extrato(conta1.numero)
Extrato : 1
DEPOSITO 1000.00 Data 14/Jun/2020
SAQUE 1500.00 Data 14/Jun/2020

DICA
Experimente adicionar mais uma conta e realize uma transferência de valores
entre ambas. Depois, crie uma classe Banco para armazenar todos os clientes
e todas as contas do banco.

ENCAPSULAMENTO
Conforme apresentado no módulo anterior, o encapsulamento é fundamental
para a manutenção da integridade dos objetos e proibir qualquer alteração
indevida nos valores dos atributos (estado) do objeto (CAELUM, 2020). Este
ponto foi fundamental para a popularização da orientação aos objetos: reunir
dados e funções em uma única entidade e proibir a alteração indevida dos
atributos.

EXEMPLO
No caso da classe conta, imagine que algum programa tente realizar a seguinte
alteração direta no valor do saldo:

conta1.saldo = -200

Esse comando viola a regra de negócio do método sacar(), que indica para não
haver saque maior do que o valor e deixar a conta no negativo (estado inválido
para o sistema).

def sacar(self, valor):

if self.saldo < valor:

return False

else:

self.saldo -= valor

self.extrato.transacoes.append(["SAQUE", valor, "Data", datetime.datetime.today()])

return True

Como proibir alterações indevidas dos atributos em Python?


ATRIBUTOS PÚBLICOS E PRIVADOS
Para seguir o encapsulamento e proibir alterações indevidas dos atributos,
devemos definir atributos privados para a classe. Por default, em Python, os
atributos são definidos como público, ou seja, podem ser acessados
diretamente sem respeitar o encapsulamento - acesso feito apenas através de
métodos do objeto.
Para tornar um atributo privado, devemos iniciá-lo com dois underscores (‘__’).
A classe conta possui todos os atributos privados:
>>>class Conta:

... def__init__(self,numero,saldo):

... self.numero = __numero

... self.saldo = __saldo:

Qual o retorno do interpretador ao se acessar um atributo privado para classe


Conta?

>>> conta = Conta(1,1000)


>>> conta.saldo
Traceback (most recent call last):
File "<input>", line 1, in <module>
AttributeError: 'Conta' object has no attribute 'saldo'

É importante ressaltar que, em Python, não existe realmente atributos privados.


O interpretador renomeia o atributo privado para
_nomedaClasse__nomedoatributo. Portanto, o atributo ainda pode ser
acessado. Embora funcione, é considerado uma prática que viola o princípio de
encapsulamento da orientação a objetos.

>>> conta._Conta__saldo
1000

Na prática, deve existir uma disciplina para não serem acessados diretamente
os atributos como __ ou _ definido nas classes.
DECORATOR @PROPERTY
Uma estratégia importante disponibilizada pelo Python são as properties.
Utilizando o decorator property nos métodos, mantém-se os atributos como
protegidos, e estes são acessados apenas através dos métodos “decorados”
com property (CAELUM, 2020).
No caso da classe conta, não se pode acessar o atributo saldo (privado) para
leitura. Com o código, ele será acessado pelo método decorator @property:
@property

def saldo(self):

return self._saldo

Os métodos decorados com a property @setter forçam que todas alterações de


valor dos atributos privados devem passar por esses métodos.

Notação:

@<nomedometodo>.setter

@saldo.setter

def saldo(self, saldo):

if (self.saldo < 0):

print(“saldo inválido”)

else:

self._saldo = saldo

Os properties ajudam a garantir o encapsulamento no Python. Uma boa prática


implementada em todas as linguagens orientadas a objetos é definir esses
métodos apenas se realmente houver regra de negócios diretamente associada
ao atributo. Caso não haja, deve-se deixar o acesso aos atributos conforme
definido na classe.

ATRIBUTOS DE CLASSE

Existem algumas situações que os sistemas precisam controlar valores


associados à classe, e não aos objetos (instâncias) das classes; por exemplo,
ao desenvolver um aplicativo de desenho, como o Paint, que precisa contar o
número de círculos criados na tela.

Inicialmente, a classe Circulo vai ser criada:

class Circulo():

def__init__(self,pontox,pontoy,raio):

self.pontox = pontox

self.pontoy = pontoy

self.raio = raio

No entanto, conforme mencionado, é necessário controlar a quantidade de


círculos criados.

class Circulo():

total_circulos = 0 (1)

def__init__(self,pontox, pontoy, raio):

self.pontox = pontox

self.pontoy = pontoy

self.raio = raio

self.total_circulos +=1 (2)

Em (1), indicamos para o interpretador que seja criada uma variável


total_circulos. Como a declaração está localizada antes do init, o interpretador
“entende” que se trata de uma variável de classe, ou seja, terá um valor único
para todos objetos da classe. Em (2), é atualizado o valor da variável de classe
a cada instanciação de um objeto da classe Circulo.

Como acessar os valores armazenados em uma variável de classes?

>> from Circulo import Circulo


>>>circ1 = Circulo(1,1,10)
>>>circ1.total_circulos
1
>>>circ2 = Circulo(2,2,20)
>>>circ2.total_circulos
2
>>>Circulo.total_circulos
2
Esse acesso direto ao valor da variável de classe não é desejado. Deve-se
colocar a variável com atributo privado com o underscore ‘_’. Como fica agora?
O resultado é apresentado a seguir.
class Circulo:

_total_circulos = 0

def__init__(self,pontox, pontoy, raio):

self.pontox = pontox

self.pontoy = pontoy

self.raio = raio

circulo._total_circulos += 1

Repetindo o mesmo código:


>>>from Circulo import Circulo
>>>circ1 = Circulo(1,1,10)
>>>circ1._total_circulos
1
>>>Circulo.total_circulos
Traceback (most recent call last):
File "<input>", line 1, in <module>
AttributeError: type object 'Circulo' has no attribute 'total_circulos'
MÉTODOS DE CLASSE
Os métodos de classe são a maneira indicada para se acessar os atributos de
classe. Eles têm acesso diretamente à área de memória que contém os
atributos de classe. O esquema é apresentado na imagem a seguir.

Fonte: O autorFigura 32 – Memória Estática

Para definir um método como estático, deve-se usar o decorator


@classmethod. Assim, segue a classe Circulo alterada:

class Circulo:

_total_circulos = 0

def__init__(self,pontox, pontoy, raio):

self.pontox = pontox

self.pontoy = pontoy

self.raio = raio

type(self)._total_circulos +=1

@classmethod

def get total_circulos(cls): (1)

return cls.total_circulos (2)

Em (1), é criado o parâmetro cls como referência para classe. Em (2), é


retornado o valor do atributo de classe _total_circulos.

MÉTODOS PÚBLICOS E PRIVADOS


As mesmas regras definidas para atributos são válidas para os métodos das
classes. Assim, o método pode ser declarado como privado, mas ainda pode
ser chamado diretamente, como se fosse um método público. Os
dois underscores antes do método indicam que ele é privado:
class Circulo:
def__init__(self,clientes,numero,saldo):

self.clientes = clientes

self.numero = numero

self.saldo = saldo

def __gerarsaldo(self):

print(f"numero: {self.numero}\n saldo:{self.saldo}")

No código acima, foi definido o método geralsaldo como privado. Portanto,


pode ser acessado apenas internamente pela classe Conta. Um dos principais
padrões da orientação a objetos consiste nos métodos públicos e nos atributos
privados. Desse modo, respeita-se o encapsulamento.

MÉTODOS ESTÁTICOS

São métodos que podem ser chamados sem ter uma referência para um objeto
da classe, ou seja, não existe obrigatoriedade da instanciação de um objeto da
classe. O método pode ser chamado diretamente:

import math

class Math:

@staticmethod

def sqrt(x):

return math.sqrt(x)

>>> Math.sqrt(20)
4.47213595499958

No caso acima, foi chamado o método sqrt da classe Math sem haver
instanciado um objet da classe Math. Os métodos estáticos não são uma boa
prática na programação orientada a objetos. Devem ser utilizados apenas em
casos especiais, como classes de log em sistemas.
ENTENDA MAIS SOBRE
AGREGAÇÃO, CLASSES E
MÉTODOS ESTÁTICOS
No vídeo a seguir, faremos uma breve contextualização do tema.

VERIFICANDO O APRENDIZADO
1. ANALISE O SEGUINTE CÓDIGO ESCRITO EM PYTHON,
QUE DEFINE A ESTRUTURA DA CLASSE CONTABANCARIA:
CLASS CONTABANCARIA:

NUM_CONTAS = 0

DEF__INIT__(SELF,CLIENTES,NUMERO,SALDO):

SELF.AGENCIA = AGENCIA

SELF.NUMERO = NUMERO

SELF.SALDO = SALDO

CONTABANCARIA.NUM_CONTAS += 1

DEF _DEL_(SELF):

CONTABANCARIA.NUM_CONTAS -= 1

DEF DEPOSITAR(SELF,VALOR):

SELF.SALDO = SELF.VALOR + VALOR

DEF SACAR(SELF, VALOR):

SELF.SALDO = SELF.VALOR - VALOR


DEF CONSULTARSALDO(SELF):

RETURN SELF.SALDO

SOBRE A CLASSE ACIMA E AS REGRAS DE


PROGRAMAÇÃO ORIENTADA A OBJETOS EM PYTHON, A
OPÇÃO INCORRETA:
A criação de objetos chama primeiro o método __new__() e, em seguida, o
__init__().

A palavra self deve ser fornecida como argumento em todos os métodos


públicos de instâncias.

A variável num_contas é encapsulada e individual para cada instância da


classe.

O método __del__ é privado.

2. QUAL A DIFERENÇA NA UTILIZAÇÃO DOS DECORATORS


@STATICMETHOD E @CLASSMETHOD:
O decorator @staticmethod definem métodos de classe que manipulam
atributos de classe.

O decorator @classmethod definem métodos estáticos que permite acesso a


métodos sem instanciação da classe.

O decorator @classmethod permite que que os atributos de classe sejam


alterados na área de memória.

os decorators @staticmethod e @classmethod podem ser usados de forma


intercambiáveis.

GABARITO

1. Analise o seguinte código escrito em Python, que define a estrutura da


classe ContaBancaria:

class ContaBancaria:

num_contas = 0
def__init__(self,clientes,numero,saldo):

self.agencia = agencia

self.numero = numero

self.saldo = saldo

ContaBancaria.num_contas += 1

def _del_(self):

ContaBancaria.num_contas -= 1

def depositar(self,valor):

self.saldo = self.valor + valor

def sacar(self, valor):

self.saldo = self.valor - valor

def consultarSaldo(Self):

return self.saldo

Sobre a classe acima e as regras de programação orientada a objetos em


Python, a opção INCORRETA:
A alternativa "B " está correta.

A instância do objeto (self) deve ser passada implicitamente em cada chamada


do método.

2. Qual a diferença na utilização dos decorators @staticmethod e


@classmethod:

A alternativa "C " está correta.

O decorator @classmethod fica armazenado na mesma área de memória dos


atributos de classe. Portanto, pode alterar os valores dos atributos de classe.
MÓDULO 3

Descrever os conceitos da orientação a objetos como Herança e Polimorfismo

HERANÇA E POLIMORFISMO
As linguagens orientadas a objeto oferecem recursos que permitem o
desenvolvimento de sistemas de uma forma mais ágil e eficiente. Esses
recursos são a herança, polimorfismo e o tratamento das exceções. A herança
permite uma redução da repetição de código, permitindo que uma classe filho
herde métodos e atributos da classe pai. O polimorfismo permite que, em
determinadas situações, os objetos possam ter comportamentos específicos.
Caso haja algum problema durante a execução do código, o tratamento de
exceções facilita a manipulação do erro.

HERANÇA
É um dos princípios mais importantes da programação orientada a objetos, pois
permite a reutilização de código com a possiblidade de extensão para se
ajustar às regras de negócio dos sistemas.

EXEMPLO
A área de produtos do banco define quais clientes podem ter acesso a um
produto chamado Conta especial, o qual busca atender quem possui conta na
instituição há mais de um ano.

Na visão de negócios, a conta especial possui a funcionalidade de permitir o


saque da conta corrente até um certo limite, determinado durante a criação da
conta. Nesse ponto, há um dos grandes ganhos da orientação a objetos. O
objeto do mundo real Conta Especial será mapeado para uma classe
ContaEspecial que herdará todo código de Conta, conforme a figura 36:
Fonte: AutorFigura 36 - Herança Conta -> ContaEspecial.

Este é o código da implementação da nova classe Conta Especial:

from ContasClientesExtrato import Conta

import datetime

class ContaEspecial(Conta):

def__init__(self,clientes,numero,saldo,limite):

Conta.__init__(self,clientes,numero,saldo) (1)

self.limite = limite (2)

def sacar(self, valor): (3)

if (self.saldo + self.limite) < valor:

return False

else:

self.saldo -= valor

self.extrato.transacoes.append(["SAQUE", valor "Data", datetime.datetime.today()])

return True

Analisando o código ContaEspecial acima, tem-se as seguintes modificações:

MÉTODO CONSTRUTOR __INIT__-


A classe tem que ser instanciada com passagem do limite como um parâmetro
da construção do objeto. O método __Init__ foi sobrescrito da superclasse
Conta. O método super() foi utilizado para chamar um método da superclasse e
pode ser utilizado em qualquer método da subclasse (REAL PYTHONON,
2020). A orientação a objetos permite, inclusive, a reutilização do construtor da
classe pai (1).

ATRIBUTO LIMITE
Foi adicionado apenas na subclasse ContaEspecial, onde será utilizado para
implementar a regra de saques além do valor do saldo (2).
MÉTODO SACAR()
O método precisa verificar se o valor a ser sacado, passado como parâmetro, é
menor do que a soma do saldo atual mais o limite da conta especial. Nesse
caso, a classe Conta Especial reescreveu o método sacar da superclasse
Conta. Essa característica é conhecida como sobrescrita (override) dos
métodos (3).

A execução no terminal gera o seguinte:

>>>from clientes import Cliente


... from ContasClientesExtrato import Conta
... from ContaEspecial import ContaEspecial
... cliente1 = Cliente("123","Joao","Rua X")
... cliente2 = Cliente ("456","Maria","Rua W")
... cliente3 = Cliente ("789","Joana", "Rua H")
... conta1 = Conta([cliente1,cliente2],1,2000)
... conta2 = ContaEspecial([cliente3],3,1000,2000)
... conta2.depositar(100)
... conta2.sacar(3200)
Valor do Saque     3200.00 maior que o valor do saldo mais o limite    
3100.00
>>> conta2.extrato.extrato(conta2.numero)
Extrato : 3
DEPOSITO      100.00 Data      14/Jun/2020

Veja o diagrama atualizado com a implementação dos métodos na subclasse:

Fonte: AutorFigura 38. Herança Conta -> ContaEspecial.

Importante ressaltar que ContaEspecial é uma classe comum e pode ser


instanciada como todas as outras classes independentes da instanciação de
objetos da classe Conta.
Uma análise comparativa com a programação procedural indica que, mesmo
em caso com código parecido, o reuso era bastante baixo. O programador
tinha que criar um programa Conta Corrente Especial repetindo todo o código
já definido no programa Conta Corrente. Com a duplicação do código, era
necessário realizar manutenção de dois códigos parecidos em dois programas
diferentes.

HERANÇA MÚLTIPLA
A herança múltipla é um mecanismo que possibilita uma classe herdar código
de duas ou mais superclasses. Esse mecanismo é implementado por poucas
linguagens orientadas a objetos e insere uma complexidade adicional na
arquitetura das linguagens.

Para nosso sistema, vamos considerar a necessidade de um novo produto que


consiste em uma conta corrente, similar a definida anteriormente no sistema,
com as seguintes características:

Deverá ter um rendimento diário com base no rendimento da conta poupança.

Deverá ser cobrada uma taxa de manutenção mensal, mesmo se o rendimento


for de apenas um dia.

A Classe Poupança também será criada para armazenar a taxa de


renumeração e o cálculo do rendimento mensal da poupança.

Este será o diagrama com as novas classes criadas no sistema de conta


corrente:

Fonte: AutorFigura 39. Herança Múltipla.

A implementação ficou detalhada nos códigos a seguir:

import datetime

class ContaPoupanca:

def__init__(self,taxaremuneracao):
self.taxaremuneracao = taxaremuneracao

self.data_abertura = datetime.datetime.today()

def remuneracaoConta(self)

self.saldo +=self.saldo * self.taxaremuneracao

from ContasClientesExtrato import Conta

from ContaPoupanca import Poupanca

class ContaRemuneradaPoupanca(Conta, Poupanca): (1)

def__init__(self, taxaremuneracao, clientes, numero, saldo, taxaremuneracao):

Conta.__init__(self,clientes,numero,saldo) (2)

Poupanca.__init__(self,taxaremuneracao) (2)

self.taxaremuneracao = taxaremuneracao

def remuneraConta(Self):

self.saldo += self.saldo * (self.taxaremuneracao/30)

self.saldo -= self.taxaremuneracao

Alguns pontos importantes sobre a implementação:

Declaração de herança múltipla: em (1) indica que a classe é herdeira de Conta


e Poupança nessa ordem. Essa ordem tem importância, pois existem dois
métodos no pai com o mesmo nome. O Python dá prioridade para a primeira
classe que implementa esse método na ordem da declaração – (PYTHON
COURSE, 2020)

Construtor da classe: Deve ser chamado o construtor explicitamente das


superclasses com o seguinte formato: nomeclasse.__init__(construtores)

Execução no terminal:

>>>from clientes import Cliente


... from ContasClientesExtrato import Conta
... from ContaPoupanca import Poupanca
... from ContaRemuneradaPoupanca import ContaRemuneradaPoupanca
... cliente1 = Cliente("123","Joao","Rua X")
... cliente2 = Cliente ("456","Maria","Rua W")
... conta1 = Conta([cliente1,cliente2],1,2000)
... contapoupanca1 = Poupanca(0.1)
... contarenumerada1 = ContaRemuneradaPoupanca(0.1,cliente1,5,1000,5)
... contarenumerada1.remuneraConta()
... contarenumerada1.geralsaldo()
numero: 5
  saldo: 998.3333333333334

POLIMORFISMO
Polimorfismo é o mecanismo que permite que um método com o mesmo nome
seja executado de modo diferente, dependendo do objeto que está chamando
o método. A linguagem define em tempo de execução (late binding) qual
método deve ser chamado. Essa característica é bastante comum em herança
de classes devido à redefinição da implementação dos métodos nas
subclasses.

Vamos assumir que agora teremos uma entidade Banco que controla todas as
contas criadas no sistema de conta corrente. As contas podem ser do tipo
conta, contacomum ou contarenumerada. O cálculo do rendimento da conta
Cliente desconta IOF e IR; a conta Renumerada desconta apenas o IOF; a
conta Cliente não tem desconto nenhum. Todos os descontos são realizados
em cima do valor bruto após o rendimento mensal. Uma vez por vez o Banco
executa o cálculo do rendimento de todos os tipos de contas. O diagrama é
apresentado na Figura 42.
Fonte: AutorFigura 42 - Diagrama Banco.

Vamos analisar agora a implementação das classes:

class ContaCliente:

def__init__(self, numero, IOF,IR,valorinvestido,taxarendimento):

self.numero = numero

self.IOF = IOF

self.IR = IR

self.valorinvestido = valorinvestido

self.taxarendimento = taxarendimento

def CalculoRendimento(self):

self.valorinvestido += (self.valorinvestido * self.taxarendimento)

self.valorinvestido = (self.valorinvestido – (self.taxarendimento * self.IOF* self.IR)

def Extrato(Self): (1)

print (f"O saldo atual da conta {self.numero} é {self.valorinvestido:10.2f}")

from ContaCliente import ContaCliente

class ContaComum(ContaCliente)

def__init__(self,numero,IOF,IR,valorinvestido,taxarendimento):

super().__init__(numeroIOFIR,valorinvestido,taxarendimento)

def CalculoRendimento(Self): (2)

sef.valorinvestido += (self.valorinvestido * self.taxarendimento)

from ContaCliente import ContaCliente

class ContaRemunerada(ContaCliente):

def__init__(self,numero,IOF,IR,valorinvestido,taxarendimento):

super().__init__(numeroIOFIR,valorinvestido,taxarendimento)
def CalculoRendimento(Self): (3)

sef.valorinvestido += (self.valorinvestido * self.taxarendimento)

sef.valorinvestido -= self.valorinvestido * self.IOF

Em (1), foi definido um método Extrato que é igual para as 3 classes, ou seja,
as subclasses herdarão o código completo desse método. Em (2) e (3), as
subclasses possuem regras de negócios diferentes, portanto sobrescreveram o
método CalculoRendimento para atender às suas necessidades.

Vamos analisar a implementação da classe Banco e do programa que a utiliza:

class Banco():

def__init__(self, codigo,nome):

self.codigo = codigo

self.nome = nome

self.contas = []

def adicionaconta(self,contacliente):

self.contas.append(contacliente)

def calcularendimentomensal(self): (7)

for c in self.contas:

c.CalculoRendimento()

def imprimesaldocontas(self):

for c in self.contas:

banco1 = Banco(999,"teste")

contacliente1 = ContaCliente (1,0.01,0.1,1000,0.05)

contacomum1 = ContaComum(2,0.01,0.1,2000,0.05)

contaremunerada1 = ContaRemunerada(3,0.01,0.1,2000,0.05)
banco1.adicionaconta(contacliente1) (4)

banco1.adicionaconta(contacomum1) (5)

banco1.adicionaconta(contaremunerada1) (6)

banco1.calcularendimentomensal(7)

banco1.imprimesaldocontas() (8)

Em (4), (5) e (6), banco adiciona todas as contas da hierarquia em um único


método devido ao teste “É-UM” das linguagens orientadas a objetos. No
método, isso é definido para receber um objeto do tipo ContaCliente. Toda vez
que o método é chamado, a linguagem testa se o objeto passado “É-UM”
objeto do tipo ContaCliente.

Em (4), o objeto é da própria classe Conta Cliente. Em (5), o objeto


contacomoum1 passado é uma ContaComum, que passa no teste “É-UM”, pois
uma ContaComum é uma ContaCliente também.

Em (6), o objeto contarenumerada1 “É-UM” objeto ContaComum. Essas ações


são feitas de forma transparente para o programador.

Em (7), acontece a “mágica” do Polimorfismo. Pois, em (4), (5) e (6) são


adicionadas contas de diferentes tipos para o array conta da classe Banco.
Assim, no momento da execução do método c.calculorendimentomensal(), o
valor de c recebe, em cada loop, um tipo de objeto diferente da hierarquia da
classe ContaCliente. Portanto, na instrução c.CalculoRendimento(), o
interpretador tem que identificar dinamicamente de qual objeto da hierarquia
Conta Cliente deve ser chamado o método CalculoRendimento.
Em (8), acontece uma característica que vale ser ressaltada. Pelo
polimorfismo, o interpretador irá verificar o teste “É-UM”, porém esse método
não foi sobrescrito pelas subclasses da hierarquia ContaCliente. Portanto, será
chamado o método Extrato da superclasse.

Se executarmos a classe o programa banco_contarenumerada, o resultado


será:

O saldo atual da conta 1 é: 1048.95


O saldo atual da conta 2 é: 2100.00
O saldo atual da conta 3 é: 2079.00

O polimorfismo é bastante interessante em sistemas com dezenas de


subclasses herdeiras de uma única classe, assim todas as subclasses
redefinem esse método. Sem o polimorfismo, haveria a necessidade de
“perguntar” para a linguagem qual a instância do objeto em execução para
chamar o método correto. Com base no polimorfismo, essa checagem é feita
internamente pela linguagem de maneira transparente.

CLASSES ABSTRATAS
Definir uma classe abstrata é uma característica bastante utilizada pela
programação orientada a objetos. Esse é um tipo de classe que não pode ser
instanciado durante a execução do programa orientado a objetos, ou seja, não
podem existir objetos dessa classe sendo executados na memória. O termo
abstrato remete a um conceito do mundo real, considerando que preciso
apenas de objetos concretos no programa.

A classe abstrata se encaixa perfeitamente no problema do sistema de conta


corrente do banco. Nesse sistema, o banco não quer tratar clientes do tipo
ContaCliente, e sim apenas os objetos do tipo ContaComum e Conta VIP.
Fonte: AutorFigura 48 - Diagrama de Classes abstratas.

Houve apenas adição de esteréotipo <<abstract>> para indicar que Conta


Cliente é uma classe abstrata.

O Python utiliza um módulo chamado abc para definir uma classe como
abstrata, a qual será herdeira da superclasse ABC (Abstract Base Classes).
Toda classe abstrata é uma subclasse da classe ABC (CAELUM, 2020). Para
tornar a classe Conta Cliente abstrata, muda-se a definição para:

from abc import ABC

class ContaCliente(ABC):

Para uma classe ser considerada abstrata, tem de ter pelo menos um método
abstrato. Esse método abstrato pode ter implementação, embora não faça
sentido, pois ele deverá, obrigatoriamente, ser implementado pelas subclasses.
Em nosso exemplo, como não teremos o ContaCliente, esta conta não terá
Calculo do rendimento.

O decorator @abstractmethod indica para a linguagem que o método é


abstrato (STANDARD LIBRARY, 2020), conforme o código apresentado na
Figura 3.15:

from abc import ABC, abstractmethod

class ContaCliente(ABC)

def__init__(self,sumero,IOF,IR,valorinvestido,taxarendimento):

self.numero = numero

self.IOF = IOF

self.IR = IR

self.valorinvestido = valorinvestido

self.taxarendimento = taxarendimento

@abstractmethod
def CalculoRendimento(self):

pass

Quando se tentar instanciar um objeto da classe, obtém-se um erro indicando


que essa classe não pode ser instanciada..

>>> from ContaClienteAbstrata import ContaCliente


cc1 = ContaCliente(1,0.1,0.25,0.1)
Traceback (most recent call last):
File "<input>", line 2, in <module>
TypeError: Can't instantiate abstract class ContaCliente with abstract
methods CalculoRendimento

Apenas as subclasses ContaComum e ContaVIP podem ser instanciadas.

ATENÇÃO
Um alerta importante é que as classes mencionadas devem, obrigatoriamente,
implementar os métodos. Caso contrário, serão classes abstratas e delegarão
para as suas subclasses a implementação concreta do método abstrato.

Fica como sugestão criar as classes concretas ContaComum e ContaVIP sem


implementar o método abstrato do superclasse ContaCliente.

EXCEÇÕES
Como diversas linguagens orientadas a objetos, o Python permite criar novos
tipos de exceções para diferenciar os erros gerados pelas bibliotecas da
linguagem dos erros gerados pelas aplicações desenvolvidas. Devemos usar a
característica da herança para herdar novas exceções a partir classe Exception
do Python (MENEZES, 2020).

class ExcecaoCustomizada(exception): (1)

pass

def throws(): (2)


raise ExcecaoCustomizada

try: (3)

throws()

except ExcecaoCustomizada as ex:

print ("Excecao lançada")

No código acima:

Em (1), definimos a exceção customizada ExcecaoCustomizada com o método


pass, pois não executa nada relevante.

Em (2), é definido um método que, se for chamado, cria a exceção na memória


ExcecaoCustomizada.

Em (3), é utilizado o try...except, que indica para o interpretador que a área do


código localizada entre o try e o except poderá lançar exceções que deverão
ser tratadas nas linhas de código após o except.

Ao final da execução, será impresso “Exceção lançada” pela captura da


exceção lançada pelo método throws().

ENTENDA MAIS SOBRE HERANÇA,


POLIMORFISMO E EXCEÇÕES
No vídeo a seguir, faremos uma breve contextualização do tema.
VERIFICANDO O APRENDIZADO
1. SOBRE A LINGUAGEM DE PROGRAMAÇÃO PYTHON,
MARQUE A ALTERNATIVA INCORRETA.
Python suporta a maioria das técnicas da programação orientada a objetos.

Python suporta e faz uso constante de tratamento de exceções como uma


forma de testar condições de erro e outros eventos inesperados no programa.

A linguagem Python permite a utilização do conceito de sobrecarga de métodos


através do polimorfismo dos métodos.

A separação de blocos de código em Phyton é feita utilizando a endentação de


código.

2. EM RELAÇÃO AOS CONCEITOS DA ORIENTAÇÃO A


OBJETOS E À IMPLEMENTAÇÃO EM PYTHON, PODEMOS
AFIRMAR QUE:
O Poliformismo permite a sobrecarga de métodos em uma classe Python.

Objetos diferentes podem ser agrupados na mesma classe, sempre que


tenham o mesmo número de bytes.

Na linguagem Python existe o conceito de classes abstratas, que fornecem


uma capacidade de reutilização para programas orientados a objetos.

A linguagem Python implementa parcialmente herança múltipla através do


poliformismo.

GABARITO

1. Sobre a linguagem de programação PYTHON, marque a alternativa


incorreta.

A alternativa "C " está correta.


A questão abrange uma visão geral sobre os conceitos de Orientação a
Objetos implementados em Python. O Python não permite a sobrecarga de
métodos nativamente.

2. Em relação aos conceitos da orientação a objetos e à implementação


em Python, podemos afirmar que:

A alternativa "C " está correta.

A questão abrange uma visão geral a implementação dos conceitos orientados


a objetos implementados em Python. Uma classe em Python pode representar
um objeto abstrato do mundo real, pois esse possui propriedades e
responsabilidades que serão utilizados por outros objetos da hierarquia no
programa orientado a objetos.

MÓDULO 4

Comparar a implementação dos conceitos orientados a objetos aplicados a


Python com outras linguagens orientadas a objetos existentes no mercado

LINGUAGEM DE PROGRAMAÇÃO
ORIENTADAS A OBJETOS
As linguagens orientadas a objetos C++ e Java são bastante utilizadas assim
como Python. Inclusive, estão em posições subsequentes no ranking das
linguagens mais utilizadas de todos os paradigmas (TIO-BE, 2020). Portanto, é
interessante fazer um paralelo das principais características de cada linguagem
em relação a orientada a objetos: Python (RAMALHO, 2020), C++ (C++, 2020)
e Java (JAVA, 2020)

COMPARAÇÃO COM C++ E JAVA


INSTANCIAÇÃO DE OBJETOS
As linguagens Java e C++ obrigam utilizar a palavra reservada new e indicar o
tipo do objeto. Porém, a linguagem C++ referencia todos os objetos
explicitamente através de ponteiros. Na tabela a seguir, o objeto Conta
instanciado será referenciado pelo ponteiro *c1. A linguagem Python tem uma
forma simplificada de instanciação de objetos.

Java

Conta c1 = new Conta() Conta *c1 = new Conta(

 Atenção! Para visualização completa da tabela utilize a rolagem horizontal

CONSTRUTORES DE OBJETOS
As linguagens Java e C++ exigem um método definido como público e com o
mesmo nome da classe. O Python obriga ser um método privado __init__,
conforme apresentado na tabela 4.

Java C++

Utilizado um método público com o mesmo nome Utilizado um método com o mesmo
da classe sem tipo de retorno: Public Conta() sem tipo de retorno: Conta::Conta(v

 Atenção! Para visualização completa da tabela utilize a rolagem horizontal

MODIFICADORES DE ACESSO ATRIBUTOS


As linguagens C++ e Python possuem apenas os modificadores público e
privado para atributos. No entanto, ao contrário de Python, C++ e Java,
garantem que um atributo definido como privado seja acessado estritamente
pela própria classe. O Python permite burlar um atributo privado, conforme
detalhado na Tabela 5.

Java C++

Possui os seguintes modificadores:

public Possui os seguintes modificadores:

private public

protected private

default

 Atenção! Para visualização completa da tabela utilize a rolagem horizontal

HERANÇA MÚLTIPLA DE CLASSES

As linguagens C++ e Python implementam herança múltipla diretamente


através de classes, enquanto Java implementa através de herança múltipla de
interfaces.

Java C++

Implementa com a referência da


Não implementa. Utiliza herança múltipla de interfaces herdadas na declaração da clas
para substituir essa característica. Class ContaRemunerada: public
Poupanca)

 Atenção! Para visualização completa da tabela utilize a rolagem horizontal


CLASSES SEM DEFINIÇÃO FORMAL

A linguagem Java implementa o conceito como classes anônimas. Todas as


linguagens implementam o conceito de classes sem definição formal.

Java C++

protected void Calcular(){

    class Calculo{

       private int soma;

       public void setSoma(int soma) { Existe o conceito de classes locais – inte

          this.soma = soma; void func() {

   }    class LocalClass {

      public int getSoma() {    }

         return soma; }

      }

   }

 Atenção! Para visualização completa da tabela utilize a rolagem horizontal

TIPOS PRIMITIVOS

As linguagens Java e C++ possuem um conjunto parecido de tipos primitivos,


enquanto, em Python, todos as variáveis são definidas como objetos.

Java C++
Possui vários tipos primitivos:
Possui vários tipos primitivos:
int
bool
byte
char
short
int
long
float
float
double
double
void
boolean
wchar_t
char

 Atenção! Para visualização completa da tabela utilize a rolagem horizontal

INTERFACES

As linguagens Java e C++ implementam interfaces simples e múltiplas,


enquanto, em Python, não existe o conceito de interfaces.

Java

Implementa interfaces simples e múltiplas: Implementa int

Simples - Class Funcionario implements Autenticavel Simples - Clas

Múltipla - Class Funcionario implements Autenticavel, Descontavel Múltipla - Class

 Atenção! Para visualização completa da tabela utilize a rolagem horizontal

SOBRECARGA DE MÉTODOS
As linguagens Java e C++ implementam sobrecarga de métodos nativamente,
enquanto Python não implementa nativamente.

Java

Implementa sobrecarga de métodos: Implementa sobreca

calculaimposto(salario) calculaimposto(salar

calculaImposto(salario,IR) calculaImposto(salar

 Atenção! Para visualização completa da tabela utilize a rolagem horizontal

TABELA COMPARATIVA
A Tabela 11 apresenta um resumo das características das linguagens Java, C+
+ e Python. A linguagem Python não possui atributos privados, interfaces e
sobrecarga de métodos, que são necessidades fundamentais para a
construção de sistemas orientados a objetos robustos baseado em design
patterns. Portanto, Java e C++ levam uma vantagem considerável para
construção de sistemas puramente orientados a objetos.

Por sua simplicidade, o Python vem crescendo como a primeira linguagem de


programação ensinada na graduação e, devido a quantidade de bibliotecas
estatísticas e frameworks web existentes, é utilizada para o desenvolvimento
de algoritmos de Data Science e sistemas Web.

Características

Instanciação de objetos
Construtores de objetos

Modificadores de acesso atributos

Modificadores de acesso métodos

Herança múltipla

Classes informais

Tipos primitivos

Interfaces

Sobrecarga de métodos

 Atenção! Para visualização completa da tabela utilize a rolagem horizontal

COMPARAÇÃO ENTRE AS
LINGUAGENS C++, JAVA E PYTHON
No vídeo a seguir, faremos uma breve contextualização do tema.
VERIFICANDO O APRENDIZADO
1. EM PYTHON, COMO TRABALHAR SEMPRE COM TIPOS
OBJETOS:
x = c + ADD(a + b).

obj(8).__.

5.__add__(3).

sub(5).__add__(3).

2. ANALISANDO AS CARACTERÍSTICAS ORIENTADA A


OBJETOS DE C++, JAVA E PYTHON, CONSIDERAMOS AS
SEGUINTES AFIRMAÇÕES:
I. EM JAVA, É PERMITIDA A CRIAÇÃO DE HERANÇA
MÚLTIPLA DE CLASSES ATRAVÉS DAS CLASSES
DENOMINADAS INTERFACES
II. EM PYTHON, COMO EM C++ E JAVA, EXISTEM OS TIPOS
PRIMITIVOS E OS OBJETOS PARA SEREM UTILIZADOS
PELOS PROGRAMAS
III. EM PYTHON, O ENCAPSULAMENTO NÃO SEGUE OS
PRINCÍPIOS DA ORIENTAÇÃO A OBJETOS
II, apenas.

II e III, apenas.

I e II, apenas.

III, apenas.
GABARITO

1. Em Python, como trabalhar sempre com tipos objetos:

A alternativa "C " está correta.

Na alternativa C, é realizada a soma seguindo a nota Python. A questão


abrange o tratamento do Python em relação a todos os tipos serem
considerados objetos.

2. Analisando as características Orientada a Objetos de C++, Java e


Python, consideramos as seguintes afirmações:
I. Em Java, é permitida a criação de herança múltipla de classes através
das classes denominadas interfaces
II. Em Python, como em C++ e Java, existem os tipos primitivos e os
objetos para serem utilizados pelos programas
III. Em Python, o encapsulamento não segue os princípios da orientação a
objetos
A alternativa "D " está correta.

Python não possui tipos privados. Os tipos privados que garantem o


encapsulamento são em Java e C++.

CONCLUSÃO

CONSIDERAÇÕES FINAIS
O paradigma orientado a objetos é largamente utilizado no mercado devido a
facilidade na transformação de conceitos do mundo real para objetos
implementados em uma linguagem de software. A linguagem Python
implementa o paradigma utilizando uma sintaxe simples e robusta. Portanto,
vem ganhando mercado, tanto na área acadêmica, quanto na área comercial,
para o desenvolvimento de sistemas orientado a objetos.

Outro ponto importante é que, devido a sua simplicidade, Python vem sendo
utilizada como a primeira linguagem a ser aprendida nos primeiros períodos
dos cursos de tecnologia e engenharia, inclusive para fixar os conceitos da
orientação a objetos.

A quantidade de bibliotecas opensource disponíveis para a implementação de


algoritmos de Data Science tornou a linguagem importante para a
implementação de sistemas de aprendizado e visualização de dados.

AVALIAÇÃO DO TEMA:

REFERÊNCIAS
ANAYA, M. Clean Code in Python: Refactor Your Legacy Code Base. Packt
Publishing Ltd, 29 ago. 2018.
CAELUM. Python e Orientação a Objetos. Consultado em meio eletrônico
em: 14 jun. 2020.
COSTA, M. Análise Orientada a Objetos, março de 2017, 100 f. Notas de
Aula.
FARINELLI, F. Conceitos básicos de programação orientada a objetos.
Consultado em meio eletrônico em: 14 jun. 2020.
GIRIDHAR, C. Learning Python Design Patterns. Packit Publishing, 2018.
JAVA. Java Tutorial. Consultado em meio eletrônico em: 14 jun. 2020.
MENEZES, N. C. Introdução a programação com Python. 3. ed. São Paulo:
Novatec, 2019.
PAJANKAR, A. Python Unit Test Automation: Practical Techniques for
Python Developers and Testers. Apress, 2017.
PYTHON COURSE, Blog Python. Consultado em meio eletrônico em: 14 jun.
2020.
QCONCURSOS, Questões de Concursos. Consultado em meio eletrônico
em: 18 jun. 2020.
RAMALHO, L. Fluent Python. Sebastopol, CA: O´Reilly Media, 2015.
RAMALHO, L. Introdução à Orientação a Objetos em Python (sem sotaque).
Consultado em meio eletrônico em: 14 jun. 2020.

REAL PYTHON, Blog Python, Consultado em meio eletrônico em: 14 jun. 2020.

RUMBAUGH, J. et al. Modelagem e projetos baseados em objetos, Rio de


janeiro: Campus, 1994.
STANDARD LIBRARY, The Python Standard Library. Consultado em meio
eletrônico em: 24 jun. 2020.
TIO-BE. TIO-BE Index. Consultado em meio eletrônico em: 14 jun. 2020.
TUTORIALSPOINT. C++ Tutorial. Consultado em meio eletrônico em: 14 jun.
2020.

EXPLORE+
Para saber mais sobre os assuntos tratados neste tema:

 O desenvolvimento de frameworks com metaclasses é um assunto


importante e bastante utilizado no mercado. Para estudar um pouco
mais esse tema, indicamos o livro Fluent Python, de Luciano
Ramalho, publicado em 2015 pela O´Reilly Media.
 Os designs patterns devem ser estudados e aplicados em sistemas
orientados a objetos de qualquer porte. Para se aprofundar nesse
assunto, indicamos a obra Clean Clean Code in Python: Refactor
Your Legacy Code Base, de Mariano Anaya, publicado em 2018 pela
Packit Publishing e o livro Learning Python Design Patterns, de
Giridhar publicado em 2018 Packit Publishing.
 Os testes unitários buscam garantir a qualidade da implementação de
acordo com as regras de negócios. Para se aprofundar nesse
assunto, indicamos a obra Python Unit Test Automation: Practical
Techniques for Python Developers and Testers de Ashwin Pajankar
publicado em 2017 pela Apress.

CONTEUDISTA
Marcelo Nascimento Costa

CURRÍCULO LATTES
DEFINIÇÃO
Apresentação básica da utilização do Python em outros paradigmas, como
linguagem funcional, computação concorrente, desenvolvimento web e ciência
de dados.

PROPÓSITO
Apresentar a programação por meio do paradigma de linguagem funcional,
bem como a utilização do framework Flask para aplicações web com Python e
a sua utilização para a realização de tarefas relacionadas à mineração de
dados e à extração de conhecimento.
PREPARAÇÃO
Para este tema, é necessário conhecimento prévio em Python.

OBJETIVOS
MÓDULO 1
Identificar a linguagem funcional e sua utilização em Python

MÓDULO 2
Definir os conceitos de computação concorrente e sua utilização em Python

MÓDULO 3
Identificar o Python como ferramenta para desenvolvimento web

MÓDULO 4
Identificar o Python como ferramenta para ciência de dados

INTRODUÇÃO
Neste tema, veremos a utilização da linguagem Python em outros paradigmas,
como linguagem funcional, computação concorrente, desenvolvimento web e
ciência de dados.

Apesar do Python não ser uma linguagem puramente funcional, ela fornece
ferramentas para que possamos programar utilizando esse paradigma. Neste
tema, veremos como isso é possível e quais as vantagens desse estilo de
programação.

Vamos aprender também conceitos relacionados à computação concorrente e


à computação paralela, suas diferenças e como podem ser implementadas em
Python.
Embora o Python não seja a primeira escolha como linguagem de programação
para servidores web, é possível encontrar diversos frameworks que facilitam, e
muito, a sua utilização para tal finalidade. Alguns são minimalistas, como o —
Flask — e permitem criar servidores web escritos em Python em minutos.

Em contrapartida, essa linguagem de programação é a escolha número 1 para


a ciência de dados. Neste tema, iremos conhecer um pouco sobre o processo
de extração de conhecimento e como implementá-lo em Python utilizando a
biblioteca Scikit-Learn.

Baixe os CÓDIGOS FONTE PYTHON, deste tema, para lhe


auxiliar na realização das atividades.

MÓDULO 1

 Identificar a linguagem funcional e sua utilização em Python

INTRODUÇÃO
A programação funcional teve seu início no final dos anos 1950, com a
linguagem LISP.

À diferença do que muitos pensam, esse tipo de programação não é apenas a


utilização de funções em seu código-fonte, mas um paradigma e um estilo de
programação.

Na programação funcional, toda ação realizada pelo programa deve ser


implementada como uma função ou uma composição de funções, mas estas
devem seguir algumas regras:

LISP
LISP é uma família de linguagens de programação desenvolvida, em 1958, por
John McCarthy. Ela foi pensada a princípio para o processamento de dados
simbólicos. Ela é uma linguagem formal matemática.

1
Devem ser puras, ou seja, em qualquer ponto do programa, sempre produzem
o mesmo resultado quando passados os mesmos parâmetros;

Os dados devem ser imutáveis, e uma vez definida uma variável, seu valor não
pode ser alterado;

3
Os loops não devem ser utilizados, mas sim a composição de funções ou
recursividade.

A utilização dessas regras visa garantir, principalmente, que não haja um efeito
indesejável e imprevisto quando executamos um programa ou parte dele.

MUITAS LINGUAGENS DE
PROGRAMAÇÃO (COMO PYTHON, JAVA
E C++) DÃO SUPORTE PARA A
PROGRAMAÇÃO FUNCIONAL, PORÉM
SÃO DE PROPÓSITO GERAL, DANDO
BASE PARA OUTROS PARADIGMAS,
COMO PROGRAMAÇÃO IMPERATIVA E
ORIENTADA A OBJETOS.
Outras linguagens, como Haskell, Clojure e Elixir, são predominantemente de
programação funcional.

A seguir, ensinaremos como utilizar o Python para programação funcional.

FUNÇÕES PURAS
São aquelas que dependem apenas dos parâmetros de entrada para gerar
uma saída. Elas sempre retornam um valor, um objeto ou outra função. Em
qualquer ponto do programa, ao chamar uma função pura, com os mesmos
parâmetros, devemos obter sempre o mesmo resultado.

Veja os dois scripts, funcao1.py e funcao2.py, no Codigo 1 seguir:

Codigo 1 - Scripts funcao1.py

valor = 20

def multiplica(fator):

global valor

valor = valor * fator

print("Resultado", valor)

multiplica(3)

multiplica(3)

Codigo 1 - Scripts funcao2.py

valor = 20

 
def multiplica(valor, fator):

valor = valor * fator

return valor

print("Resultado", multiplica(valor, 3))

print("Resultado", multiplica(valor, 3))

SCRIPT 1
funcao1.py, definimos uma função chamada multiplica, que multiplica a variável
global valor por um fator passado como parâmetro. O valor do resultado é
atribuído à variável valor novamente (linha 5), que é impresso em seguida
(linha 6).
Ao chamarmos a função multiplica(3) pela primeira vez (linha 8), obtemos a
saída “Resultado 60”. Como modificamos a própria variável global valor no
corpo da função, ao chamarmos novamente a função multiplica(3) (linha 9),
obtemos um resultado diferente para a saída: “Resultado 180”.
Além de não depender apenas dos parâmetros, essa função não retorna valor
algum. A função multiplica deste script não é pura.

SCRIPT 2
funcao2.py, utilizamos a variável valor como mais um parâmetro para a
função multiplica. As duas vezes que executamos essa função (linha 7 e 8),
elas retornam o mesmo valor, 60.
A função multiplica deste script é um exemplo de função pura, pois depende
apenas de seus parâmetros para gerar o resultado, e não acessa ou modifica
nenhuma variável externa à função e retorna um valor.

DADOS IMUTÁVEIS
São aqueles que não podem ser alterados após sua criação. Apesar do Python
disponibilizar algumas estruturas de dados imutáveis, como as tuplas, a maioria
é mutável. Na programação funcional, devemos tratar todos os dados como
imutáveis!

As funções puras devem utilizar apenas os parâmetros de entrada para gerar


as saídas. Além dessa característica, as funções puras não podem alterar
nenhuma variável fora de seu escopo.

Observe os scripts do Codigo 2 a seguir, em que passamos a


lista valores como argumento para a função altera_lista. Lembre-se que, no
Python, ao passar uma lista como argumento, apenas passamos sua
referência, ou seja, qualquer mudança feita no parâmetro dentro da função,
também altera a lista original.

Codigo 2 - Scripts funcao3.py

valores = [10, 20, 30]

def altera_lista(lista):

lista[2] = lista[2] + 10

return lista

print("Nova lista", altera_lista(valores))

print("Nova lista", altera_lista(valores))

Codigo 2 - Scripts funcao4.py

valores = [10, 20, 30]

def altera_lista(lista):

nova_lista = list(lista)

nova_lista[2] = nova_lista[2] + 10

return nova_lista

 
print("Nova lista", altera_lista(valores))

print("Nova lista", altera_lista(valores))

Na programação funcional, devemos evitar alterar qualquer dado que já tenha


sido criado. No exemplo anterior, no script funcao3.py, ao alterar o terceiro
elemento do parâmetro lista (linha 4), alteramos também a variável
global valores.
Com isso, ao chamar a mesma função duas vezes (linha 7 e 8), com,
teoricamente, o mesmo parâmetro, obtemos um efeito indesejável, resultando
em saídas diferentes, como no Codigo 3.

Codigo 3 - Saída do script funcao3.py

C:\Users\ftoli\PycharmProjects\estac

Nova lista [10, 20, 40]

Nova lista [10, 20, 50]

Process finished with exit code 0

No exemplo do script funcao4.py, muito similar ao anterior, ao invés de


alterarmos o valor do próprio parâmetro, criamos uma cópia dele (linha 4),
sendo assim, não alteramos a variável valores e obtemos o mesmo resultado
para as duas chamadas da função (linha 8 e 9).
A saída desse script está no Codigo 4.

Codigo 4 - Saída do script funcao4.py

C:\Users\ftoli\PycharmProjects\estac

Nova lista [10, 20, 40]

Nova lista [10, 20, 40]

Process finished with exit code 0


EFEITO COLATERAL E ESTADO DA
APLICAÇÃO
As funções puras e dados imutáveis buscam evitar os efeitos indesejáveis,
como ocorreu no script funcao3.py. Na terminologia de programação funcional,
chamamos isso de efeito colateral (side effect). Além de evitar o efeito
colateral, a programação funcional evita a dependência do estado de um
programa.

A dependência apenas dos parâmetros para gerar saídas garante que o


resultado será sempre o mesmo, independentemente do estado da aplicação,
por exemplo, valores de outras variáveis. Ou seja: não teremos diferentes
comportamentos para uma função baseado no estado atual da aplicação.

EFEITO COLATERAL
O efeito colateral é quando a função faz alguma operação que não seja
computar a saída a partir de uma entrada. Como por exemplo: alterar uma
variável global, escrever no console, alterar um arquivo, inserir um registro no
banco de dados, ou enviar um foguete à lua.

DICA
Ao garantir que uma função utilizará apenas os dados de entrada para gerar
um resultado e que nenhuma variável fora do escopo da função será alterada,
temos a certeza de que não teremos um problema escondido, ou efeito
colateral em nenhuma outra parte do código.

O objetivo principal da programação funcional não é utilizar funções puras e


dados imutáveis, mas sim evitar o efeito colateral.

FUNÇÕES DE ORDEM SUPERIOR


Na programação funcional, é muito comum utilizar funções que aceitem outras
funções, como parâmetros ou que retornem outra função.

Essas funções são chamadas de funções de ordem superior (higher order


function).
No exemplo do Codigo 5 a seguir, vamos criar uma função de ordem superior
chamada multiplicar_por. Ela será utilizada para criar e retornar novas funções.
Essa função, ao ser chamada com um determinado multiplicador como
argumento, retorna uma nova função multiplicadora por aquele multiplicador e
que tem como parâmetro o número a ser multiplicado ( multiplicando).

Codigo 5 - Scripts funcao5.py

def multiplicar_por(multiplicador):

def multi(multiplicando):

return multiplicando * multiplicador

return multi

multiplicar_por_10 = multiplicar_por(10)

print(multiplicar_por_10(1))

print(multiplicar_por_10(2))

multiplicar_por_5 = multiplicar_por(5)

print(multiplicar_por_5(1))

print(multiplicar_por_5(2))

Dentro da função “pai” multiplicar_por, definimos a função multi (linha 2), que


espera um parâmetro chamado multiplicando, que será multiplicado
pelo multiplicador passado como parâmetro para a função “pai”.
Ao chamar a função multiplicar_por com o argumento 10 (linha 6), definimos a
função interna multi como:
DEF MULTI(MULTIPLICANDO):

RETURN MULTIPLICANDO * 10
Essa função é retornada e armazenada na variável multiplicar_por_10 (linha 6),
que nada mais é que uma referência para a função multi recém-criada.
Dessa forma, podemos chamar a função multiplicar_por_10, passando um
número como argumento, o multiplicando, para ser multiplicado por 10 (linha 7
e 8). Produzindo os resultados 10 e 20.
Da mesma forma, criamos a função multiplicar_por_5, passando o número 5
como argumento para a função multiplicar_por (linha 10), que recebe uma
referência para a função:

DEF MULTI(MULTIPLICANDO):

RETURN MULTIPLICANDO * 5
Com isso, podemos utilizar a função multiplicar_por_5 para multiplicar um
número por 5 (linhas 11 e 12).

Observe a saída do programa no console abaixo.

Codigo 5 - Saída do script funcao5

C:\Users\fotoli\PycharmProjects\estac

10

20

10

Process finished with exit code 0


FUNÇÕES LAMBDA
Assim como em outras linguagens, o Python permite a criação de funções
anônimas. Estão são definidas sem identificador (ou nome) e, normalmente,
são utilizadas como argumentos para outras funções (de ordem superior).

Em Python, as funções anônimas são chamadas de funções lambda. Para


criá-las, utilizamos a seguinte sintaxe:
LAMBDA ARGUMENTOS: EXPRESSÃO
Iniciamos com a palavra reservada lambda, seguida de uma sequência de
argumentos separados por vírgula, dois pontos e uma expressão de apenas
uma linha. As funções lambda SEMPRE retornam o valor da expressão
automaticamente. Não é necessário utilizar a palavra return.

EXEMPLO
Considere a função para multiplicar dois números a seguir:

def multiplicar(a, b):

return a*b

A função lambda equivalente é:
lambda a, b: a*b

Temos os parâmetros a e b e a expressão a*b, que é retornado


automaticamente. As funções lambda podem ser armazenadas em variáveis
para depois serem chamadas como uma função qualquer.
Retornando ao exemplo da função multiplicar_por, podemos trocar a
função multi por uma função lambda. Observe no Codigo 6, a seguir, em que
abaixo (anonima.py), temos a utilização da função lambda e após a utilização
da função original (funcao5.py):

Codigo 6 - Script anonima.py

def multiplicar_por(multiplicador):

return lambda multiplicando: multiplicando * multiplicador


 

multiplicar_por_10 = multiplicar_por(10)

print(multiplicar_por_10(1))

print(multiplicar_por_10(2))

multiplicar_por_5 = multiplicar_por(5)

print(multiplicar_por_5(1))

print(multiplicar_por_5(2))

Codigo 6 - Script funcao5.py

def multiplicar_por(multiplicador):

def multi(multiplicando):

return multiplicando * multiplicador

return multi

multiplicar_por_10 = multiplicar_por(10)

print(multiplicar_por_10(1))

print(multiplicar_por_10(2))

multiplicar_por_5 = multiplicar_por(5)

print(multiplicar_por_5(1))

print(multiplicar_por_5(2))

Ao executar o script anonima.py, obtemos o mesmo resultado mostrado


anteriormente: 10, 20, 5 e 10.

NÃO UTILIZAR LOOPS
Outra regra, ou boa prática, da programação funcional é não utilizar laços
(for e while), mas sim composição de funções ou recursividade.
A função lambda exerce um papel fundamental nisso, como veremos a seguir.
Para facilitar a composição de funções e evitar loops, o Python disponibiliza
diversas funções e operadores.
As funções internas mais comuns são map e filter.
MAP
A função map é utilizada para aplicar uma determinada função em cada
elemento de um iterável (lista, tupla, dicionários etc.), retornando um
novo iterável com os valores modificados.

A FUNÇÃO MAP É PURA E DE ORDEM
SUPERIOR, POIS DEPENDE APENAS DE
SEUS PARÂMETROS E RECEBE UMA
FUNÇÃO COMO PARÂMETRO. A SUA
SINTAXE É A SEGUINTE:
MAP(FUNÇÃO, ITERÁVEL1,
ITERÁVEL2...)
O primeiro parâmetro da map é o nome da função (sem parênteses) que será
executada para cada item do iterável. Os demais parâmetros são os iteráveis
separados por vírgula. A função map SEMPRE retorna um novo iterável.
No exemplo do Codigo 7, a seguir, vamos criar três scripts. Todos executam a
mesma operação. Recebem uma lista e triplicam cada item, gerando
uma nova lista com os valores triplicados.

Codigo 7 - Script funcao_iterable.py

lista = [1, 2, 3, 4, 5]

def triplica_itens(iterable):

lista_aux = []

for item in iterable:

lista_aux.append(item*3)

return lista_aux

 
nova_lista = triplica_itens(lista)

print(nova_lista)

Codigo 7 - Script funcao_map.py

lista = [1, 2, 3, 4, 5]

def triplica(item):

return item * 3

nova_lista = map(triplica, lista)

print(list(nova_lista))

Codigo 7 - Script funcao_map_lambda.py

lista = [1, 2, 3, 4, 5]

nova_lista = map(lambda item: item * 3, lista)

print(list(nova_lista))

PRIMEIRO SCRIPT
funcao_iterable.py, definimos uma função chamada triplica_item, que recebe
um iterável como parâmetro (linha 3), cria uma lista auxiliar para garantir
imutabilidade (linha 4), percorre os itens do iterável passado como parâmetro
(linha 5), adiciona os itens triplicados à lista auxiliar (linha 6) e retorna a lista
auxiliar (linha 7).
Essa função é chamada com o argumento lista (linha 9) e o resultado é
impresso (linha 10).
SEGUNDO SCRIPT
funcao_map.py, definimos a função triplica, que triplica e retorna o item
passado como parâmetro (linha 3 e 4). É utilizada, assim como a variável lista,
como argumentos para a função map (linha 6).
A map vai aplicar internamente a função passada como parâmetro em cada
item da lista, retornando um novo iterável (que pode ser convertido em listas,
tuplas etc.). O resultado da função map é armazenado na variável nova_lista,
para então ser impresso (linha 7).
A função map garante a imutabilidade dos iteráveis passados como
argumento. Como a função map retorna um iterável, utilizamos o
construtor list(iterável) para imprimir o resultado (linha 7).
TERCEIRO SCRIPT
funcao_map_lambda.py, substituímos a função triplica pela
função lambda (lambda item: item*3), que foi utilizada como argumento para a
função map (linha 3). Esta vai aplicar a função lambda em cada item da lista,
retornando um novo iterável que foi impresso posteriormente (linha 4).
Observe como o código foi reduzido e mesmo assim preservamos a utilização
de funções puras (lambda), alta ordem (map) e que preservaram a
imutabilidade dos dados. Tudo isso para garantir que não haja efeitos
colaterais e dependência de estados.

Todos os scripts utilizam funções puras e geraram o mesmo resultado: [3, 6, 9,


12, 15].
FILTER
É utilizada para filtrar elementos de um iterável (lista, tupla, dicionários etc.). O
filtro é realizado utilizando uma função, que deve ser capaz de
retornar true ou false para cada elemento do iterável.

TRUE OU FALSE
Verdadeiro ou falso.

ATENÇÃO
Todo elemento que for avaliado como true será incluído em um
novo iterável retornado pela função filter, que é pura e de alta ordem, pois
depende apenas dos parâmetros e recebe uma função como parâmetro. A sua
sintaxe é a seguinte:
filter(função, iterável)
O primeiro parâmetro da função filter é o nome da função (sem parênteses),
que será executada para cada item do iterável. O segundo parâmetro é
o iterável. A função filter SEMPRE retorna um novo iterável, mesmo que
vazio.
No exemplo do Codigo 8 a seguir, vamos criar três scripts. Todos fazem a
mesma filtragem. Recebem uma lista e retornam os elementos ímpares,
gerando uma nova lista, de forma a garantir a imutabilidade.

Codigo 8 - Script funcao_filtro_iterable.py

lista = [1, 2, 3, 4, 5]

def impares(iterable):

lista_aux = []

for item in iterable:

if item % 2 != 0:

lista_aux.append(item)

return lista_aux

nova_lista = impares(lista)

print(nova_lista)

Codigo 8 - Script funcao_filter.py

lista = [1, 2, 3, 4, 5]

def impar(item):

return item % 2 != 0

nova_lista = filter(impar, lista)

print(list(nova_lista))

Codigo 8 - Script funcao_filter_lambda.py
lista = [1, 2, 3, 4, 5]

nova_lista = filter(lambda item: item % 2 != 0, lista)

print(list(nova_lista))

SCRIPT FUNÇÃO_FILTRO_ITERABLE.PY
Definimos uma função chamada ímpares, que recebe um iterável como
parâmetro (linha 3), cria uma lista auxiliar para garantir imutabilidade (linha 4),
percorre os itens do iterável passados como parâmetros (linha 5), adiciona os
itens ímpares à lista auxiliar (linha 6 e 7) e retorna a lista auxiliar (linha 8).
Essa função é chamada com o argumento lista (linha 10) e o resultado é
impresso (linha 11).
SCRIPT FUNCAO_FILTER.PY
Definimos a função ímpar, que retorna true se o item passado como parâmetro
é ímpar ou false caso contrário (linha 3 e 4). Utilizamos essa função, assim
como a variável lista, como argumentos para a função filter (linha 6).
A filter vai aplicar, internamente, a função passada como parâmetro em cada
item da lista, retornando um novo iterável (que pode ser convertido em listas,
tuplas etc.). O resultado da função filter é armazenado na variável nova_lista,
para então ser impresso (linha 7).
A função filter garante a imutabilidade dos iteráveis passados como
argumento. Como a função filter retorna um iterável, utilizamos o
construtor list(iterável) para imprimir o resultado (linha 7).
SCRIPT, FUNÇÃO_FILTER_LAMBDA.PY
Substituímos a função ímpar pela função lambda (lambda item: item%2 != 0)
que foi utilizada como argumento para a função filter (linha 3). Esta vai aplicar a
função lambda em cada item da lista, retornando um novo iterável que foi
impresso posteriormente (linha 4).

Todos os scripts geraram o mesmo resultado: [1, 3, 5].


APLICANDO PROGRAMAÇÃO
FUNCIONAL COM PYTHON

VERIFICANDO O APRENDIZADO
1. OBSERVE AS AFIRMATIVAS RELACIONADAS À
PROGRAMAÇÃO FUNCIONAL E RESPONDA.

I - AS FUNÇÕES PURAS SEMPRE PRODUZEM O MESMO


RESULTADO QUANDO PASSADOS OS MESMOS
PARÂMETROS.
II - DADOS IMUTÁVEIS SÃO AQUELES NOS QUAIS SEUS
VALORES PODEM SER ALTERADOS APÓS A SUA
DEFINIÇÃO.
III - NÃO SE DEVE UTILIZAR LOOPS, MAS COMPOSIÇÃO DE
FUNÇÕES.
IV - A PROGRAMAÇÃO FUNCIONAL É UM PARADIGMA E UM
ESTILO DE PROGRAMAÇÃO.

DAS AFIRMATIVAS ANTERIORES, QUAIS SÃO


VERDADEIRAS?
II e III.

I e III.

II.

I, III e IV.
2. QUAL É O RESULTADO IMPRESSO PELO PROGRAMA A
SEGUIR?
SCRIPT LAMBDA1.PY

MINHA_FUNCAO = LAMBDA X: X ** 2

RESULTADO = MINHA_FUNCAO(4)

PRINT(RESULTADO)

4.

8.

16.

32.

GABARITO

1. Observe as afirmativas relacionadas à programação funcional e


responda.

I - As funções puras sempre produzem o mesmo resultado quando


passados os mesmos parâmetros.
II - Dados imutáveis são aqueles nos quais seus valores podem ser
alterados após a sua definição.
III - Não se deve utilizar loops, mas composição de funções.
IV - A programação funcional é um paradigma e um estilo de
programação.

Das afirmativas anteriores, quais são verdadeiras?


A alternativa "D " está correta.

A única incorreta é a II. Os dados imutáveis NÃO podem ser alterados.

2. Qual é o resultado impresso pelo programa a seguir?


Script lambda1.py

minha_funcao = lambda x: x ** 2

resultado = minha_funcao(4)

print(resultado)

A alternativa "C " está correta.

A função criada retorna o valor do argumento ao quadrado.

MÓDULO 2

 Definir os conceitos de computação concorrente e sua utilização em


Python

INTRODUÇÃO
No início do ano 2000, poucas pessoas tinham acesso a computadores com
mais de um processador. Além disso, os processadores
dos desktops e notebooks daquela época continham apenas um núcleo, ou
seja, só podiam executar uma operação por vez.
Fonte: Nonchanon/Shutterstock

Atualmente, é raro ter um computador, ou até mesmo um celular, com um


processador de apenas um núcleo. Com isso, é muito importante aprendermos
alguns conceitos sobre programação concorrente e paralela e como
implementá-los, de forma a extrair o máximo de performance dos nossos
programas.

CONCORRENTE
Alerta! Clique no item acima. ×

Na computação, temos dois conceitos relacionados à execução


simultânea, concorrência e paralelismo, que serão apresentados no decorrer
deste módulo.

A seguir, definiremos alguns conceitos relacionados à computação concorrente


e paralela, e, posteriormente, mostraremos como o Python implementa tais
funcionalidades.

CONCEITOS
PROGRAMAS E PROCESSOS
Os conceitos iniciais que precisamos definir são programas e processos. Mas
o que seria um programa e um processo na visão do sistema operacional?

PROGRAMA É ALGO ESTÁTICO E


PERMANENTE. CONTÉM UM CONJUNTO
DE INSTRUÇÕES E É PERCEBIDO PELO
SISTEMA OPERACIONAL COMO
PASSIVO.
Em contrapartida, o processo é dinâmico e tem uma vida curta. Ao longo da
sua execução, tem seu estado alterado. Ele é composto por código, dados e
contexto. Em suma, o processo é um programa em execução.

O mesmo programa executado mais de uma vez gera processos diferentes,


que contêm dados e momento de execução (contexto) também diferentes.

CONCORRÊNCIA E PARALELISMO
Em computação, o termo concorrente se refere a uma técnica para tornar os
programas mais usáveis. Ela pode ser alcançada mesmo em processadores de
apenas um núcleo, pois permite compartilhar o processador de forma a rodar
vários processos. Os sistemas operacionais multitarefas suportam
concorrência.

EXEMPLO
Por exemplo, é possível compactar um arquivo e continuar usando o
processador de texto, mesmo em um processador de um núcleo, pois o
processador divide o tempo de uso entre os processos dessas duas
aplicações. Ou seja: essas duas aplicações executam de forma concorrente.
Apesar da concorrência não necessariamente precisar de mais de um núcleo,
ela pode se beneficiar se houver mais deles, pois os processos não precisarão
compartilhar tempo de processador.

Já o paralelismo é uma técnica para permitir que programas rodem mais


rápido, executando várias operações ao mesmo tempo. Ela requer várias
máquinas ou um processador com mais de um núcleo. Também é possível
realizar o paralelismo nas placas de vídeo.
THREADS E PROCESSOS
RELEMBRANDO
O processo é uma instância de um programa em execução. Ele é composto
pelo código que está sendo executado, os dados utilizados pelo programa
(exemplo: valores de variável) e o estado ou contexto do processo.

Em um programa com múltiplos processos, cada um tem seu próprio espaço


de memória e cada um pode executar em um núcleo diferente, melhorando
consideravelmente a performance do programa.

VOCÊ SABIA?
A thread pertence a um determinado processo. Múltiplas threads podem ser
executadas dentro de um mesmo processo. As de um mesmo processo
compartilham a área de memória e podem acessar os mesmos dados de forma
transparente.

Em Python, podemos criar tanto processos quanto threads em um programa.


Antes de falarmos sobre cada abordagem em Python, vamos falar sobre
o global interpreter lock (GIL). No CPython — que é a implementação principal
da linguagem de programação Python, escrita em linguagem C — o GIL existe
para proteger o acesso aos objetos da linguagem.
Fonte: Nonchanon/Shutterstock

Isso acontece objetivando a prevenção para que múltiplas threads não possam


executar os bytecodes do Python de uma vez. Essa “trava” é necessária, pois
visa garantir a integridade do interpretador, uma vez que o gerenciamento de
memória no CPython não é thread-safe.

NA PRÁTICA, PARA UM MESMO


PROCESSO, O GIL SÓ PERMITE
EXECUTAR UMA THREAD DE CADA
VEZ, OU SEJA, ELAS NÃO EXECUTAM
DE FORMA PARALELA,
MAS CONCORRENTES. SEM A “TRAVA”
DO GIL, UMA OPERAÇÃO SIMPLES DE
ATRIBUIÇÃO DE VARIÁVEL PODERIA
GERAR UM DADO INCONSISTENTE
CASO DUAS THREADS ATRIBUÍSSEM
UM VALOR A UMA MESMA VARIÁVEL
AO MESMO TEMPO.
Para os processos, por sua vez, o funcionamento é diferente. Para cada um,
temos um GIL separado. Ou seja: podem ser executados paralelamente. Cabe
ao programador garantir o acesso correto aos dados.

Múltiplos processos podem rodar em paralelo, enquanto múltiplas threads (de


um mesmo processo) podem rodar concorrentemente.

ATENÇÃO
Normalmente, utilizamos thread para interface gráfica, acesso ao banco de
dados, acesso à rede etc., pois o programa não pode parar, ou a interface
congelar, enquanto esperamos baixar um arquivo, por exemplo.

Porém, quando temos um programa que necessita muito dos recursos do


processador e temos como paralelizar nosso programa, devemos optar pela
criação de múltiplos processos.

Criar novos processos pode ser lento e consumir muita memória, enquanto a
criação de threads é mais rápida e consome menos memória.
CRIAÇÃO DE THREADS E PROCESSOS
EXEMPLO
Como criar threads e processos em Python:
Vamos utilizar a classe thread e process, dos
módulos threading e multiprocessing, respectivamente. Para facilitar a
transição entre processos e threads simples, o Python fez os construtores e
métodos das duas classes muito parecidos.

No script principal.py do Codigo 9, vamos criar uma thread e um processo que


executam a mesma função. Na linha 8, criamos uma thread para executar a
função funcao_a utilizando a classe thread. O construtor tem como parâmetros
a função que deverá ser executada (target) e quais parâmetros serão passados
para essa função (args). O parâmetro args espera um iterável (lista, tupla etc.),
onde cada elemento será mapeado para um parâmetro da função target.
Como a funcao_a espera apenas um parâmetro, definimos uma tupla de
apenas um elemento (‘Minha Thread”). O primeiro elemento da tupla,
a string Minha Thread, será passada para o parâmetro nome da funcao_a.
Na linha 9, enviamos o comando para a thread iniciar sua execução, chamando
o método start() do objeto t do tipo thread.

Codigo 9 - Script principal.py

from threading import Thread

from multiprocessing import Process

def funcao_a(nome):

print(nome)

if __name__ == '__main__':

t = Thread(target=funcao_a, args=("Minha Thread",))

t.start()

p = Process(target=funcao_a, args=("Meu Processo",))

p.start()

A criação do processo é praticamente igual, porém utilizando a classe process,


conforme a linha 11. Para iniciar o processo, chamamos o método start() na
linha 12.
Verifique a saída desse script no console abaixo.

Codigo 9 - Saída do script principal(1)

C:\Users\ftoli\PycharmProjects\estac

Minha Thread

Meu Processo

Process finished with exit code 0


MÚLTIPLAS THREADS E PROCESSOS
No exemplo do Codigo 10 a seguir, vamos criar múltiplas threads e processos
usando na criação de para criar threads e processos para compararmos as
saídas de cada um.

VAMOS APROVEITAR PARA MOSTRAR


QUE TODAS AS THREADS ESTÃO NO
MESMO CONTEXTO, COM ACESSO ÀS
MESMAS VARIÁVEIS, ENQUANTO O
PROCESSO NÃO. VAMOS MOSTRAR,
TAMBÉM, COMO FAZER O PROGRAMA
AGUARDAR QUE TODAS
AS THREADS E PROCESSOS TERMINEM
ANTES DE SEGUIR A EXECUÇÃO.
ATENÇÃO
Observe que os códigos dos scripts são praticamente idênticos, com exceção
das classes construtoras thread e process na linha 16 dos dois scripts.

Neste exemplo, a função que será paralelizada é a funcao_a (linha 7). Ela


contém um laço que é executado cem mil vezes e para cada iteração adiciona
o elemento 1 à lista minha_lista, definida globalmente na linha 5.
Vamos criar 10 threads (e processos) para executar 10 instâncias dessa
função, na qual, esperamos que o número de elementos na lista ao final da
execução do programa seja de 1 milhão (10 threads X cem mil iterações).
Para criar essas 10 threads ou processos, temos um laço de 10 iterações (linha
15), em que criamos (linha 16) e iniciamos (linha 18) cada thread ou processo.

O OBJETIVO DA CRIAÇÃO
DE THREADS OU PROCESSOS É
JUSTAMENTE A COMPUTAÇÃO
CONCORRENTE OU PARALELA, O
PYTHON NÃO FICA “PARADO”
AGUARDANDO DELA APÓS CHAMAR O
MÉTODO START(), ELE
IMEDIATAMENTE COMEÇA A PRÓXIMA
ITERAÇÃO DO LAÇO FOR.
Codigo 10 - Script threads_var.py

from threading import Thread, Lock

from multiprocessing import Process

import time

minha_lista = []

def funcao_a(indice):

for i in range(100000):

minha_lista.append(1)

print("Termino thread ", indice)

if __name__ == '__main__':

tarefas = []

for indice in range(10):

tarefa = Thread(target=funcao_a, args=(indice,))

tarefas.append(tarefa)

tarefa.start()

print("Antes de aguardar o termino!", len(minha_lista))

for tarefa in tarefas:

tarefa.join()
 

print("Após aguardar o termino!", len(minha_lista))

Codigo 10 - Script processos_var.py

from threading import Thread, Lock

from multiprocessing import Process

import time

minha_lista = []

def funcao_a(indice):

for i in range(100000):

minha_lista.append(1)

print("Termino processo ", indice)

if __name__ == '__main__':

tarefas = []

for indice in range(10):

tarefa = Process(target=funcao_a, args=(indice,))

tarefas.append(tarefa)

tarefa.start()

print("Antes de aguardar o termino!", len(minha_lista))

for tarefa in tarefas:

tarefa.join()

print("Após aguardar o termino!", len(minha_lista))

ATENÇÃO
É função do programador armazenar uma referência para as suas threads ou
processos, de maneira que possamos verificar seu estado ou interrompê-las.
Para isso, armazenamos cada thread ou processo criado em uma lista
chamada tarefas (linha 17).

Logo após a criação das threads ou processos, vamos imprimir o número de


itens na variável minha_lista (linha 20); aguardar o término da execução
das threads ou processos pela iteração da lista tarefas e utilizando o
método join() (linha 22 e 23); e, por fim, imprimimos o número de itens final da
variável minha_ lista (linha 25).
No Codigo 11, a seguir, temos o resultado de cada script.

Codigo 11 - Saída do script threads_var.py

C:\Users\ftoli\PycharmProjects\estacio_ead\venv\Scripts\python.e

Termino thread Termino thread 0 1

Termino thread Termino thread 23Termino thread 4

Termino thread 5

Termino thread 6

Termino thread 7

Termino thread Antes de guardar o termino! Termino thread 9

970012

Apos guardar o termino! 1000000

Process finished with exit code 0

Codigo 11 - Saída do script processos_var.py

C:\Users\ftoli\PycharmProjects\estacio_ead\venv\

Antes guardar o termino! 0

Termino thread 0
Termino thread 2

Termino thread 1

Termino thread 4

Termino thread 3

Termino thread 5

Termino thread 7

Termino thread 6

Termino thread 8

Termino thread 9

Apos guardar o termino! 0

Process finished with exit code 0

Apesar da saída do script thread.py ter ficado confusa (já iremos retornar nesse
problema), observe que o número de itens da variável minha_lista muda
durante a execução do programa quando usamos thread e não muda quando
usamos processos.
Isso acontece, pois a área de memória das threads é compartilhada, ou seja,
elas têm acesso às mesmas variáveis globais. Em contrapartida, as áreas de
memória dos processos não são compartilhadas. Cada processo acaba criando
uma versão própria da variável minha_lista.
TRAVAS (LOCK)
No exemplo anterior, a função funcao_a incluía o elemento 1 à lista a cada
iteração, utilizando o método append(). No exemplo a seguir, a funcao_a irá
incrementar a variável global contador. Observe o código do Codigo 12 e
verifique o resultado impresso no console seguinte.

Codigo 12 - Script threads_inc.py

from threading import Thread, Lock

from multiprocessing import Process

import time
 

contador = 0

def funcao_a(indice):

global contador

for i in range(1000000):

contador += 1

print("Termino thread ", indice)

if __name__ == '__main__':

tarefas = []

for indice in range(10):

tarefa = Thread(target=funcao_a, args=(indice,))

tarefas.append(tarefa)

tarefa.start()

print("Antes de aguardar o termino!", contador)

for tarefa in tarefas:

tarefa.join()

print("Após aguardar o termino!", contador)

Codigo 12 - Saída do script threads_inc

C:\Users\ftoli\PycharmProjects\estacio_ead\venv\S

Termino thread 1

Termino thread Termino thread 3 2

Termino thread 0 Termino thread

Antes de aguardar o termino! Termino thread 4

5Termino thread 6
2235554

Termino thread Termino thread 9

Termino thread 7

Apos aguardar o termino! 3316688

Process finished with exit code 0

O valor impresso ao final do programa deveria ser 10.000.000 (10 threads X


1.000.000 de iterações), porém foi impresso 3.316.688. Você deve estar se
perguntado por que aconteceu isso, se o GIL garante que apenas
uma thread esteja em execução por vez.

E POR QUE NÃO ACONTECEU ISSO NO


EXEMPLO ANTERIOR?
RESPOSTA

E POR QUE NÃO ACONTECEU ISSO NO


EXEMPLO ANTERIOR?
Vamos começar pelo exemplo anterior. O método utilizado para inserir um
elemento na lista (append), na visão do GIL, é atômico, ou seja, ele é
executado de forma segura e não pode ser interrompido no meio de sua
execução.

O incremento de variável (+=1), que está sendo usando no exemplo atual (linha
10), não é atômico. Ele é, na verdade, composto por duas operações, a leitura
e a atribuição, e não temos como garantir que as duas operações serão
realizadas atomicamente.
Veja a figura 1, em que temos um contador inicialmente com o valor 0 e
três threads incrementando esse contador. Para incrementar, a thread realiza
duas operações: lê o valor do contador e depois atribui o valor lido
incrementado de um ao contador.

Fonte: Autor Figura 1.

Cada thread é executada em um determinado tempo t. Em t1, a thread1 lê e


incrementa o contador, que passa a valer 1. Em t2, a thread2 lê o contador
(valor 1). Em t3, a thread3 lê e incrementa o contador, que passa a valer 2. Em
t4, a thread2 incrementa o contador, porém a partir do valor que ela leu, que
era 1.
No final, o contador passa a valer 2, erroneamente. Esse resultado inesperado
devido à sincronia na concorrência de threads (ou processos) se
chama condição de corrida.
Para evitar a condição de corrida, utilizamos a primitiva lock (trava). Um objeto
desse tipo tem somente dois estados: travado e destravado. Quando criado,
ele fica no estado destravado. Esse objeto tem dois
métodos: acquire e release.
Quando no estado destravado, o acquire muda o estado dele para travado e
retorna imediatamente. Quando no estado travado, o acquire bloqueia a
execução até que outra thread faça uma chamada ao método release e
destrave o objeto. Veja como adaptamos o código anterior para utilizar
o lock no Codigo 13.

Codigo 13 - Script threads_inc_lock.py
from threading import Thread, Lock

from multiprocessing import Process

import time

contador = 0

lock = Lock()

print_lock = Lock()

def funcao_a(indice):

global contador

for i in range(1000000):

lock.acquire()

contador += 1

lock.release()

print_lock.acquire()

print("Termino thread ", indice)

print_lock.release()

if __name__ == '__main__':

tarefas = []

for indice in range(10):

tarefa = Thread(target=funcao_a, args=(indice,))

tarefas.append(tarefa)

tarefa.start()

print("Antes de aguardar o termino!", contador)

for tarefa in tarefas:

tarefa.join()
 

print("Após aguardar o termino!", contador)

Primeiramente, definimos a variável global lock utilizando o construtor lock(),


também do módulo threading (linha 6). Depois, vamos utilizar essa trava para
“envolver” a operação de incremento. Imediatamente antes de incrementar o
contador, chamamos o método acquire() da variável lock (linha 12), de forma a
garantir exclusividade na operação de incremento (linha 13).

Logo após o incremento, liberamos a trava utilizando o método release (linha


14). Com apenas essa modificação, garantimos que o resultado estará correto.
Podemos verificar o resultado no console abaixo.

Codigo 13 - Saída do script threads_inc_lock

C:\Users\ftoli\PycharmProjects\estacio

Antes de aguardar o termino! 73844

Termino thread 1

Termino thread 7

Termino thread 8

Termino thread 9

Termino thread 2

Termino thread 3

Termino thread 0

Termino thread 4

Termino thread 6

Termino thread 5

Após aguardar o termino! 10000000

Process finished with exit code 0

Aproveitamos este exemplo para corrigir o problema de impressão no console


de forma desordenada. Esse problema ocorria, pois o print também não é uma
operação atômica. Para resolver, envolvemos o print da linha 16 com outra
trava, print_lock, criada na linha 7.

COMPARTILHANDO VARIÁVEIS ENTRE


PROCESSOS
Para criar uma área de memória compartilhada e permitir que diferentes
processos acessem a mesma variável, podemos utilizar a classe value do
módulo multiprocessing.
No exemplo do Codigo 14 a seguir, vamos criar uma variável do tipo inteiro e
compartilhá-la entre os processos. Essa variável fará o papel de um contador e
a função paralelizada vai incrementá-la.

Codigo 14 - Script processos.py

from threading import Thread

from multiprocessing import Process, Value

def funcao_a(indice, cont):

for i in range(100000):

with cont.get_lock():

cont.value += 1

print("Termino processo ", indice)

if __name__ == '__main__':

contador = Value('i', 0)

tarefas = []

for indice in range(10):

tarefa = Process(target=funcao_a, args=(indice, contador))

tarefas.append(tarefa)

tarefa.start()

 
print("Antes de aguardar o termino!", contador.value)

for tarefa in tarefas:

tarefa.join()

print("Após aguardar o termino!", contador.value)

Codigo 14 - Saída do script processos

C:\Users\ftoli\PycharmProjects\estacio_e

Antes de aguardar o termino! 0

Termino processo 2

Termino processo 1

Termino processo 0

Termino processo 3

Termino processo 4

Termino processo 5

Termino processo Termino processo 7

Termino processo 8

Termino processo 9

Após aguardar o termino! 1000000

Process finished with exit code 0

Para permitir que a variável seja compartilhada, declaramos uma variável


chamada contador utilizando o construtor da classe value, onde passamos
como primeiro argumento um caractere com o tipo da variável compartilhada (‘i’
🡪 inteiro) e seu valor inicial (0) (linha 11).

COMO NÃO TEMOS ACESSO A


VARIÁVEIS GLOBAIS ENTRE OS
PROCESSOS, PRECISAMOS PASSAR
ESTA PARA O
CONSTRUTOR PROCESS POR MEIO DO
PARÂMETRO ARGS. COMO A
PASSAGEM DE PARÂMETROS É
POSICIONAL, O PARÂMETRO INDICE DA
FUNCAO_A RECEBE O VALOR DA
VARIÁVEL ÍNDICE E O
PARÂMETRO CONT RECEBE UMA
REFERÊNCIA PARA A
VARIÁVEL CONTADOR (LINHA 14).
Isso já é o suficiente para termos acesso a variável contador por meio do
parâmetro cont da função funcao_a. Porém, não resolve a condição de corrida.
Para evitar esse problema, vamos utilizar uma trava (lock) para realizar a
operação de incremento, assim como fizemos no exemplo anterior.

VOCÊ SABIA?
O Python já disponibiliza essa trava nos objetos do tipo value, não sendo
necessário criar uma variável específica para a trava (lock). Observe como foi
realizada a trava utilizando o método get_lock() (linha 6).

Observe pelo console que agora nossa variável está com o valor certo: um
milhão!

Para corrigir o problema da impressão desordenada, basta criar uma variável


do tipo lock e passá-la como parâmetro, assim como fizemos no exemplo
anterior e com a variável contador.

UTILIZANDO PYTHON NA
PROGRAMAÇÃO CONCORRENTE
VERIFICANDO O APRENDIZADO
1. OBSERVE AS AFIRMATIVAS E RESPONDA:

I – É POSSÍVEL ALCANÇAR A CONCORRÊNCIA EM


PROCESSADORES DE APENAS UM NÚCLEO.
II – O PARALELISMO É UMA TÉCNICA PARA PERMITIR
EXECUTAR VÁRIAS OPERAÇÕES AO MESMO TEMPO.
III – PROGRAMAS E PROCESSOS TÊM A MESMA
DEFINIÇÃO.
IV – AS THREADS PERTENCEM A UM DETERMINADO
PROCESSO.

DAS AFIRMATIVAS ANTERIORES, QUAIS ESTÃO


CORRETAS?
II e III.

I e IV.

I, II e IV.

I, II.

2. QUAL O VALOR IMPRESSO PELO SCRIPT A SEGUIR:?


CODIGO 14 - SCRIPT PROCESSOS.PY

MINHA_LISTA = []

DEF ADICIONA():
FOR I IN RANGE(100):

MINHA_LISTA.APPEND(1)

IF __NAME__ == '__MAIN__':

TAREFAS = []

FOR INDICE IN RANGE(10):

T = THREAD(TARGET=ADICIONA)

TAREFAS.APPEND(T)

T.START()

FOR INDICE IN RANGE(10):

P = THREAD(TARGET=ADICIONA)

TAREFAS.APPEND(T)

P.START()

FOR TAREFA IN TAREFAS:

TAREFA.JOIN()

PRINT(LEN(MINHA_LISTA))

100.

1000.

2000.

10000.

GABARITO

1. Observe as afirmativas e responda:

I – É possível alcançar a concorrência em processadores de apenas um


núcleo.
II – O paralelismo é uma técnica para permitir executar várias operações
ao mesmo tempo.
III – Programas e processos têm a mesma definição.
IV – As threads pertencem a um determinado processo.

Das afirmativas anteriores, quais estão corretas?


A alternativa "C " está correta.

A única afirmação errada é a III, pois processo é um programa em execução.

2. Qual o valor impresso pelo script a seguir:?


Codigo 14 - Script processos.py

minha_lista = []

def adiciona():

for i in range(100):

minha_lista.append(1)

if __name__ == '__main__':

tarefas = []

for indice in range(10):

t = Thread(target=adiciona)

tarefas.append(t)

t.start()

for indice in range(10):

p = Thread(target=adiciona)
tarefas.append(t)

p.start()

for tarefa in tarefas:

tarefa.join()

print(len(minha_lista))

A alternativa "B " está correta.

Apenas a thread consegue acessar a variável global minha_lista. São


executadas 10 threads X 100 iterações = 1000.

MÓDULO 3

 Identificar o Python como ferramenta para desenvolvimento web

INTRODUÇÃO
Atualmente, existem diversas opções de linguagem de programação para
desenvolver aplicações web, sendo as principais: PHP, ASP.NET, Ruby e
Java.
De acordo com o site de pesquisas W3Techs, o PHP é a linguagem mais
utilizada nos servidores, com um total de 79% de todos os servidores utilizando
essa linguagem.
Grande parte da utilização do PHP se deve aos gerenciadores de conteúdo,
como WordPress, Joomla e Drupal, escritos em PHP e que tem muita
representatividade na web hoje.
VOCÊ SABIA?
O Python também pode ser utilizado para desenvolver aplicações web?
Atualmente existem diversos frameworks que facilitam a criação de
aplicações web em Python.

Os frameworks podem ser divididos em, basicamente, dois tipos: full-stack e


não full-stack.

FRAMEWORKS FULL-STACK
Os frameworks full-stack disponibilizam diversos recursos internamente, sem a
necessidade de bibliotecas externas. Dentre os recursos, podemos citar:

 Respostas à requisição;

 Mecanismos de armazenamento (acesso a banco de dados);

 Suporte a modelos (templates);

 Manipulação de formulários;

 Autenticação;

 Testes;

 Servidor para desenvolvimento, entre outros.

O principal framework Python full-stack é o Django.
FRAMEWORKS NÃO FULL-STACK
Estes oferecem os recursos básicos para uma aplicação web, como resposta a
requisição e suporte a modelos. Os principais frameworks dessa categoria são
o Flask e o CherryPy.
Normalmente, para aplicações maiores, são utilizados os frameworks full-stack,
que também são um pouco mais complexos de se utilizar.

Para este módulo, usaremos o Flask.

CONCEITOS
O FLASK É UM
MICRO FRAMEWORK WEB EM PYTHON.
Pela descrição de seus desenvolvedores, micro não quer dizer que toda a
aplicação precisa ficar em apenas um arquivo ou que falta alguma
funcionalidade, mas que o núcleo de funcionalidades dele é limpo e simples,
porém extensível.

O desenvolvedor fica livre para escolher qual suporte a modelos (templates)


utilizar, qual biblioteca de acesso ao banco de dados e como lidar com
formulários. Existem inúmeras extensões compatíveis com o Flask.

INICIAR O DESENVOLVIMENTO COM


FLASK É MUITO SIMPLES E
MOSTRAREMOS ISSO AO LONGO
DESTE MÓDULO. APESAR DE NÃO
SER FULL-STACK, O FLASK
DISPONIBILIZA UM
SERVIDOR WEB INTERNO PARA
DESENVOLVIMENTO.
A configuração padrão inicia um servidor local na porta 5000, que pode ser
acessado por: http://127.0.0.1:5000.

Iremos começar com uma aplicação web básica que retorna “Olá, mundo.”


quando acessamos pelo navegador o nosso servidor em http://127.0.0.1:5000.
O nome do nosso script é flask1.py e está apresentado no Codigo 15 a seguir.

Codigo 15 - Script flask1.py

from flask import Flask

app = Flask(__name__)

 
@app.route('/')

def ola_mundo():

return "Olá, mundo."

if __name__ == '__main__':

app.run()

Codigo 15 - Saída do script flask1

C:\Users\ftoli\PycharmProjects\estacio_ead\venv\Scripts\phyton.exe C:/Users/ftoli/Py

* Serving Flask app "principal" (lazy loading)

* Enviroment: production

WARNING: This is a development server. Do not use it in a production deployment.

Use a production WSGI server instead.

* Debug mode: off

* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

Na primeira linha, importamos a classe flask, que é a classe principal


do framework. É a partir de uma instância dessa classe que criaremos nossa
aplicação web. Na linha 2, é criada uma instância da classe flask, onde
passamos __name__ como argumento para que o Flask consiga localizar, na
aplicação, arquivos estáticos, como css e javascript, e arquivos de modelos
(templates), se for o caso.

VOCÊ SABIA?
O Flask utiliza o conceito de rotas para direcionar o acesso às páginas
(ou endpoints). As rotas servem para guiar as requisições feitas ao servidor
para o trecho de código que deve ser executado. Os nomes das rotas são os
nomes utilizados pelo usuário para navegar na sua aplicação.

Por isso, utilize nomes com significado e de fácil memorização. No caso do


Flask, as rotas são direcionadas para funções, que devem retornar algum
conteúdo.
Na linha 5, utilizamos o decorador @app.route(‘/’) para criar uma rota para a
URL raiz da nossa aplicação (‘/’). Esse decorador espera como parâmetro a
rota, ou URL, que será utilizada no navegador, por exemplo.
Toda requisição feita para uma rota é encaminhada para a função
imediatamente abaixo do decorador. No nosso caso, para a
função ola_mundo (linha 6). O retorno dessa função é a resposta que o nosso
servidor enviará ao usuário. Pela linha 7, a função ola_mundo retorna
a string “Olá, mundo.”.
Ao iniciar a execução do script, recebemos no console algumas informações,
incluindo em qual endereço o servidor está “escutando”, observe à direita do
Codigo 16.
Ao digitar no navegador a URL http://127.0.0.1:5000, será exibida a frase “Olá,
mundo.”, como na imagem da figura 2.

Fonte: Autor Figura 2 - Resultado do acesso a http://127.0.0.1:5000.

APRIMORANDO ROTAS
Para ilustrar melhor o uso de rotas, vamos alterar o exemplo anterior de forma
que a rota (URL) para a função ola_mundo seja http://127.0.0.1:5000/ola.
Observe o Codigo 16 e compare com a anterior. Veja que o parâmetro do
decorador @app.route da linha 5 agora é ‘/ola’.

Codigo 16 - Script flask2.py
from flask import Flask

app = Flask(__name__)

@app.route('/ola')

def ola_mundo():

return "Olá, mundo."

if __name__ == '__main__':

app.run()

Se acessarmos no navegador http://127.0.0.1:5000/ola, recebemos como


resposta “Olá, mundo.” (figura 3 A), porém, ao acessar http://127.0.0.1:5000,
recebemos um erro (404) de página não encontrada (Not Found), pois a rota
para a URL raiz da aplicação não existe mais (figura 3 B).

Fonte: Autor Figura 3 A - Resultado do acesso a http://127.0.0.1:5000/ola.


Figura 3 B - Resultado do acesso a http://127.0.0.1:5000.

Vamos acertar nossa aplicação para criar, também, uma rota para a URL raiz
da aplicação (@app.route(‘/’)).

Vamos chamar a função dessa rota de index e criar essa rota conforme linhas
5 a 7. Veja o resultado no Codigo 17 a seguir.

Codigo 17 - Script flask3.py

from flask import Flask

 
app = Flask(__name__)

@app.route('/')

def index():

return "Página principal."

@app.route('/ola')

def ola_mundo():

return "Olá, mundo."

if __name__ == '__main__':

app.run()

Veja, na imagem a seguir, que agora podemos acessar tanto a rota para
função índice (URL: /) (figura 4 A), onde é retornado “Página principal”, quanto
a rota da função ola_mundo (URL: /ola) ( figura 4 B), que é retornado “Olá,
mundo.”.

Fonte: Autor Figura 4 A - Resultado do acesso a http://127.0.0.1:5000. Figura 4


B - Resultado do acesso a http://127.0.0.1:5000/ola.

RECEBENDO PARÂMETROS
O decorador de rota (route) também permite que sejam passados parâmetros
para as funções. Para isso, devemos colocar o nome do parâmetro da função
entre < e> na URL da rota.
No exemplo do Codigo 18 a seguir, vamos mudar a rota da
função ola_mundo de forma que seja possível capturar e retornar o nome
passado como parâmetro.

Codigo 18 - Script flask4.py

from flask import Flask

app = Flask(__name__)

@app.route('/')

def index():

return "Página principal."

@app.route('/ola/<nome>')

def ola_mundo(nome):

return "Olá, " + nome

if __name__ == '__main__':

app.run()

Observe a URL da rota na linha 9, em que utilizamos a variável nome entre <


e>, que é o mesmo nome do parâmetro da função ola_mundo. Isso indica que
qualquer valor que for adicionado à URL após ‘/ola/’ será passado como
argumento para a variável nome da função ola_mundo.
Veja na figura 5 a seguir, em que acessamos a
URL http://127.0.0.1:5000/ola/Amigo.
Fonte: Autor Figura 5 - Resultado do acesso a http://127.0.0.1:5000/ola/Amigo.

Porém, se tentarmos acessar a URL http://127.0.0.1:5000/ola, receberemos um


erro, pois removemos a rota para essa URL. Para corrigir esse problema,
vamos adicionar uma segunda rota para a mesma função, bastando adicionar
outro decorador @app.route para a mesma função ola_mundo,
conforme Codigo 19 a seguir.

Codigo 19 - Script flask5.py

from flask import Flask

app = Flask(__name__)

@app.route('/')

def index():

return "Página principal."

@app.route('/ola/')

@app.route('/ola/<nome>')

def ola_mundo(nome="mundo"):

return "Olá, " + nome

if __name__ == '__main__':

app.run()
Observe que agora temos duas rotas para a mesma função (linha 9 e 10). Em
qualquer uma das URL, o usuário será direcionado para a função ola_mundo.

ATENÇÃO
OBS: A rota com URL ‘/ola/’ aceita requisições tanto para ‘/ola’ quanto ‘/ola/’.

Como nessa nova configuração, o parâmetro nome pode ser vazio quando


acessado pela URL ‘/ola’, definimos o valor padrão “mundo” para ele (linha 11).
Ao acessar essas duas URLs ‘/ola/’ e ‘/ola/Amigo’, obtemos os resultados
exibidos nos resultados exibidos na figura 6 A e 6 B, respectivamente.

Fonte: Autor Figura 6 A - Resultado do acesso a http://127.0.0.1:5000/ola/.


Figura 6 B - Resultado do acesso a http://127.0.0.1:5000/ola/Amigo.

MÉTODOS HTTP
AS APLICAÇÕES WEB DISPONIBILIZAM
DIVERSOS MÉTODOS PARA ACESSAR
UMA URL: GET, POST, PUT E DELETE.
POR PADRÃO, AS ROTAS DO FLASK
SOMENTE RESPONDEM ÀS
REQUISIÇÕES GET. PARA RESPONDER
A OUTROS MÉTODOS, É NECESSÁRIO
EXPLICITAR, NA ROTA, QUAIS
MÉTODOS SERÃO ACEITOS.
Para isso, precisamos utilizar o parâmetro methods do decorador @app.route(),
que espera uma lista de strings com o nome dos métodos aceitos.
Observe no Codigo 20, a seguir, em que criamos a rota para a função logar e
passamos como argumento uma lista contendo duas strings, ‘GET’ e ‘POST’
(linha 15). Isso indica que essa rota deve responder às requisições do tipo GET
e POST.

Codigo 20 - Script flask6.py

from flask import Flask

app = Flask(__name__)

app.debug = True

@app.route('/')

def index():

return "Página principal."

@app.route('/ola/')

@app.route('/ola/<nome>')

def ola_mundo(nome):

return "Olá, " + nome

@app.route('/logar', methods=['GET', 'POST'])

def logar():

if request.method == 'POST':

return "Recebeu post! Fazer login!"

else:

return "Recebeu get! Exibir FORM de login."

if __name__ == '__main__':

app.run()
Para verificar o método que foi utilizado na requisição, usamos o
atributo method do objeto request, que retorna uma das strings: GET, POST,
PUT ou DELETE.
O objeto request é uma variável global disponibilizada pelo Flask e pode ser
utilizada em todas as funções. Para cada requisição, um novo objeto request é
criado e disponibilizado.
Com o objeto request, temos acesso a muitas outras propriedades da
requisição, como: cookie, parâmetros, dados de formulário, mimetype etc.
Neste exemplo, utilizamos o atributo method do objeto request para verificar o
método passado na requisição e retornar conteúdos diferentes dependendo do
método (linhas 17 a 20).

ATENÇÃO
Caso seja requisitada uma rota que exista, porém o método não seja aceito
pela rota, o erro retornado é o 405 - Method Not Allowed (método não
permitido), e não o 404 – Not Found (não encontrado), como ocorre quando a
rota não existe.

Observe que ativamos o modo debug do servidor interno do Flask (linha 5).


Isso nos permite visualizar melhor os avisos e erros durante o
desenvolvimento.

UTILIZANDO MODELOS
As funções no Flask precisam retornar algo. O retorno das funções pode ser
uma string simples e até uma string contendo uma página inteira em HTML.
Porém, criar páginas dessa maneira é muito complicado, principalmente devido
à necessidade de escapar (scape) o HTML, para evitar problemas de
segurança, por exemplo.
Para resolver esse problema, o Flask, por meio da extensão Jinja2, permite
utilizar modelos (templates) que são arquivos texto com alguns recursos a
mais, inclusive escape automático.
No caso de aplicações web, os modelos normalmente são páginas HTML, que
são pré-processadas antes de retornarem ao requisitante, abrindo um novo
leque de possibilidades no desenvolvimento web.

Fonte: Melody Smart/Shutterstock

A cada requisição, podemos alterar uma mesma página de acordo com um


contexto (valores de variáveis, por exemplo). Com a utilização de marcadores
(tags) especiais, é possível injetar valores de variáveis no corpo do HTML, criar
laços (for), condicionantes (if/else), filtros etc.

1
Para criar e utilizar os modelos, por convenção, os HTMLs precisam ficar
dentro da pasta templates, no mesmo nível do arquivo que contém a aplicação
Flask.

2
Para ilustrar, no próximo exemplo (Codigo 21), vamos alterar nossa aplicação
de forma que seja retornada uma página HTML ao se acessar a raiz da
aplicação (‘/’).

3
Para isso, vamos criar um arquivo chamado indice.html na pasta templates, no
mesmo nível do script flask7.py, conforme vemos na árvore de diretório abaixo.
Fonte: MAutor

O conteúdo do modelo indice.html está exibido abaixo do Codigo 21

4
Para o modelo ser acessado na URL raiz (‘/’), a função index() deve ser a
responsável por retorná-lo. Para isso, vamos utilizar a
função render_template disponibilizada pelo Flask, que recebe o nome do
arquivo que desejamos retornar.

Observe a linha 7 do script flask7.py, em que utilizamos essa função e


passamos “indice.html” como parâmetro.

Codigo 21 - Script flask7.py

from flask import Flask, render_template

app = Flask(__name__)

@app.route('/')

def index():

return render_template('indice.html')

@app.route('/ola/')

@app.route('/ola/<nome>')

def ola_mundo(nome="mundo"):
return "Olá, " + nome

if __name__ == '__main__':

app.run()

Codigo 21 - Modelo indice.html

<!DOCTYPE html>

<html>

<body>

<h1>Página principal!</h1>

<h2>Usando templates</h2>

</body>

</html>

Ao acessar http://127.0.0.1:5000, recebemos o resultado exibido na figura 7.

Fonte: Autor Figura 7 - Resultado do acesso a http://127.0.0.1:5000.

Como dito anteriormente, os modelos são páginas HTML turbinadas, nas quais
podemos utilizar delimitadores especiais para alterar nossa página. Os dois
tipos de delimitadores são:

Expressões: {{ ... }}

Que serve para escrever algo no modelo, como o valor de uma variável.

Declarações: {% ... %}
Utilizado em laços e condicionantes, por exemplo.

Antes de serem retornadas ao usuário, essas páginas são renderizadas, ou


seja, os delimitadores são computados e substituídos.

No próximo exemplo, Código 22, vamos alterar a nossa aplicação de forma


que o nome passado como parâmetro para a rota ‘/ola/<nome>’ seja exibido
dentro do HTML.
Para isso, vamos criar um arquivo chamado ola.html na pasta templates,
conforme abaixo no Codigo 22. Observe que utilizamos o delimitador de
expressões com a variável ({{nome_recebido}}), indicando que vamos escrever
o conteúdo dessa variável nesse local após a renderização (linha 4 do
arquivo ola.html).

Codigo 22 - Script flask8.py

from flask import Flask, render_template

app = Flask(__name__)

@app.route('/')

def index():

return render_template('indice.html')

@app.route('/ola/')

@app.route('/ola/<nome>')

def ola_mundo(nome="mundo"):

return "Olá, ", nome_recebido = nome

if __name__ == '__main__':

app.run()

Codigo 22 - Modelo ola.html


<!DOCTYPE html>

<html>

<body>

<h1>Olá, {{ nome_recebido }}</h1>

</body>

</html>

Além de informar a página que queremos renderizar na


função render_templates, podemos passar uma ou mais variáveis para essa
função. Essas variáveis ficarão disponíveis para serem utilizadas em
expressões ({{ }}) e declarações ({% %}) dentro do modelo (template).
No exemplo, desejamos exibir o nome passado via URL na página. Para
passar a variável nome para o HTML, precisamos chamar a
função render_template com um parâmetro a mais, conforme linha 12 e
destacado a seguir (figura 8).

Fonte: Autor Figura 8 - Destaque da sintaxe da função render_template do


Flask.

A variável nome_recebido estará disponível para ser usada dentro do


modelo ola.html. Esse nome pode ser qualquer outro escolhido pelo
programador, mas lembre-se de que ele será usado, também, dentro do
modelo.
Para finalizar, utilizamos o delimitador de expressões envolvendo o nome da
variável (linha 4 do html). Ao ser renderizada, essa expressão será substituída
pelo valor da variável, conforme figura 9 a seguir, onde passamos
a string “Amigo” para a variável nome e, consequentemente, nome_recebido.

Fonte: Autor Figura 9 - Resultado do acesso a http://127.0.0.1:5000/ola/Amigo.

DESENVOLVENDO APLICAÇÕES
WEB COM PYTHON

VERIFICANDO O APRENDIZADO
1. CONSIDERE O CÓDIGO A SEGUIR, EM QUE TEMOS UM
SERVIDOR FLASK ESCUTANDO NA PORTA 5000, E
RESPONDA:
EXERCICIO1.PY

FROM FLASK IMPORT FLASK

APP = FLASK(__NAME__)

@APP.ROUTE('/OLA')

DEF OLA_MUNDO():

RETURN "OLÁ, MUNDO"

@APP.ROUTE('/OLA')

DEF OLA_MUNDO(NOME="MUNDO"):

RETURN "OLÁ, " + NOME

IF __NAME__ == '__MAIN__':

APP.RUN()

O QUE SERÁ APRESENTADO NO NAVEGADOR SE


ACESSARMOS A URL HTTP://127.0.0.1:5000/OLA/EAD?
Olá, mundo.

Olá, mundo.
Olá, EAD.

Olá, EAD.

O programa vai apresentar um erro.

2. CONSIDERE O CÓDIGO A SEGUIR, NO QUAL TEMOS UM


SERVIDOR FLASK ESCUTANDO NA PORTA 5000, E
RESPONDA:
EXERCICIO2.PY
FROM FLASK IMPORT FLASK

APP = FLASK(__NAME__)

@APP.ROUTE('/OLA', METHODS=['POST'])

DEF OLA_POST():

RETURN "OLÁ, GET"

@APP.ROUTE('/OLA')

DEF OLA_GET(NOME="MUNDO"):

RETURN "OLÁ, POST"

IF __NAME__ == '__MAIN__':

APP.RUN()

O QUE SERÁ APRESENTADO NO NAVEGADOR SE


ACESSARMOS A URL HTTP://127.0.0.1:5000/OLA?
Olá, GET.

Olá, GET.
Olá, POST.

Olá, POST.

O programa vai apresentar um erro.

GABARITO

1. Considere o código a seguir, em que temos um servidor Flask


escutando na porta 5000, e responda:

exercicio1.py

from flask import Flask

 
app = Flask(__name__)

@app.route('/ola')

def ola_mundo():

return "Olá, mundo"

@app.route('/ola')

def ola_mundo(nome="mundo"):

return "Olá, " + nome

if __name__ == '__main__':

app.run()

O que será apresentado no navegador se acessarmos a


URL http://127.0.0.1:5000/ola/EAD?
A alternativa "C " está correta.

A URL acessada está de acordo com a rota da linha 9.

2. Considere o código a seguir, no qual temos um servidor Flask


escutando na porta 5000, e responda:

exercicio2.py

from flask import Flask

app = Flask(__name__)

@app.route('/ola', methods=['POST'])

def ola_post():

return "Olá, GET"
 

@app.route('/ola')

def ola_get(nome="mundo"):

return "Olá, POST"

if __name__ == '__main__':

app.run()

O que será apresentado no navegador se acessarmos a


URL http://127.0.0.1:5000/ola?
A alternativa "C " está correta.

O navegador utiliza, por default, o método GET. Com isso, será executada a


rota para a função ola_get, da linha 10.

MÓDULO 4

Identificar o Python como ferramenta para ciência de dados

INTRODUÇÃO
Desde o século XVII, as ciências experimentais e teóricas são reconhecidas
pelos cientistas como os paradigmas básicos de pesquisa para entender a
natureza. De umas décadas para cá, a simulação computacional de fenômenos
complexos evoluiu, criando o terceiro paradigma, a ciência computacional.

A ciência computacional fornece ferramentas necessárias para tornar possível


a exploração de domínios inacessíveis à teoria ou experimento.
Com o aumento das simulações e experimentos, mais dados são gerados e um
quarto paradigma emerge, que são as tecnologias e técnicas associadas à
ciência de dados.

A ciência de dados é uma área de conhecimento que envolve a utilização de


dados para gerar impactos em uma instituição, seja uma universidade, uma
empresa, um órgão federal etc., de forma a resolver um problema real
utilizando os dados.

Fonte: metamorworks/Shutterstock
Em 1996, Fayyad (1996) apresentou a definição clássica do processo de
descoberta de conhecimento em bases de dados, conhecido por KDD
(Knowledge Discovery in Databases):

“KDD É UM PROCESSO, DE VÁRIAS ETAPAS,


NÃO TRIVIAL, INTERATIVO E ITERATIVO,
PARA IDENTIFICAÇÃO DE PADRÕES
COMPREENSÍVEIS, VÁLIDOS, NOVOS E
POTENCIALMENTE ÚTEIS A PARTIR DE
GRANDES CONJUNTOS DE DADOS”.
As técnicas de KDD (FAYYAD, 1996), também conhecidas como mineração de
dados, normalmente se referem à extração de informações implícitas, porém
úteis, de uma base de dados.

Essas aplicações, tipicamente, envolvem o uso de mineração de dados para


descobrir um novo modelo, e então os analistas utilizam esse modelo em suas
aplicações.

O processo de KDD é basicamente composto por três grandes etapas: pré-


processamento, mineração de dados e pós-processamento.
A figura 10, a seguir, mostra todo o processo de KDD.
Fonte: FAYYAD, 1996Figura 10 - Visão geral dos passos que compõe o
processo de KDD

A primeira etapa do processo de KDD, conhecida como pré-processamento, é


responsável por selecionar, preparar e transformar os dados que serão
utilizados pelos algoritmos de mineração.

Algumas atividades envolvidas no reprocessamento são:

COLETA E INTEGRAÇÃO:
Quando é necessário que dados provenientes de diversas fontes sejam
consolidados em uma única base de dados. Esta atividade é bastante
encontrada na construção de data warehouses;
CODIFICAÇÃO:

Significa transformar a natureza dos valores de um atributo. Isto pode


acontecer de duas diferentes formas: uma transformação de dados numéricos
em categóricos — codificação numérico-categórica, ou o inverso — codificação
categórico-numérica;

CONSTRUÇÃO DE ATRIBUTOS:

Após a coleta e integração dos dados, pode ser necessário criar colunas em
uma tabela, por exemplo, refletindo alguma transformação dos dados
existentes em outras colunas;
LIMPEZA DOS DADOS:

Pode ser subdividida em complementação de dados ausentes, detecção de


ruídos, e eliminação de dados inconsistentes;

A PARTIÇÃO DOS DADOS:

Consiste em separar os dados em dois conjuntos disjuntos. Um para


treinamento (abstração do modelo de conhecimento) e outro para testes
(avaliação do modelo gerado).

A segunda etapa do KDD, conhecida como mineração de dados, é a aplicação


de um algoritmo específico para extrair padrões de dados. Hand (2001) define
a etapa de mineração de dados da seguinte forma:

“MINERAÇÃO DE DADOS É A ANÁLISE DE


(QUASE SEMPRE GRANDES) CONJUNTOS DE
DADOS OBSERVADOS PARA DESCOBRIR
RELAÇÕES ESCONDIDAS E PARA
CONSOLIDAR OS DADOS DE UMA FORMA
TAL QUE ELES SEJAM INTELIGÍVEIS E ÚTEIS
AOS SEUS DONOS.”
Esta etapa, normalmente, é a que atrai maior atenção, por ser ela que revela
os padrões ocultos nos dados.

OS ALGORITMOS DE MINERAÇÃO
PODEM SER CLASSIFICADOS
COMO SUPERVISIONADOS E NÃO
SUPERVISIONADOS. NOS PRIMEIROS,
OS ALGORITMOS “APRENDEM”
BASEADOS NOS VALORES QUE CADA
DADO JÁ POSSUI. OS ALGORITMOS
SÃO TREINADOS (AJUSTADOS),
APLICANDO UMA FUNÇÃO E
COMPARANDO O RESULTADO COM OS
VALORES EXISTENTES.
Já nos não supervisionados, os dados não foram classificados previamente e
os algoritmos tentam extrair algum padrão por si só.

A seguir, serão apresentados alguns algoritmos que podem ser realizados


durante a etapa de mineração de dados.

Não supervisio

Uma das técnicas de mineração de dados mais utilizada para comér


Regras de
mesma transação. Ou seja, a presença de um produto em um conju
associação
compras nos enviam sugestões de compras adicionais, baseado no

Reúne, em um mesmo grupo, objetos de uma coleção que mantenh


Agrupamento
de objetos do mesmo grupo e minimizar entre elementos de outros g

Supervisiona

Tem como objetivo descobrir uma função capaz de mapear (classific


Classificação função que realiza esse mapeamento, qualquer nova ocorrência pod
classe;

É uma técnica para se estimar uma variável a partir de uma função.


Regressão linear
computado inicialmente.

 Atenção! Para visualizaçãocompleta da tabela utilize a rolagem horizontal

A última etapa do KDD, o pós-processamento, tem como objetivo transformar


os padrões dos dados obtidos na etapa anterior, de forma a torná-los
inteligíveis, tanto ao analista de dados quanto ao especialista do domínio da
aplicação (SOARES, 2007).
CONCEITOS
Vamos apresentar algumas situações de forma a explicar alguns algoritmos de
mineração e como eles podem ser implementados em Python.

Utilizaremos a biblioteca Pandas para realizar a leitura de dados, a biblioteca


Scikit-Learn para realizar o treinamento e utilização dos algoritmos de
mineração de dados e a biblioteca matplotlib para gerar a visualização de
resultados.

SUPERVISIONADO – REGRESSÃO
LINEAR
Neste exemplo, vamos utilizar uma série histórica fictícia de casos de
dengue de uma determinada cidade e, com o auxílio do algoritmo
supervisionado de regressão linear, predizer casos futuros.
A série está em uma planilha (arquivo CSV) com duas
colunas, ano e casos (número de casos). Na planilha, temos o número de
casos de 2001 a 2017. Vamos utilizar essa série histórica e aplicar o algoritmo
de regressão linear para estimar os casos de dengue para o ano de 2018.
No Codigo 23, a seguir, temos o código do script regressao.py, o arquivo CSV
(dados_dengue.csv) e a saída do console.

Codigo 23 - Script regressao.py

import matplotlib.pyplot as plt

from sklearn.linear_model import LinearRegression

import pandas

############# Pré-processamento ###############

# Coleta e Integração

arquivo = pandas.read_csv('dados_dengue.csv')

 
anos = arquivo[['ano']]

casos = arquivo[['casos']]

############## Mineração #################

regr = LinearRegression()

regr.fit(X=anos, y=casos)

ano_futuro = [[2018]]

casos_2018 = regr.predict(ano_futuro)

print('Casos previstos para 2018 ->', int(casos_2018))

############ Pós-processamento ################

plt.scatter(anos, casos, color='black')

plt.scatter(ano_futuro, casos_2018, color='red')

plt.plot(anos, regr.predict(anos), color='blue')

plt.xlabel('Anos')

plt.ylabel('Casos de dengue')

plt.xticks([2018])

plt.yticks([int(casos_2018)])

plt.show()

Codigo 23 - Dados_dengue.csv

ano,casos

2017,450

2016,538

2015,269

2014,56

2013,165
2012,27

2011,156

2010,102

2009,86

2008,42

2007,79

2006,65

2005,58

2004,39

2003,23

2002,15

2001,28

Codigo 23 - Saída do script regressao.py

C:\Users\fotoli\PycharmProjects\estac

Casos previstos para 2018 -> 330

Após importar os módulos necessários, vamos passar para a primeira etapa do


KDD, o pré-processamento. Neste caso simples, vamos realizar apenas
a coleta e integração que, na prática, é carregar a planilha dentro do
programa.
Para isso, utilizamos a função read_csv da biblioteca Pandas, passando como
parâmetro o nome do arquivo (linha 7).

A CLASSE DA BIBLIOTECA SCIKIT-
LEARN UTILIZADA PARA REALIZAR A
REGRESSÃO LINEAR SE
CHAMA LINEARREGRESSION. PARA
REALIZAR A REGRESSÃO, ELA
PRECISA DOS DADOS DE
TREINAMENTO (PARÂMETRO X) E SEUS
RESPECTIVOS RESULTADOS
(PARÂMETRO Y).
No nosso exemplo, como desejamos estimar o número de casos, vamos utilizar
os anos como dado de treinamento e o número de casos como resultado. Ou
seja, teremos os anos no parâmetro X e os casos no parâmetro y.
Como estamos usando apenas uma variável para o parâmetro X, o ano, temos
uma regressão linear simples e o resultado esperado é uma reta, onde temos
os anos no eixo x e os casos no eixo y.
Após carregar o arquivo, vamos separar os dados das colunas nas respectivas
variáveis. Observe a sintaxe para obter os anos (linha 9) e casos (linha 10). O
Pandas detecta, automaticamente, o nome das colunas e permite extrair os
elementos das colunas utilizando o nome.

ATENÇÃO
O próximo passo é criar o objeto do tipo LinearRegression e atribuí-lo a uma
variável (linha 13). Esse objeto será utilizado para treinar (ajustar) a equação
da reta que será gerada pela regressão. Para realizar o treinamento (fit),
precisamos passar os parâmetros X e y (linha 14).

Após a execução do método fit, o objeto regr está pronto para ser utilizado para


predizer os casos para os anos futuros, utilizando o método predict (linha 17).
Ao chamar o método predict passando o ano 2018 como argumento,
recebemos como retorno o número casos previsto para 2018, conforme
impresso no console da figura 33 (330).
A partir da linha 21, temos a etapa de pós-processamento, na qual utilizamos a
biblioteca matplotlib para exibir um gráfico com os dados da série (pontos em
preto), a reta obtida pela regressão, em azul, e o valor predito para o ano de
2018, em vermelho (figura 11).
Fonte: AutorFigura 11 - Gráfico da série dos casos de dengue

SUPERVISIONADO ‒ CLASSIFICAÇÃO
Os algoritmos de classificação são do tipo supervisionado, nos quais passamos
um conjunto de características sobre um determinado item de uma classe de
forma que o algoritmo consiga compreender, utilizando apenas as
características, qual a classe de um item não mapeado.

Para este exemplo, vamos utilizar um conjunto de dados (dataset) criado em


1938 e utilizado até hoje: o dataset da flor de íris (Iris Dataset). Ele contém
informações de cinquenta amostras de três diferentes classes de Flor de Íris
(Iris setosa, Iris virginica e Iris versicolor).
NO TOTAL, SÃO QUATRO
CARACTERÍSTICAS PARA CADA
AMOSTRA, SENDO ELAS O
COMPRIMENTO E A LARGURA, EM
CENTÍMETROS, DAS SÉPALAS E
PÉTALAS DE ROSAS.
Por ser um dataset muito utilizado e pequeno, o Scikit-Learn já o disponibiliza
internamente.
Vamos treinar dois algoritmos de classificação, árvore de decisão e máquina de
vetor suporte (suport vector machine – SVM) para montar dois classificadores
de flores de íris. A forma como são implementados esses algoritmos estão fora
do escopo deste módulo.
Confira o script a seguir, Codigo 24, em que utilizamos esses dois algoritmos.

Codigo 24 - Script classificacao.py

from sklearn.datasets import load_iris, fetch_kddcup99

from sklearn.metrics import accuracy_score

from sklearn.model_selection import train_test_split

from sklearn.tree import DecisionTreeClassifier, export_text, plot_tree

from sklearn.svm import SVC

################## Pré-processamento ###################

# Coleta e Integração

iris = load_iris()

caracteristicas = iris.data

rotulos = iris.target

print("Caracteristicas:\n", caracteristicas[:2])

print("Rótulos:\n", rotulos[:2])
print('########################################################')

# Partição dos dados

carac_treino, carac_teste, rot_treino, rot_teste = train_test_split(caracteristicas, rotulos)

################### Mineração #####################

############---------- Arvore de Decisão -----------############

arvore = DecisionTreeClassifier(max_depth=2)

arvore.fit(X=carac_treino, y=rot_treino)

rot_preditos = arvore.predict(carac_teste)

acuracia_arvore = accuracy_score(rot_teste, rot_preditos)

############-------- Máquina de Vetor Suporte ------############

clf = SVC()

clf.fit(X=carac_treino, y=rot_treino)

rot_preditos_svm = clf.predict(carac_teste)

acuracia_svm = accuracy_score(rot_teste, rot_preditos_svm)

################ Pós-processamento ####################

print("Acurácia Árvore de Decisão:", round(acuracia_arvore, 5))

print("Acurácia SVM:", round(acuracia_svm, 5))

print('########################################################')

r = export_text(arvore, feature_names=iris['feature_names'])

print("Estrutura da árvore")

print(r)

Codigo 24 - Saída do script classificacao.py


C:\Users\fotoli\PycharmProjects\estacio_ead\

Caracteristicas:

[[5.1 3.5 1.4 0.2]

[4.9 3.  1.4 0.2]]

Rótulos:

[0 0]

###########################################

Acurácia Árvore de Decisão: 0.92105

Acurácia SVM: 0.97368

###########################################

Estrutura da árvore

|--- petal width (cm) <= 0.80

|   |--- class: 0

|--- petal width (cm) > 0.80

|   |--- petal width (cm) <= 1.75

|   |   |--- class: 1

|--- petal width (cm) > 1.75

|   |   |--- class: 2

Process finished with exit code 0

ETAPA 01
Na etapa de pré-processamento, vamos começar pela coleta e integração,
que é a obtenção do dataset de flores utilizando a função load_iris() (linha 9).
Esta função retorna um objeto onde podemos acessar as características das
flores pelo atributo data e os rótulos, ou classes das flores, pelo atributo target.

ETAPA 02
Na linha 11, separamos as características das flores na variável características.
Ela contém uma lista com 150 itens, onde cada item contém outra lista com
quatro elementos. Observe o conteúdo dos dois primeiros itens desta lista no
console.
Cada um dos quatro elementos corresponde ao comprimento da sépala,
largura da sépala, comprimento da pétala e largura da pétala, respectivamente.

ETAPA 03
Na linha 12, separamos os rótulos (ou classes) na variável rótulo. Ela contém
uma lista com 150 itens que variam entre 0, 1 ou 2. Cada número corresponde
a uma classe de flor (0: Iris-Setosa; 1:Iris-Versicolour; 2:Iris-Virginica). Como
dito na introdução deste módulo, esse mapeamento entre categorias e
números se chama codificação categórico-numérica. Essa etapa de pré-
processamento já foi realizada e disponibilizada pela função load_iris().

ETAPA 03
Outra etapa de pré-processamento que precisaremos realizar é a partição dos
dados. Ela nos permitirá verificar a qualidade do algoritmo de classificação.
Para isso, precisamos particionar nossos dados em treino e teste.

Os dados de treino são, como o próprio nome diz, utilizados para treinar
(ajustar) o algoritmo, enquanto os dados de testes são utilizados para verificar
a acurácia dele, comparando o valor calculado para os testes com os valores
reais.

DICA
Para separar as amostras em treino e teste, o Scikit-Learn disponibiliza uma
função chamada train_test_split, que recebe como primeiro parâmetro uma lista
com as características e segundo parâmetro uma lista com os rótulos.

Essa função retorna quatro novas listas:

 De treino;

 De teste das características;

 De treino;

 De teste dos rótulos.


Observe a linha 19, onde utilizamos essa função para gerar quatro novas
variáveis: características para treino (carac_treino); características para teste
(carac_teste); rótulos para treino (rot_treino); e rótulos para teste (rot_teste).
Com a etapa de pré-processamento concluída, o próximo passo é treinar um
algoritmo de classificação com os dados de treino. Para isso, criamos uma
instância do classificador DecisionTree passando como parâmetro a
profundidade máxima da árvore, ou seja, o número máximo de níveis, ou
camadas, a partir do nó raiz, que a árvore encontrada poderá ter (linha 24).

VEREMOS COMO A ÁRVORE FICOU AO


TÉRMINO DO SCRIPT. ESSE OBJETO
SERÁ UTILIZADO PARA TREINAR
(AJUSTAR) A ÁRVORE DE DECISÃO.
PARA REALIZAR O TREINAMENTO (FIT),
PRECISAMOS PASSAR OS
PARÂMETROS X E Y, QUE CONTERÃO
AS CARACTERÍSTICAS DE TREINO E
RÓTULOS DE TREINO
RESPECTIVAMENTE (LINHA 25).
Após treinado o algoritmo, vamos utilizar o método predict do objeto árvore,
passando como argumento as características para teste. Como resultado,
receberemos uma lista com os rótulos preditos (linha 27).
Fonte: PabloLagarto/Shutterstock

Esse resultado será utilizado como parâmetro para a função accuracy_score,


que calcula a acurácia do classificador, comparando os resultados preditos
com os resultados reais (linha 28).

ANALOGAMENTE, FAREMOS O
TREINAMENTO DE UM ALGORITMO DE
CLASSIFICAÇÃO UTILIZANDO O SVM,
POR MEIO DA CLASSE SVC (SUPPORT
VECTOR CLASSIFICATION) EM QUE
UTILIZAREMOS OS VALORES PADRÃO
DO CONSTRUTOR PARA O
CLASSIFICADOR (LINHA 30 A 34).
No pós-processamento, vamos imprimir a acurácia de cada classificador (linha
37 e 38) e uma representação textual da árvore, utilizando a
função export_text (linha 41).

Observe que a acurácia do classificador SVC foi ligeiramente melhor que da


árvore de decisão, 0,97 contra 0,92 da árvore.

Uma representação gráfica da árvore de decisão gerada pode ser vista


na figura 12.

Fonte: AutorFigura 12 - Representação da árvore de decisão com


profundidade 2

Alterando a profundidade da árvore para 3 e executando novamente o


programa, encontramos uma acurácia de 0,97 e a seguinte árvore é exibida
na figura 13:
Fonte: AutorFigura 13 - Representação da árvore de decisão com
profundidade 3

Durante o treinamento de algoritmos, devemos experimentar diferentes


parâmetros, a fim de encontrar o melhor resultado.

NÃO SUPERVISIONADO ‒
AGRUPAMENTO

O OBJETIVO DE UM ALGORITMO DE
AGRUPAMENTO É REUNIR OBJETOS DE
UMA COLEÇÃO QUE MANTENHAM
ALGUM GRAU DE AFINIDADE. É
UTILIZADA UMA FUNÇÃO PARA
MAXIMIZAR A SIMILARIDADE DE
OBJETOS DO MESMO GRUPO E
MINIMIZAR ENTRE ELEMENTOS DE
OUTROS GRUPOS.
Exemplos de algoritmo de agrupamento são k-means (k-medias) e mean-shift.
No próximo exemplo (Codigo 25), vamos utilizar o algoritmo k-medias para
gerar grupos a partir do dataset de flor de íris. Porém, como o agrupamento é
um algoritmo não supervisionado não utilizaremos os rótulos para treiná-lo. O
algoritmo vai automaticamente separar as amostras em grupos, que serão
visualizados em um gráfico.
Na etapa de pré-processamento, vamos começar pela coleta e integração que
é a obtenção do dataset de flores utilizando a função load_iris() (linha 8).
Na linha 10, separamos as características das flores na variável características.
Lembrando que as características das flores são: comprimento da sépala
(índice 0), largura da sépala (índice 1), comprimento da pétala (índice 2) e
largura da pétala (índice 3).

NA ETAPA DE MINERAÇÃO DE DADOS,


VAMOS TREINAR O ALGORITMO DE
AGRUPAMENTO K-MEDIAS COM AS
CARACTERÍSTICAS DAS FLORES. PARA
ISSO, CRIAMOS UMA INSTÂNCIA DA
CLASSE KMEANS PASSANDO COMO
PARÂMETRO O NÚMERO DE GRUPOS
(OU CLASSES) QUE DESEJAMOS QUE O
ALGORITMO IDENTIFIQUE
(N_CLUSTERS) (LINHA 13).
Passamos o número 3, pois sabemos que são 3 classes de flor, mas
poderíamos alterar esse valor. O objeto grupos criado será utilizado para
treinar (ajustar) o algoritmo. Para realizar o treinamento (fit), precisamos passar
apenas parâmetros X, que conterá as características das flores (linha 14).
Após o treino, podemos utilizar o atributo labels_ do objeto grupos para retornar
uma lista com o índice do grupo ao qual cada amostra pertence. Como o
número de grupos (n_clusters) é 3, o índice varia entre: 0, 1 e 2.

Codigo 25 - Script agrupamento.py

import matplotlib.pyplot as plt

from mpl_toolkits.mplot3d import Axes3D

from sklearn.cluster import KMeans

from sklearn.datasets import load_iris

################## Pré-processamento ###################

# Coleta e Integração

iris = load_iris()

caracteristicas = iris.data

################### Mineração #####################

grupos = KMeans(n_clusters=3)

grupos.fit(X=caracteristicas)

labels = grupos.labels_ # indice do grupo ao qual cada amostra pertence

################ Pós-processamento ####################

fig = plt.figure(1)

ax = Axes3D(fig)

ax.set_xlabel('Comprimento Sépala')

ax.set_ylabel('Largura Sépala')

ax.set_zlabel('Comprimento Pétala')

ax.scatter(caracteristicas[:, 0], caracteristicas[:, 1], caracteristicas[:, 2], c=grupos.labels_, edgec

olor='k')

target = iris.target
fig = plt.figure(2)

ax = Axes3D(fig)

ax.set_xlabel('Comprimento Sépala')

ax.set_ylabel('Largura Sépala')

ax.set_zlabel('Comprimento Pétala')

ax.scatter(caracteristicas[:, 0], caracteristicas[:, 1], caracteristicas[:, 2], c=target, edgecolor='k')

plt.show()

A partir da linha 12, temos a etapa de pós-processamento, em que utilizamos a


biblioteca matplotlib para exibir dois gráficos, onde objetos do mesmo grupo
apresentam a mesma cor.
O gráfico da figura 14 A contém os resultados do agrupamento e o
gráfico figura 14 B contém os resultados reais da amostra.

Fonte: AutorFigura 14 A - Resultado do agrupamento e Figura 14 B -


Resultados reais da amostra

APLICANDO PYTHON PARA O


TRATAMENTO DE DADOS
VERIFICANDO O APRENDIZADO
1. DE ACORDO COM O PROCESSO DE DESCOBERTA DE
CONHECIMENTO EM BASE DE DADOS (KDD) E
ANALISANDO AS ASSERTIVAS A SEGUIR, QUAIS
ATIVIDADES PODEM FAZER PARTE DA ETAPA DE PRÉ-
PROCESSAMENTO?

I. COLETA E INTEGRAÇÃO.

II. CODIFICAÇÃO.

III. CONSTRUÇÃO DE ATRIBUTOS.

IV. VISUALIZAÇÃO DOS DADOS.

AGORA, ASSINALE A ALTERNATIVA CORRETA:


I e II

I, II e III

I, III e IV

II, III e IV

2. EM ALGUMAS SITUAÇÕES, PRECISAMOS


TRANSFORMAR UM ATRIBUTO OU CARACTERÍSTICA DE
UMA AMOSTRA DE CATEGORIA PARA UM NÚMERO. QUAL
O NOME DESSA ATIVIDADE?
Coleta e integração.

Codificação.

Construção de atributos.

Partição dos dados.

GABARITO

1. De acordo com o processo de descoberta de conhecimento em base de


dados (KDD) e analisando as assertivas a seguir, quais atividades podem
fazer parte da etapa de pré-processamento?

I. Coleta e Integração.

II. Codificação.

III. Construção de atributos.

IV. Visualização dos dados.

Agora, assinale a alternativa correta:


A alternativa "B " está correta.

Todas fazem parte do pré-processamento, exceto a visualização, que faz


parte do pós-processamento.

2. Em algumas situações, precisamos transformar um atributo ou


característica de uma amostra de categoria para um número. Qual o nome
dessa atividade?

A alternativa "B " está correta.


A codificação categório-numérica transforma string em números.

CONCLUSÃO

CONSIDERAÇÕES FINAIS
Como visto neste tema, a linguagem funcional pode resolver alguns problemas
relacionados à execução do programa, chamados de efeitos colaterais.

Mesmo que não utilizemos todas as diretrizes da programação funcional, como


imutabilidade dos dados, é uma boa prática utilizarmos funções puras, de
forma a evitar a dependência do estado da aplicação e alteração de variáveis
fora do escopo da função.

Em Python, podemos criar tanto programas concorrentes quanto paralelos.


Apesar do GIL (Global Interpreter Lock) permitir executar apenas
uma thread de cada vez por processo, podemos criar múltiplos processos em
uma mesma aplicação.
Com isso, conseguimos tanto gerar códigos concorrentes (múltiplas threads),
quanto paralelos (múltiplos processos).
Apesar do Python não ser a primeira escolha para desenvolvimento web,
mostramos como é simples a utilização do framework Flask para essa
finalidade. Assim como o Flask, outros frameworks mais completos, como
Django, facilitam o desenvolvimento desse tipo de aplicação. Sites como
Instagram e Pinterest utilizam a combinação Python+Django, mostrando que
essa combinação é altamente escalável!

A utilização do Python como ferramenta para ciência de dados evolui a cada


dia. As principais bibliotecas para análise e extração de conhecimento de base
de dados, mineração de dados e aprendizado de máquinas têm uma
implementação em Python.

Apesar de não ter sido mostrado, neste tema, o console do Python é muito
utilizado para realizar experimentações nesta área.

AVALIAÇÃO DO TEMA:

REFERÊNCIAS
DICIONÁRIO ONLINE DE PORTUGUÊS. Definições e significados de mais
de 400 mil palavras. Todas as palavras de A a Z. 2009-2020.
FAYYAD, U. M.; PIATETSKY-SHAPIRO, G.; SMYTH, P.; UTHURUSAMY, R.
(Eds.). From data mining to knowledge discovery in databases. AI
Magazine, v. 17, n. 3, p. 37-54, 1996.
FLASK. Web development, one drop at a time. 2010.
HAND, D.; MANNILA, H.; SMYTH, P. Principles of data mining.
Massachusetts: MIT Press, 1991.
HUNT, J. A beginners guide to Python 3 programming. Basileia: Springer,
2019.
MATPLOBIT. Visualization with Python. John Hunter, Darren Dale, Eric
Firing, Michael Droettboom and the Matplotlib development team. 2012-2020.
PANDAS. Sponsored project of NumFOCUS. 2015.
PYTHON. Python Software Foundation. Copyright 2001-2020.
SCIKIT-LEARN. Machine Learning in Python. 2007.
W3TECHS. Web Technology Surveys. 2009-2020.

EXPLORE+
Acesse a documentação oficial do Python sobre as funções e os operadores
que se integram bem ao paradigma de programação funcional, para aprender
mais sobre o assunto.

Pesquise no site da Jinja2 e conheça mais detalhadamente as funcionalidades


da linguagem de modelos (templates) para Python.

CONTEUDISTA
Frederico Tosta de Oliveira

CURRÍCULO LATTES

Você também pode gostar