Instrutor do Python, Parte 1: O que Há de Novo

Sintaxe Mais Limpa para Código Melhor

Python 3 é a versão mais recente da poderosa linguagem de programação com propósitos gerais de Guido van Rossum. Ele rompe com questões de compatibilidade anteriores à versão 2x, eliminando alguns problemas de sintaxe. Este artigo é o primeiro em uma série que fala sobre as alterações que afetam a linguagem e a compatibilidade de retrocesso e fornece exemplos de novos recursos.

Cesar Otero, Consultant, Freelance Consultant

Cesar OteroCesar Otero é consultor freelancer de Java e Python. É formado em engenharia elétrica com ênfase em matemática.



19/Dez/2008

Python versão 3, também conhecido como Python 3000 ou Py3K (um apelido que é um jogo de palavras no sistema operacional Microsoft® Windows® 2000), é a versão mais recente da linguagem de programação avançada de uso geral do Guido van Rossum. Embora muitos aperfeiçoamentos tenham sido feitos na linguagem principal, a nova versão quebrará a compatibilidade de retrocesso com a linha 2.x. Outras alterações foram antecipadas por algum tempo, como:

  • Divisão verdadeira—por exemplo, 1/2 retorna 0,5.
  • Os tipos long e int foram unificados em um único tipo, com o final L agora removido.
  • True, False e None são agora palavras-chave.

Este artigo—o primeiro em uma série no Python 3—abrange a nova funçãoprint() , input(), muda para Entrada/Saída (E/S), o novo tipo de dados bytes , muda para cadeias e formatação de cadeia e, finalmente, muda para o tipo interno dict . Este artigo é destinado a programadores já familiarizados com o Python que estão curiosos sobre as alterações, mas não desejam passar com dificuldades na longa lista de Python Enhancement Proposals (PEPs).

A Nova Função print()

Você terá que treinar seus dedos novamente para parar de digitar print "hello" e começar a digitar print("hello"), porque print agora é uma função, não uma instrução. Eu sei, é difícil. Cada programador do Python, eu sei,—assim que instala a versão 3 e obtém o erro "sintaxe incorreta"—grita de raiva. Eu sei que os dois caracteres extras são irritantes; eu sei que isso quebrará a compatibilidade de retrocesso. Mas existem vantagens.

Considere os casos em que é necessário redirecionar a saída padrão (stdout) para um log. O seguinte exemplo abre o arquivo log.txt para colocar anexo e designa o objeto para fid. Uma cadeia é então redirecionada para o arquivo, fid, utilizando print>>:

>>>fid = open("log.txt", "a")
>>>print>>fid, "log text"

Um outro exemplo é redirecionar para o erro padrão (sys.stderr):

>>>print>>sys.stderr, "Ocorreu um Erro"

Ambos os exemplos anteriores são bons, mas existe uma solução melhor. A nova sintaxe é agora simplesmente passar um valor para o argumento da palavra-chave file no campo de texto de print() . Por exemplo:

>>>fid = open("log.txt", "a")
>>>print("log.txt", file=fid)

Esse código tem sintaxe bem mais limpa. Uma outra vantagem é a capacidade de alterar o separador passando uma cadeia para o argumento da cadeia sep e alterar a cadeia final passando uma outra cadeia para o argumento da palavra-chave end . Para alterar o separador, seria possível utilizar:

>>>print("Foo", "Bar", sep="%")
>>>Foo%Bar

Em geral, a nova sintaxe é:

print([object, ...][, sep=' '][, end='endline_character_here'][, file=redirect_to_here])

em que o código dentro dos parênteses quadrados ([]) é opcional. Por padrão, chamar o próprio print() anexa um caractere de nova linha ( \n).

Da raw_input() para a input()

No Python versão 2.x, raw_input() lê uma entrada da entrada padrão (sys.stdin) e retorna uma cadeia com o caractere de nova linha final demarcado do final. O seguinte exemplo utiliza raw_input() para capturar uma cadeia do prompt de comandos e, em seguida, designa o valor para quest.

