O livro "Python. Curso expresso. 3rd ed.

imagem Oi, habrozhiteli! Este livro é destinado a pessoas que já possuem experiência em uma ou mais linguagens de programação e desejam aprender o básico do Python 3. o mais rápido e fácil possível.Pode presumir que o leitor já esteja familiarizado com estruturas de controle, OOP, manipulação de arquivos, manipulação de exceções, etc. O livro também será útil para usuários de versões anteriores do Python que precisam de uma referência compacta do Python 3.1.

Convidamos você a ler o trecho "Processando arquivos de dados"

Como usar um livro


Parte 1 fornece informações gerais sobre Python. Você aprenderá como baixar e instalar o Python no seu sistema. Ele também fornece uma visão geral da linguagem, que será útil principalmente para programadores experientes que desejam uma compreensão de alto nível do Python.

A parte 2 contém o material principal do livro. Ele discute os ingredientes necessários para obter habilidades práticas no uso do Python como uma linguagem de programação de uso geral. O material dos capítulos foi planejado para que os leitores que estão começando a aprender Python possam avançar sequencialmente, dominando os pontos principais da linguagem. Esta parte também contém seções mais complexas, para que você possa retornar e encontrar todas as informações necessárias sobre um determinado design ou tópico em um único local.

A Parte 3 apresenta os recursos avançados dos elementos da linguagem Python que não são absolutamente necessários, mas certamente serão úteis para qualquer programador Python sério.

A parte 4 se concentra em tópicos especializados que vão além da simples sintaxe do idioma. Você pode ler esses capítulos ou ignorá-los, dependendo de suas necessidades.

Os programadores iniciantes em Python são incentivados a começar no capítulo 3 para obter uma impressão geral e, em seguida, passar para os capítulos de interesse na parte 2. Introduzir exemplos interativos para instanciar conceitos. Você também pode ir além dos exemplos fornecidos no texto e procurar respostas para quaisquer perguntas que ainda não estejam claras. Essa abordagem aumentará a velocidade do aprendizado e aprofundará a compreensão. Se você ainda não conhece o OOP ou não é necessário para o seu aplicativo, pode pular a maior parte do capítulo 15.

Os leitores que já estão familiarizados com o Python também devem começar no capítulo 3. Ele fornece uma boa visão geral introdutória e uma descrição das diferenças entre o Python 3 e as versões mais familiares. Também pode ser usado para avaliar se você está pronto para avançar para os capítulos mais complexos das partes 3 e 4 deste livro.

Talvez alguns leitores que não tenham experiência com o Python, mas que tenham experiência suficiente em outras linguagens de programação, possam obter a maioria das informações necessárias lendo o Capítulo 3 e observando os módulos da biblioteca padrão do Python (Capítulo 19) e o manual de referência da biblioteca do Python na documentação do Python. .

Trecho. Processamento de arquivo de dados


A maioria dos dados é distribuída em arquivos de texto. Pode ser um texto não estruturado (por exemplo, uma coleção de mensagens ou uma coleção de textos literários) ou dados mais estruturados, nos quais cada linha é um registro, e os campos são separados por um caractere separador especial - uma vírgula, um caractere de tabulação ou uma barra vertical (|). Arquivos de texto podem ser enormes; um conjunto de dados pode ocupar dezenas ou até centenas de arquivos e os dados nele contidos podem estar incompletos ou distorcidos. Com essa variedade, você quase inevitavelmente encontrará a tarefa de ler e usar dados de arquivos de texto. Este capítulo apresenta as estratégias básicas para resolver esse problema no Python.

21.1 Apresentando ETL


A necessidade de extrair dados dos arquivos, analisá-los, convertê-los em um formato conveniente e fazer algo apareceu quase simultaneamente com os arquivos de dados. Além disso, existe até um termo padrão para esse processo: ETL (Extract-Transform-Load, ou seja, “extração - transformação - carregamento”). Recuperação refere-se ao processo de ler uma fonte de dados e analisá-la, se necessário. A conversão pode envolver a limpeza e a normalização dos dados, além de combinar, dividir e reorganizar os registros que eles contêm. Por fim, carregar significa salvar os dados convertidos em um novo local (em outro arquivo ou banco de dados). Este capítulo discute o básico da implementação de um ETL no Python, de arquivos de dados de texto a armazenamento de dados convertidos em outros arquivos. Arquivos de dados mais estruturados são discutidos no capítulo 22, e o armazenamento de informações em um banco de dados é discutido no capítulo 23.

