• Nenhum resultado encontrado

Exemplo de expressão com geradores

No documento Python e Django Fundamentos (páginas 97-102)

O exemplo implementa uma classe Aluno para auxiliar a demonstração. O if principal no fim do programa mostra o uso de expressões geradoras.

#!/usr/bin/env python3 # src/modelo08.py class Aluno:

def __init__(self, codigo=0, nome='', media=0): self.codigo = codigo self.nome = nome self.media = media def situacao(self): if self.media < 4: return 'Reprovado' elif self.media < 7: return 'Recuperação' else: return 'Aprovado' if __name__ == '__main__':

# Implementa a classe exemplo alunos para ser usada como exemplo # de uso de expressões de geradores. Além das expressões que criam # os geradores codigos e situacoes, a função zip é um gerador também.

P yt ho n e D ja ng o F un da m en to s

alunos = [Aluno(1, 'Pedro', 8), Aluno(2, 'Laura', 9), Aluno(3, 'Estudapoco', 5), Aluno(4, 'Mataula', 3)]

codigos = (aluno.codigo for aluno in alunos) print(type(codigos))

# <class 'generator'>

situacoes = (aluno.situacao() for aluno in alunos) print(type(situacoes))

# <class 'generator'>

resultados = {cod: sit for cod, sit in zip(codigos, situacoes)} print(resultados)

# {1: 'Aprovado', 2: 'Aprovado', 3: 'Recuperação', 4: 'Reprovado'}

É criada uma lista de alunos que será usada nos exemplos de expressões geradoras. Então, são criados dois geradores utilizando expressões geradoras.

codigos = (aluno.codigo for aluno in alunos) print(type(codigos))

<class 'generator'>

situacoes = (aluno.situacao() for aluno in alunos) print(type(situacoes))

<class 'generator'>

Para confirmar que foram criados geradores, foi impresso o tipo das variáveis codigos e situacoes usando a função type. Elas são do tipo “class generator”.

resultados = {codigo: situacao

for codigo, situacao in zip(codigos, situacoes)} print(resultados)

{1: 'Aprovado', 2: 'Aprovado', 3: 'Recuperação', 4: 'Reprovado'}

Por fim, criamos um dicionário que utiliza os códigos como chave, associados a situação. O dicionário é criado utilizando uma expressão geradora, essa sintaxe é chamada também de compreensão de dicionários.

Uma dúvida sempre surge: quando usar compreensão de listas ou expressões geradoras? Uma das maneiras mais fáceis de decidir é pensar se uma lista será necessária. Após obter o resultado, será necessário usar um método de lista (algo como lista.append ou lista.insert)? Será necessário acessar elementos pelo índice ou usar fatiamento de listas? Enfim, se for necessário ter uma lista, deve ser usada uma compreensão de listas.

Módulos

q

1 São arquivos Python que contêm definições e comandos. 1 Facilitam a reutilização e organização de código.

1 O nome do arquivo é o nome do módulo, mais o sufixo “.py”

1 O nome de um módulo pode ser acessado pela variável global __name__.

Os módulos da linguagem Python são arquivos com a extensão “.py”, que podem conter instruções, variáveis, comandos, funções ou classes. Para manter uma boa organização, recomenda-se que em um módulo fiquem definidas coisas similares dentro de um contexto.

Ca pí tu lo 4 - R ec ur so s e sp ec ia is d o P yt ho n

Existe uma variável global muito utilizada em módulos, chamada __name__, que arma- zena o nome do módulo. Um módulo da linguagem Python é um objeto e, portanto, possui propriedades.

Vejamos como isso acontece na prática. Vamos implementar um módulo simples que imprima a variável __name__.

# exercicio01.py print(__name__)

Tendo feito isto, execute o mesmo conforme o comando:

$ python exercicio01.py

Em seguida, abra o interpretador e execute o comando import, conforme indicado a seguir:

$ python

>>> import exercicio01

Qual a diferença entre as duas execuções do mesmo módulo?

Sempre que um módulo é importado ou quando é passado como parâmetro na linha de comando do interpretador, ele é interpretado. Todas as instruções do módulo são interpre- tadas, ou seja, são realizadas as análises léxica e sintática, é gerado o bytecode, que é então executado pela máquina virtual da linguagem Python.

Isso tudo linha a linha, instrução por instrução. Mas nem sempre é necessário executar tudo, já que em módulos com muitas classes ou funções podemos estar interessados em usar apenas uma função ou classe específica. Nesse caso, é possível usar uma técnica específica para que a parte principal de um módulo só seja executada quando o módulo for chamado por linha de comando.

q

1 Para rodar um módulo, usamos o comando: python nome_do_modulo.py <argumentos>. 1 Quando executado dessa forma, o nome do módulo será __main__, ou seja, a variável