>>>quest = raw_input("Qual a sua procura? ")
Qual a sua procura? Buscar o santo graal.
>>>quest
'Buscar o santo graal.'

Por outro lado, a função input() no Python 2.x espera uma expressão do Python válida, como 3+5.

Originalmente, foi sugerido que ambas input() e raw_input() fossem removidas totalmente do namespace interno do Python; por meio disso, requerendo uma importação para ter qualquer tipo de recurso de entrada. Isso parecia pedagogicamente infundado; repentinamente, simplesmente digitando:

>>>quest = input("Qual a sua procura?")

teria mudado para:

>>>import sys
>>>print("Qual a sua procura?")
>>>quest = sys.stdin.readline()

o que é muito mais detalhado para somente uma entrada simples e muito mais para explicar a um novato. Isso teria requerido instrução sobre o que são módulos e importações , imprimindo uma cadeia e o operador ponto. (Isso suspeitamente é muito parecido com a linguagem Java™ ...) Portanto, no Python 3, raw_input() é renomeada input() e nenhuma importação é necessária para obter dados da entrada padrão. Se você precisa reter a funcionalidade input() versão 2.x, utilize eval(input()), que funciona de maneira idêntica.


Um Pouco Sobre Bytes

O novo tipo de dado, a literal de bytes, assim como o objeto bytes são utilizados para armazenar dados binários. Esse objeto é uma sequência imutável de números inteiros entre 0 e 127 ou caracteres somente ASCII. Realmente, ele é uma versão imutável do objeto bytearray a partir da versão 2.5. Um literal de bytes é uma cadeia com um b antes dela—por exemplo, b'literal de byte'. A avaliação de uma literal de bytes gera um novo objeto bytes . É possível criar um novo objeto bytes com o bytes() . O construtor para um objeto bytes é:

bytes([inicializador[, codificação]])

Por exemplo:

>>>b = (b'\xc3\x9f\x65\x74\x61')
>>>print(b)
b'\xc3\x83\xc2\x9feta'

cria um objeto bytes , mas é redundante, porque é possível criar um objeto bytes simplesmente designando uma literal de byte. (Eu apenas queria demonstrar que você pode fazer isso: Eu não estou, de fato, sugerindo que faça isso.) Se você desejasse utilizar a codificação iso-8859-1, poderia tentar isso:

>>>b = bytes('\xc3\x9f\x65\x74\x61', 'iso-8859-1')
>>>print(b)
b'\xc3\x83\xc2\x9feta'

Se o inicializador for uma cadeia, você deve fornecer uma codificação. Se o inicializador for uma literal de bytes, não é necessário especificar o tipo de codificação: Lembre-se, literais de bytes não são cadeias. Mas como cadeias, é possível concatenar bytes:

>>>b'hello' b' world'
b'hello world'

Utilize o método bytes() para representar ambos: dados binários e texto codificado. Para converter de bytes para str, a bytes deve ser decodificado (há mais sobre isso posteriormente). Dados binários são decodificados com o método decode() . Por exemplo:

>>>b'\xc3\x9f\x65\x74\x61'.decode()
'ßeta'

Também é possível ler dados binários a partir de um arquivo. O código:

>>>data = open('dat.txt', 'rb').read()
>>>print(data) # dado é um conteúdo
>>># de cadeia de data.txt impresso aqui

é aberto para ler um objeto de arquivo no modo binário e lê no arquivo inteiro.


Cadeias

O Python possui um tipo de cadeia único, str, que se comporta de forma semelhante ao tipo unicode da versão 2.x. Em outras palavras, todas as cadeias são cadeias unicode. Além disso—e muito convenientemente para usuários de texto não-latino—identificadores não-ASCII são agora permitidos. Por exemplo:

>>>césar = ["autor", "consultor"]
>>>print(césar)
['autor', 'consultor']

Nas versões anteriores do Python, repr() converte cadeias de 8 bits em ASCII. Por exemplo:

>>>repr('é')
"'\\xc3\\xa9'"

Ele agora retorna uma cadeia unicode:

>>>repr('é')
"'é'"

que, como mencionado anteriormente, é o tipo de cadeia interno.

Objetos de cadeia e objetos de byte são incompatíveis. Se você deseja a representação de cadeia de um byte, utilize seu método decode() . De modo contrário, utilize o método encode() de um objeto de cadeia se você deseja uma literal de bytes daquela cadeia.


Alterações na Formatação da Cadeia

Muitos programadores do Python acharam que o operador interno % para formatar cadeias era muito limitado, porque:

  • Ele é um operador binário e pode utilizar no máximo dois argumentos.
  • Isentando o argumento de cadeia de formatações, todos os outros argumentos devem ser comprimidos com um conjunto de variáveis ou um dicionário.

Esse estilo é um tanto inflexível; portanto, o Python 3 apresenta uma nova maneira de fazer a formatação de cadeia. (O operador % e o módulo string.Template são retidos na versão 3.) Objetos de cadeia agora têm um método, format(), que aceita argumentos posicionais e de palavra-chave, que são passados em campos de substituição. Campos de substituição são indicados por chaves ({}) dentro de uma cadeia. O elemento dentro de um campo de substituição é simplesmente chamado de um campo. Este é um exemplo simples:

>>>"Eu amo {0}, {1} e {2}".format("ovos", "bacon", "salsicha")
'Eu amo ovos, bacon e salsicha'

Os campos {0}, {1} e {2} são passados nos parâmetros posicionais ovos, bacon e salsicha para o método format() . O seguinte exemplo mostra como utilizar format() com argumentos de palavra-chave passados para o formato:

>>>"Eu amo {a}, {b} e {c}".format(a="ovos", b="bacon", c="salsicha")
'Eu amo ovos, bacon e salsicha'

Aqui está um outro exemplo que combina parâmetros posicionais e argumentos de palavra-chave:

>>>"Eu amo {0}, {1} e {param}".format("ovos", "bacon", param="salsicha")
'Eu amo ovos, bacon e salsicha'

Lembre-se de que é um erro de sintaxe ter um argumento de não palavra-chave depois de argumento de palavra-chave. Para escapar de chaves, dobre-as, como a seguir:

>>>"{{0}}".format("Impossível me ver")
'{0}'

O parâmetro posicional invisível não é impresso, porque não há nenhum campo para imprimir. Observe que isso não causa um erro.

A nova função interna format() formata um valor único. Por exemplo:

>>>print(format(10.0, "7.3g"))
       10

Em outras palavras, o g representa formato geral, que imprime um número de largura fixa. O primeiro número antes do ponto especifica a largura mínima e o número após o ponto especifica a precisão. A sintaxe completa para especificadores de formato está além do escopo deste artigo, mas é possível localizar links para obter informações adicionais na seção Recursos .


Alterações no Tipo de Dicionário Interno

Uma outra mudança importante no 3.0 é a remoção dos métodos dict.iterkeys(), dict.itervalues() e dict.iteritems() nos dicionários. Como alternativa, você utiliza .keys(), .values() e .items(), que foram remodelados para retornar objetos leves, configurados como contêiner ao invés de uma lista que é uma cópia das chaves ou valores. A vantagem aqui é a capacidade de executar operações set em chaves e itens sem ter que copiá-las. Por exemplo:

>>>d = {1:"dead", 2:"parrot"}
>>>print(d.items())
<itens de método interno do objeto dict em 0xb7c2468c>

Nota: No Python, sets são coletas desordenadas de elementos exclusivos.

Aqui, eu criei um dicionário com duas chaves e valores e, em seguida, imprimi os valores d.items(), o que retorna um objeto, não uma lista de valores. É possível testar a associação de um elemento exatamente como um objeto set object:

>>>1 in d # teste para associação
True

Aqui está um exemplo de iteração sobre os itens do objeto dict_values :