21.2 Lendo arquivos de texto


O primeiro componente do ETL - extração - envolve abrir um arquivo e ler seu conteúdo. À primeira vista, parece simples, mas mesmo aqui podem surgir problemas - por exemplo, tamanho do arquivo. Se o arquivo for muito grande para caber na memória, o código precisará ser estruturado para funcionar com segmentos menores do arquivo (possivelmente uma linha).

21.2.1 Codificação de texto: ASCII, Unicode e outros


Outro possível problema é a codificação. Este capítulo é dedicado ao trabalho com arquivos de texto e, de fato, uma grande proporção dos dados transmitidos no mundo real é armazenada em arquivos de texto. No entanto, a natureza exata do texto pode variar dependendo do aplicativo, do usuário e, é claro, do país.

Às vezes, o texto carrega informações na codificação ASCII, incluindo 128 caracteres, dos quais apenas 95 são classificados como imprimíveis. Felizmente, a codificação ASCII é o "múltiplo menos comum" da maioria das situações de transferência de dados. Por outro lado, não pode lidar com as complexidades dos numerosos alfabetos e sistemas de escrita existentes no mundo. A leitura de arquivos na codificação ASCII quase certamente levará ao fato de que, ao ler caracteres não suportados, seja alemão ü, português ç ou quase qualquer caractere de um idioma que não seja o inglês, os problemas serão iniciados e os erros aparecerão.

Esses erros ocorrem porque o ASCII usa valores de 7 bits, enquanto os bytes em um arquivo típico consistem em 8 bits, o que permite que 256 valores possíveis sejam representados em vez de 128 para valores de 7 bits. Esses códigos adicionais geralmente são usados ​​para armazenar valores adicionais - de sinais de pontuação estendidos (como traços médios e curtos) a vários caracteres (marca registrada, símbolo de direitos autorais e sinal de grau) e versões de caracteres alfabéticos com sinais diacríticos. Sempre havia um problema: ao ler um arquivo de texto, era possível encontrar um caractere que ultrapassava o intervalo ASCII de 128 caracteres e não era possível ter certeza de qual caractere estava codificado. Suponha que você encontre um caractere com o código 214. O que é isso? Uma marca de divisão, a letra Ö ou qualquer outra coisa? Sem o código fonte que criou esse arquivo, é impossível descobrir.

Unicode e UTF-8


Para eliminar essa ambiguidade, você pode usar Unicode. A codificação Unicode, chamada UTF-8, suporta caracteres ASCII básicos sem nenhuma alteração, mas também permite um conjunto quase ilimitado de outros caracteres e caracteres do padrão Unicode. Devido à sua flexibilidade, o UTF-8 é usado em mais de 85% das páginas da web que existiam no momento em que este artigo foi escrito. Isso significa que, ao ler arquivos de texto, é melhor focar em UTF-8. Se os arquivos contiverem apenas caracteres ASCII, eles serão lidos corretamente, mas você também terá seguro caso outros caracteres sejam codificados em UTF-8. Felizmente, o tipo de dados String do Python 3 foi projetado para suportar Unicode por padrão.

Mesmo com Unicode, as situações são possíveis quando valores aparecem no texto que não podem ser decodificados com êxito. A função aberta no Python recebe um parâmetro de erros adicional, que determina como lidar com erros de codificação ao ler ou gravar arquivos. O valor padrão é 'strict', com o qual um erro é acionado toda vez que um erro de codificação é detectado. Outros valores úteis são 'ignorar' (pule o caractere que causou o erro); 'substituir' (um personagem é substituído por um marcador especial - geralmente?); 'backslashreplace' (o caractere é substituído pela sequência de escape por \) e 'surrogateescape' (o caractere invasor é convertido em um ponto de código Unicode privado ao ler e volta à sequência de bytes original ao escrever). A escolha do método para processar ou resolver erros de codificação depende da situação específica.

Considere um pequeno exemplo de arquivo que contém um caractere UTF-8 inválido e veja como esse caractere é processado em modos diferentes. Primeiro escreva o arquivo usando bytes e modo binário:

>>> open('test.txt', 'wb').write(bytes([65, 66, 67, 255, 192,193])) 

Como resultado do comando, um arquivo é criado a partir dos caracteres "ABC", seguidos por três caracteres que não estão incluídos no ASCII, que podem ser exibidos de maneira diferente, dependendo do método de codificação usado. Se você usar o vim para visualizar o arquivo, o resultado será semelhante a este:

 ABCÿÀÁ ~ 