__name__ será __main__.

1 Para controlar o que é executado quando o módulo é importado, é verificado se a variável __name__ é igual a __main__.

1 Quando o módulo for importado por outro, a variável __name__ será o nome do módulo e o bloco do teste não será executado.

Como vimos acima, para rodar um módulo pela linha de comando basta passar o nome do módulo como parâmetro da linha de comando para o interpretador:

python nome_do_modulo.py <argumentos do módulo>

Na linha de comando acima, os <argumentos do módulo> são opcionais. Ao executar um módulo dessa maneira, o nome dele, internamente, será __main__. Esse nome fica armaze- nado na variável global __name__. Então, para evitar que uma parte do código seja execu- tada, criamos uma condição que verifica se essa variável, __name__, é igual a __main__. Quando o módulo for importado, a variável __name__ conterá o nome do módulo, que no exemplo anterior era “nome_do_modulo”.

Esses conceitos podem ser melhor explorados no exemplo a seguir, modelo09.py, onde temos um módulo que define duas funções que verificam se um número é primo usando dois algo- ritmos diferentes: primo1 e primo2. Logo no início temos a definição da exceção PrimoInvalido.

Deixar todo o código de um sistema grande em um único módulo dificulta a manutenção e reutilização do código.

P yt ho n e D ja ng o F un da m en to s #!/usr/bin/env python3 # src/modelo09.py class PrimoInvalido(Exception): pass def primo1(numero): if numero <= 0: raise PrimoInvalido # Número um não é primo. if numero == 1:

return False

# Número 2 é o único par primo. if numero == 2:

return True

for valor in range(2, numero, 1): if (numero % valor) == 0: return False return True def primo2(numero): if numero == 0: raise PrimoInvalido # Número um não é primo. if numero == 1:

return False

# Número 2 é o único par primo. if numero == 2:

return True

# Os outros números pares não são primos. if (numero % 2) == 0:

return False

for valor in range(3, numero // 2, 2): if (numero % valor) == 0:

return False return True

if __name__ == '__main__': print(primo1(0))

# Traceback (most recent call last): # ... # modelo09.PrimoInvalido print(primo1(1)) # False print(primo1(2)) # True print(primo1(4)) # False print(primo1(5))

Ca pí tu lo 4 - R ec ur so s e sp ec ia is d o P yt ho n # True print(primo2(0))

# Traceback (most recent call last): # ... # modelo09.PrimoInvalido print(primo2(1)) # False print(primo2(2)) # True print(primo2(4)) # False print(primo2(5)) # True

O último comando if do programa utiliza a variável global __name__ para diferenciar o modo de execução do módulo. Os comandos dentro do bloco if são executados somente quando o módulo é executado diretamente pela linha de comando (“python modelo09.py”). Entre- tanto, se importarmos o módulo exemplo09.py em outro módulo qualquer, esse trecho do if não será executado (a variável __name__ será ‘__modelo09__’).

Vale reforçar que as instruções/comandos de um programa Python são interpretados apenas uma vez, no momento da sua execução ou importação. As definições de um módulo fazem parte da sua própria tabela de símbolos. É importante ter isso em mente, pois módulos podem importar outros módulos, permitindo assim o reaproveitamento de código.

q

1 As definições e comandos são interpretados apenas uma vez, quando o módulo é executado ou importado.

1 Cada módulo tem sua própria tabela de símbolos. 1 Módulos podem importar outros módulos.

1 Módulos importados são alocados na tabela de símbolos do módulo onde foram importados.

Quando um ou mais módulos são importados, eles são alocados na tabela de símbolos do módulo principal, que importou os outros módulos. Existem várias formas de importar um módulo, conforme veremos mais adiante.

#!/usr/bin/env python3 # src/modelo10.py import modelo09

from modelo09 import primo2 print(modelo09.primo1(13)) print(primo2(17))

if __name__ == '__main__': print(modelo09.primo1(0))

# Traceback (most recent call last): # ...

P yt ho n e D ja ng o F un da m en to s print(modelo09.primo1(1)) # False print(primo2(2)) # True print(primo2(4)) # False

Para importar o módulo, usamos o comando import modulo. Quando o módulo é impor- tado desse jeito, para acessar algum elemento usamos o nome do módulo e o nome do elemento, separado por um ponto.

modelo09.primo1(13)

Quando é importado um elemento, podemos usar o nome do elemento diretamente. Só é preciso tomar cuidado para não importar elementos que tenham o nome igual, pois isso vai provocar um conflito silencioso (o último elemento importado sobrescreve o anterior).

print(primo2(17))

No documento Python e Django Fundamentos (páginas 97-102)