>>>for values in d.items():
...     print(values)
...
dead
parrot

Mas, se você realmente deseja uma lista de valores, pode sempre difundir o objeto retornado dict . Por exemplo:

>>>keys = list(d.keys())
>>>print(keys)
[1,2]

Nova E/S

Metaclasses

De acordo com a wikipedia, "uma metaclasse é uma classe cujas instâncias são classes." Eu exploro esse conceito em mais detalhes na parte 2 desta série.

Antes de aprofundar-se nos novos mecanismos para E/S, é necessário rever Abstract Base Classes (ABCs). Um tratamento mais detalhado é fornecido neste tópico na segunda parte desta série.

ABCs são classes que não podem ser instanciadas. Para utilizar uma ABC, uma subclasse de herdar da ABC e substituir seus métodos abstratos. Um método é abstrato se for precedido com o decorador @abstractmethod. A nova estrutura ABC também fornece o decorador @abstractproperty para definir propriedades abstratas. Você acessa a nova estrutura importando o módulo da biblioteca padrão abc. A Lista 1 fornece um exemplo simples.

Lista 1. Uma Classe Base Abstrata Simples
from abc import ABCMeta

class SimpleAbstractClass(metaclass=ABCMeta):
    pass

SimpleAbstractClass.register(list)

assert isinstance([], SimpleAbstractClass)

A macro register() utiliza uma classe como um argumento e torna a ABC uma subclasse de classe registrada. É possível verificar isso chamando a instrução assert na última linha. A Lista 2 fornece um outro exemplo que utiliza decoradores.

Lista 2. Uma Classe Base Abstrata Implementada com Decoradores
from abc import ABCMeta, abstractmethod

class abstract(metaclass=ABCMeta):
    @abstractmethod
    def absMeth(self):
        pass
 
class A(abstract):
    # deve implementar método abstrato
    def absMeth(self):
        return 0

Agora que você sabe sobre ABCs, vamos continuar com o novo sistema de E/S. Releases anteriores do Python eram desprovidos de funções importantes mas exóticas, como seek(), para alguns objetos semelhantes a fluxos. Objetos semelhantes a fluxos são objetos semelhantes a arquivos com soquetes ou arquivos de métodos read() e write() , —por exemplo. O Python 3 possui múltiplas camadas para objetos semelhantes a fluxos de E/S—uma camada de E/S bruta, uma camada de E/S com buffer e uma camada de E/S de texto—cada uma definida com sua própria ABC com implementações.

Você ainda abre um fluxo utilizando a função interna open(fileName) , embora também possa chamar io.open(fileName)). Fazer isso retorna um arquivo de texto com buffer; read() e readline() retorna cadeias. (Lembre-se de que todas as cadeias no Python 3 são unicode.) Também é possível abrir um arquivo binário com buffer utilizando a forma open(fileName, 'b'). Nesse caso, read() retorna bytes, mas você não pode utilizar readline().

O construtor para a função interna open() é:

open(file,mode="r",buffering=None,encoding=None,errors=None,newline=None,closefd=True)

Os modos possíveis são:

  • r: Leitura
  • w: Abrir para gravação
  • a: Abrir para anexar
  • b: Modo binário
  • t: Modo de texto
  • +: Abrir um arquivo de disco para atualização
  • U: Modo nova linha universal

O modo padrão é rt ou abrir para leitura do modo de texto.

O argumento chave buffering espera um de três números inteiros para determinar a política de criação de buffer:

  • 0: Desliga a criação de buffer
  • 1: Criação de buffer de linha
  • > 1: Criação de buffer integral (padrão)

A codificação padrão é dependente de plataforma. O descritor de arquivo fechado ou closefd, pode ser True ou False. Se False, o descritor de arquivo é mantido após o arquivo ser fechado. Caso um nome do arquivo não vá funcionar, closefd deve ser configurado como True.

O objeto que open() retorna depende do modo que você configurar. A Tabela 1 mostra os tipos de retorno.