Quando o arquivo é criado, tente lê-lo no modo padrão de tratamento de erros estritos:

 >>> x = open('test.txt').read() Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/lib/python3.6/codecs.py", line 321, in decode (result, consumed) = self._buffer_decode(data, self.errors, final) UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 3: invalid start byte 


O quarto byte com um valor de 255 não é um caractere UTF-8 válido nessa posição; portanto, uma exceção ocorre no modo 'estrito'. Agora, vamos ver como outros modos de tratamento de erros lidam com o mesmo arquivo, sem esquecer que os três últimos caracteres acionam um erro:

imagem

Se você quiser que os caracteres problemáticos desapareçam, use o modo 'ignorar'. O modo 'substituir' marca apenas as posições de caracteres inválidos, enquanto outros modos tentam de maneira diferente salvar caracteres inválidos sem interpretação.

21.2.2 Texto não estruturado


Arquivos de texto não estruturados são lidos da maneira mais fácil, mas também criam mais problemas com a extração de informações. O processamento de texto não estruturado pode variar muito, dependendo da natureza do texto e do que você fará com ele, portanto, qualquer discussão detalhada sobre o processamento de texto está além do escopo do livro. No entanto, um pequeno exemplo ajudará a demonstrar alguns problemas básicos e estabelecerá as bases para discutir arquivos com dados de texto estruturados.

Um dos problemas mais simples é escolher a unidade lógica básica no arquivo. Se você usar uma coleção de milhares de mensagens no Twitter, textos sobre Moby Dick ou uma coleção de notícias, precisará dividi-las de alguma forma. No caso de tweets, cada bloco pode ser colocado em uma linha e a leitura e o processamento de cada linha do arquivo são organizados de maneira bastante simples.

No caso de Moby Dick e até de algumas notícias, o problema está ficando mais complicado. Obviamente, o texto do romance e até o texto das notícias são geralmente indesejáveis ​​como uma única unidade. Nesse caso, você precisa decidir de quais blocos precisa e depois desenvolver uma estratégia para dividir o arquivo em blocos. Você pode preferir processar o texto parágrafo por parágrafo. Nesse caso, você deve determinar como a discriminação do texto em parágrafos no arquivo é organizada e escrever o código adequadamente. Se os parágrafos corresponderem às linhas de um arquivo de texto, isso não será difícil. No entanto, geralmente um parágrafo de um arquivo de texto pode consistir em várias linhas em um arquivo de texto, e você terá que trabalhar duro.

Agora considere alguns exemplos.

Me chame de Ismael. Alguns anos atrás - não importa quanto tempo precisamente--
tendo pouco ou nenhum dinheiro na minha bolsa e nada em particular
para me interessar na praia, pensei em navegar um pouco
e ver a parte aquosa do mundo. É uma maneira que eu tenho
de expulsar o baço e regular a circulação.
Sempre que me vejo cada vez mais sombrio na boca;
sempre que há um novembro úmido e chuvoso em minha alma; sempre que eu
me vejo involuntariamente fazendo uma pausa diante de armazéns de caixões,
e trazendo os fundos de todos os funerais que encontro;
e, especialmente, sempre que meus hipopótamos me superam,
que exige um forte princípio moral para me impedir de
deliberadamente entrando na rua e batendo metodicamente
tirar o chapéu das pessoas - então, considero que é hora de chegar ao mar
assim que eu puder. Este é o meu substituto para pistola e bola.
Com um floreio filosófico, Cato se joga sobre a espada;
Eu discretamente levo para o navio. Não há nada de surpreendente nisso.
Se eles soubessem disso, quase todos os homens em seu nível, algum tempo
ou outro, aprecie quase os mesmos sentimentos em relação a
o oceano comigo.

Agora existe a sua cidade insular dos Manhattoes, cercada por cais
como ilhas indianas por recifes de coral - o comércio o rodeia com suas ondas.
Direita e esquerda, as ruas levam você à água. Seu centro extremo
é a bateria, onde essa nobre toupeira é lavada por ondas e resfriada
pela brisa, que poucas horas antes estavam fora da vista da terra.
Olhe para a multidão de observadores de água lá.

Neste exemplo (com o início do texto "Moby Dick"), as linhas são quebradas mais ou menos da maneira como seriam paginadas e os parágrafos são indicados por uma única linha vazia. Se você deseja tratar cada parágrafo como um todo, é necessário dividir o texto em linhas em branco. Felizmente, essa tarefa é facilmente realizada pelo método split () de strings. Cada nova linha no texto é representada pela combinação "\ n". Naturalmente, a última linha do texto de cada parágrafo termina com uma nova linha e, se a próxima linha estiver vazia, a segunda nova linha imediatamente a seguir:

imagem

A análise de texto em parágrafos é uma etapa muito simples no processamento de texto não estruturado. Você também pode precisar executar uma normalização adicional do texto antes de continuar o processamento. Suponha que você queira calcular a frequência de ocorrência de cada palavra em um arquivo de texto. Se você simplesmente dividir o arquivo por omissões, obterá uma lista de palavras no arquivo; no entanto, não será tão fácil calcular com precisão as ocorrências, porque Isto, isto, isto. e isso não será considerado a mesma palavra. Para que esse código funcione corretamente, é necessário normalizar o texto removendo sinais de pontuação e convertendo todo o texto em um caso antes do processamento. No exemplo de texto acima, o código para construir uma lista normalizada de palavras pode ser assim:

imagem

21.2.3 Arquivos delimitados não estruturados


Arquivos não estruturados são lidos com muita simplicidade, mas a falta de estrutura também é sua desvantagem. Geralmente é mais conveniente definir alguma estrutura para um arquivo, a fim de simplificar a seleção de valores individuais. Na versão mais simples, o arquivo é dividido em linhas e cada linha contém um elemento de informação. Por exemplo, pode ser uma lista de nomes de arquivos para processamento, uma lista de nomes de pessoas ou uma série de leituras de temperatura de um sensor remoto. Nesses casos, a análise dos dados é organizada de maneira muito simples: você lê a linha e, se necessário, converte-a no tipo desejado. É o suficiente para preparar o arquivo para uso.

No entanto, a situação não é tão simples. Com mais freqüência, você precisa agrupar vários elementos de dados interconectados e seu código deve lê-los juntos. Normalmente, para isso, os dados relacionados são colocados em uma linha e separados por um caractere especial. Nesse caso, ao ler cada linha do arquivo, caracteres especiais são usados ​​para dividir os dados em campos e armazenar os valores dos campos em variáveis ​​para processamento adicional.

O seguinte arquivo contém dados de temperatura em um formato delimitado:

 State|Month Day, Year Code|Avg Daily Max Air Temperature (F)|Record Count for Daily Max Air Temp (F) Illinois|1979/01/01|17.48|994 Illinois|1979/01/02|4.64|994 Illinois|1979/01/03|11.05|994 Illinois|1979/01/04|9.51|994 Illinois|1979/05/15|68.42|994 Illinois|1979/05/16|70.29|994 Illinois|1979/05/17|75.34|994 Illinois|1979/05/18|79.13|994 Illinois|1979/05/19|74.94|994 

Os dados no arquivo são separados por um canal (|). Neste exemplo, eles consistem em quatro campos: estado, data de observação, temperatura máxima média e número de estações que fornecem dados. Outros delimitadores padrão são um caractere de tabulação e uma vírgula. Talvez a vírgula seja usada com mais frequência, mas o separador pode ser qualquer caractere que não ocorra nos valores (mais sobre isso posteriormente). Dados separados por vírgula são tão comuns que esse formato geralmente é chamado de CSV (valores separados por vírgula), ou seja, dados separados por vírgula) e esse tipo de arquivo é fornecido com a extensão .csv como um atributo de formato.

Qualquer que seja o caractere usado como delimitador, se você souber qual é o caractere, poderá escrever seu próprio código Python para dividir a string em campos e retorná-los como uma lista. No caso anterior, você pode usar o método split () para converter a string em uma lista de valores:

 >>> line = "Illinois|1979/01/01|17.48|994" >>> print(line.split("|")) ['Illinois', '1979/01/01', '17.48', '994'] 

Essa técnica é muito fácil de implementar, mas todos os valores são armazenados na forma de sequência e isso pode ser inconveniente para o processamento subsequente.

21.2.4 Módulo csv


Se você costuma processar arquivos de dados delimitados, deve examinar mais de perto o módulo csv e seus recursos. Quando me pediram para nomear meu módulo favorito da biblioteca padrão do Python, chamei o módulo csv mais de uma vez - não porque parece espetacular (não é), mas porque provavelmente me salvou mais tempo e me salvou dos meus erros em potencial com mais frequência do que qualquer outro módulo.
O módulo csv é o exemplo perfeito da filosofia de "bateria incluída" do Python. Embora você possa escrever perfeitamente seu próprio código para ler arquivos delimitados (além disso, não é tão difícil), é muito mais fácil e confiável usar o módulo Python. O módulo csv foi testado e otimizado e fornece vários recursos que você dificilmente conseguiria implementar, mas que são bastante convenientes e economizam tempo.

Dê uma olhada nos dados anteriores e decida como você os leria com o módulo csv. O código de análise de dados deve ler cada linha e remover o caractere de nova linha à direita e depois dividir a linha por caracteres | e acrescente a lista de valores à lista geral de cadeias. A solução pode ser algo como isto:

 >>> results = [] >>> for line in open("temp_data_pipes_00a.txt"): ... fields = line.strip().split("|") ... results.append(fields) ... >>> results [['State', 'Month Day, Year Code', 'Avg Daily Max Air Temperature (F)', 'Record Count for Daily Max Air Temp (F)'], ['Illinois', '1979/01/01', '17.48', '994'], ['Illinois', '1979/01/02', '4.64', '994'], ['Illinois', '1979/01/03', '11.05', '994'], ['Illinois', '1979/01/04', '9.51', '994'], ['Illinois', '1979/05/15', '68.42', '994'], ['Illinois', '1979/ 05/16', '70.29', '994'], ['Illinois', '1979/05/17', '75.34', '994'], ['Illinois', '1979/05/18', '79.13', '994'], ['Illinois', '1979/05/19', '74.94', '994']] 

Se você quiser fazer o mesmo com o módulo csv, o código pode ser algo como isto:

 >>> import csv >>> results = [fields for fields in csv.reader(open("temp_data_pipes_00a.txt", newline=''), delimiter="|")] >>> results [['State', 'Month Day, Year Code', 'Avg Daily Max Air Temperature (F)', 'Record Count for Daily Max Air Temp (F)'], ['Illinois', '1979/01/01', '17.48', '994'], ['Illinois', '1979/01/02', '4.64', '994'], ['Illinois', '1979/01/03', '11.05', '994'], ['Illinois', '1979/01/04', '9.51', '994'], ['Illinois', '1979/05/15', '68.42', '994'], ['Illinois', '1979/ 05/16', '70.29', '994'], ['Illinois', '1979/05/17', '75.34', '994'], ['Illinois', '1979/05/18', '79.13', '994'], ['Illinois', '1979/05/19', '74.94', '994']] 

Nesse caso simples, o ganho comparado à implementação independente da solução não é tão grande. No entanto, o código acabou sendo duas linhas mais curtas e um pouco mais claras, e você não precisa se preocupar em cortar caracteres de nova linha. A verdadeira vantagem surge quando você enfrenta casos mais complexos.

Os dados neste exemplo são reais, mas na realidade foram simplificados e limpos. Dados reais da fonte serão mais complexos. Os dados reais contêm mais campos, alguns campos serão colocados entre aspas, outros não, e o primeiro campo pode estar vazio. O original é separado por tabulações, mas, para fins de demonstração, cito-os separados por vírgulas:

 "Notes","State","State Code","Month Day, Year","Month Day, Year Code",Avg Daily Max Air Temperature (F),Record Count for Daily Max Air Temp (F),Min Temp for Daily Max Air Temp (F),Max Temp for Daily Max Air Temp (F),Avg Daily Max Heat Index (F),Record Count for Daily Max Heat Index (F),Min for Daily Max Heat Index (F),Max for Daily Max Heat Index (F),Daily Max Heat Index (F) % Coverage ,"Illinois","17","Jan 01, 1979","1979/01/ 01",17.48,994,6.00,30.50,Missing,0,Missing,Missing,0.00% ,"Illinois","17","Jan 02, 1979","1979/01/02",4.64,994,- 6.40,15.80,Missing,0,Missing,Missing,0.00% ,"Illinois","17","Jan 03, 1979","1979/01/03",11.05,994,- 0.70,24.70,Missing,0,Missing,Missing,0.00% ,"Illinois","17","Jan 04, 1979","1979/01/ 04",9.51,994,0.20,27.60,Missing,0,Missing,Missing,0.00% ,"Illinois","17","May 15, 1979","1979/05/ 15",68.42,994,61.00,75.10,Missing,0,Missing,Missing,0.00% ,"Illinois","17","May 16, 1979","1979/05/ 16",70.29,994,63.40,73.50,Missing,0,Missing,Missing,0.00% ,"Illinois","17","May 17, 1979","1979/05/ 17",75.34,994,64.00,80.50,82.60,2,82.40,82.80,0.20% ,"Illinois","17","May 18, 1979","1979/05/ 18",79.13,994,75.50,82.10,81.42,349,80.20,83.40,35.11% ,"Illinois","17","May 19, 1979","1979/05/ 19",74.94,994,66.90,83.10,82.87,78,81.60,85.20,7.85% 