Tabela 1. Tipos de Retorno para Diferentes Modos Abertos
ModoObjeto Retornado
Modo de textoTextIOWrapper
BinárioBufferedReader
Gravar binárioBufferedWriter
Anexar binárioBufferedWriter
Modo de Leitura/GravaçãoBufferedRandom

Nota: O modo de texto pode ser w, r, wt, rt, e assim por diante.

O exemplo na Lista 3 abre um fluxo binário com buffer para leitura.

Lista 3. abrir um Fluxo Binário com Buffer para Leitura
>>>import io
>>>f = io.open("hashlib.pyo", "rb")  # abrir para leitura no modo binário
>>>f                                 # f é um objeto BufferedReader
<io.BufferedReader object at 0xb7c2534c>
>>>f.close()                         # fechar fluxo

O objeto BufferedReader possui acesso a vários métodos úteis, como isatty, peek, raw, readinto, readline, readlines, seek, seekable, tell, writable, write e writelines, para mencionar alguns. Para ver a lista integral, execute um dir() em um objeto BufferedReader .


Conclusão

Se a comunidade do Python aceitará a versão 3 é a suposição de qualquer um. A quebra da compatibilidade de retrocesso significará suportar duas versões diferentes em paralelo. Alguns desenvolvedores de projeto podem não desejar migrar seus projetos, mesmo com o conversor 2para3. Pessoalmente, eu descobri que migrar do Python versão 2 para 3 era primeiramente uma questão de reaprender algumas coisas: Certamente não era uma mudança tão drástica quanto mudar do Python, digamos, para linguagens Java ou Perl. Muitas das alterações foram previstas há muito tempo, como a divisão verdadeira e alterações no dict. Executar um print() é em geral bem mais fácil que o System.out.println() em Java; portanto, a curva de aprendizado é relativamente pequena e existem vantagens a serem ganhas.

Suponho, pela leitura de entradas na esfera de blogs, que muitos Pythonistas consideram algumas alterações—como a quebra da compatibilidade de retrocesso—interruptoras de negócios. O Lambda foi originalmente planejado para remoção, mas foi retido e em sua forma original. Para obter a lista completa de coisas que estão suspensas, visite o site de desenvolvimento principal do Python. Se você for aventureiro o suficiente para buscar através das PEPs, pode encontrar mais informações detalhadas ali.

A próxima parcela nesta série abordará tópicos mais avançados, como a sintaxe de metaclasse, ABCs, decoradores, suporte à literal de número inteiro, tipos de base e exceções.

Recursos

Aprender

Obter produtos e tecnologias

Discutir

Comentários

developerWorks: Conecte-se

Los campos obligatorios están marcados con un asterisco (*).


Precisa de um ID IBM?
Esqueceu seu ID IBM?


Esqueceu sua senha?
Alterar sua senha

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


A primeira vez que você entrar no developerWorks, um perfil é criado para você. Informações no seu perfil (seu nome, país / região, e nome da empresa) é apresentado ao público e vai acompanhar qualquer conteúdo que você postar, a menos que você opte por esconder o nome da empresa. Você pode atualizar sua conta IBM a qualquer momento.

Todas as informações enviadas são seguras.

Elija su nombre para mostrar



Ao se conectar ao developerWorks pela primeira vez, é criado um perfil para você e é necessário selecionar um nome de exibição. O nome de exibição acompanhará o conteúdo que você postar no developerWorks.

Escolha um nome de exibição de 3 - 31 caracteres. Seu nome de exibição deve ser exclusivo na comunidade do developerWorks e não deve ser o seu endereço de email por motivo de privacidade.

Los campos obligatorios están marcados con un asterisco (*).

(Escolha um nome de exibição de 3 - 31 caracteres.)

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


Todas as informações enviadas são seguras.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=80
Zone=Linux, Software livre
ArticleID=382601
ArticleTitle=Instrutor do Python, Parte 1: O que Há de Novo
publish-date=12192008