Observação: alguns campos incluem vírgulas. De acordo com as regras nesses casos, o campo é colocado entre aspas para indicar que seu conteúdo não se destina a analisar e procurar delimitadores. Na prática (como neste caso), apenas uma fração dos campos geralmente é colocada entre aspas, especialmente aquelas cujos valores podem conter um separador. No entanto (como novamente neste exemplo), alguns campos são colocados entre aspas, mesmo quando é improvável que contenham um separador.

Nesses casos, as soluções domésticas se tornam muito complicadas. Agora, apenas quebrar uma linha por um caractere delimitador não funciona mais; você precisa se certificar de usar apenas os separadores que não estão dentro das cadeias. Além disso, você deve remover as aspas, que podem estar em uma posição arbitrária ou não encontradas em nenhum lugar. Com o módulo csv, você não precisa alterar seu código. Além disso, como a vírgula é considerada o separador padrão, ela nem precisa ser especificada:

 >>> results2 = [fields for fields in csv.reader(open("temp_data_01.csv", newline=''))] >>> results2 [['Notes', 'State', 'State Code', 'Month Day, Year', 'Month Day, Year Code', 'Avg Daily Max Air Temperature (F)', 'Record Count for Daily Max Air Temp (F)', 'Min Temp for Daily Max Air Temp (F)', 'Max Temp for Daily Max Air Temp (F)', 'Avg Daily Min Air Temperature (F)', 'Record Count for Daily Min Air Temp (F)', 'Min Temp for Daily Min Air Temp (F)', 'Max Temp for Daily Min Air Temp (F)', 'Avg Daily Max Heat Index (F)', 'Record Count for Daily Max Heat Index (F)', 'Min for Daily Max Heat Index (F)', 'Max for Daily Max Heat Index (F)', 'Daily Max Heat Index (F) % Coverage'], ['', 'Illinois', '17', 'Jan 01, 1979', '1979/01/01', '17.48', '994', '6.00', '30.50', '2.89', '994', '-13.60', '15.80', 'Missing', '0', 'Missing', 'Missing', '0.00%'], ['', 'Illinois', '17', 'Jan 02, 1979', '1979/01/02', '4.64', '994', '-6.40', '15.80', '-9.03', '994', '-23.60', '6.60', 'Missing', '0', 'Missing', 'Missing', '0.00%'], ['', 'Illinois', '17', 'Jan 03, 1979', '1979/01/03', '11.05', '994', '- 0.70', '24.70', '-2.17', '994', '-18.30', '12.90', 'Missing', '0', 'Missing', 'Missing', '0.00%'], ['', 'Illinois', '17', 'Jan 04, 1979', '1979/01/04', '9.51', '994', '0.20', '27.60', '-0.43', '994', '-16.30', '16.30', 'Missing', '0', 'Missing', 'Missing', '0.00%'], ['', 'Illinois', '17', 'May 15, 1979', '1979/05/15', '68.42', '994', '61.00', '75.10', '51.30', '994', '43.30', '57.00', 'Missing', '0', 'Missing', 'Missing', '0.00%'], ['', 'Illinois', '17', 'May 16, 1979', '1979/05/ 16', '70.29', '994', '63.40', '73.50', '48.09', '994', '41.10', '53.00', 'Missing', '0', 'Missing', 'Missing', '0.00%'], ['', 'Illinois', '17', 'May 17, 1979', '1979/05/17', '75.34', '994', '64.00', '80.50', '50.84', '994', '44.30', '55.70', '82.60', '2', '82.40', '82.80', '0.20%'], ['', 'Illinois', '17', 'May 18, 1979', '1979/05/18', '79.13', '994', '75.50', '82.10', '55.68', '994', '50.00', '61.10', '81.42', '349', '80.20', '83.40', '35.11%'], ['', 'Illinois', '17', 'May 19, 1979', '1979/05/19', '74.94', '994', '66.90', '83.10', '58.59', '994', '50.90', '63.20', '82.87', '78', '81.60', '85.20', '7.85%']] 


»Mais informações sobre o livro podem ser encontradas no site do editor
» Conteúdo
» Trecho

Cupom de 20% de desconto para vendedores ambulantes - Python

Source: https://habr.com/ru/post/pt437050/


All Articles