<jupyter_start><jupyter_text>Aula 2 - Fundamento do Python**O que vamos aprender nesta aula?**- tipos de variáveis- tipos de estruturas de dados- estruturas de repetição (loops) e desvios condicionais (statements)- operadores aritméticos, relacionais/condicionais e lógicosSugestões:- muitas informações;- anotem dúvidas (que surgirão);- revejam este material no dia seguinte à aula;- pratiquem;- consultem materiais sugeridos;Pratiquem (de novo):- desenvolvimento em programação ocorrerá com prática;- dúvidas? pesquisem e perguntem.Material de apoio para esta aula:- Documentação do python possui um tutorial bem interessante: https://docs.python.org/pt-br/3.7/tutorial/- Convenção de nomes de variáveis e boas normas de programação: https://www.python.org/dev/peps/pep-0008/naming-conventions- Material sobre estruturas de dados: https://docs.python.org/3/tutorial/datastructures.html  Atribuição (assignment)Dentre todas as linhas de um código, a **atribuição** ocorre talvez em uns 75% (se não mais) linhas deste código. Isto porque este comando é utilizado para inserir um valor à uma variável, ou seja, atribuir um valor a uma variável. Isto independe da variável que estamos definindo, a sintaxe será sempre a mesma. Usamos o operador de atribuição =```pythonx = 10```Além disso, durante o desenvolvimento de um código, precisaremos sempre comentar algumas informações sobre as ações que o código deve fazer, que tipo de informação deve ser utilizada para que seu código funcione ou simples colocar seu nome no começo do código dizendo que foi você quem fez. Para isso, utiliza-se o símbolo :```python isso é um comentário e, portanto, não será rodado pelo pythn```  Variáveis**Tipos de variáveis**- int (integer): valores numérics inteiros    - ```python        x = 3    ```    - float: valores numéricos decimais    - ```python        pi = 3.14    ```    - str: (string): valores textuais (**devem** estar entre aspas, simples ou duplas)    - ```python        PI = "3.14"    ```    - bool (boolean): valores binários (True/False ou 1/0)    - ```python        boolean_true = True        ```    - ```python        boolean_false = False        ```     - complex: números complexos    - ```python        x = 3.14 + ij        ``` Alguns exemplos práticos:<jupyter_code># tudo que vem depois do # é um comentário e não é processado pelo python
# integer
x = 3

# para visualizar o que é a variável, use o print
print(x)
type(x)
# float
pi = 3.14

print(pi)
type(pi)
# string

texto1 = "3.14"

print(texto1)
type(texto1)
boolean_true = True
boolean_false = False

print(boolean_true)
type(boolean_true)<jupyter_output>True<jupyter_text>Algumas recomendações- valores booleanos devem ser, obrigatoriamente, com a primeira letra maiúscula (True ou False). Qualquer coisa diferente disso, o python procurará por variáveis com este nome- existe uma convenção para os nomes das variáveis, mas no geral use nomes que expliquem o que a variável é de fato:```python    x = 3.14    pi = 3.14``` Palavras reservadas- existem palavras **reservadas** no python, que são usadas pela linguagem de programação durante o processamento do código. Exemplos:|   and  |  assert | break | class | continue ||:------:|:-------:|:-----:|:-----:|:--------:|| def    | del     | elif  | else  | except   || exec   | finally | for   | from  | global   || if     | import  | in    | is    | lambda   || not    | or      | pass  | print | raise    || return | try     | while | enumerate|          | Outro grupo de palavras a não serem usadas como |   data  |  float | int | numeric | array |||:------:|:-------:|:-----:|:-----:|:--------:||| array   | open | range   | type  | write   | zeros |A grande função destas palavras é que elas constituem funções nativas do python, isto é, possuem uma aplicação específica. Veremos ao longo do curso diversos exemplos.Sugestão de leitura para entender a convenção dos nomes das variáveis:https://www.python.org/dev/peps/pep-0008/naming-conventions<jupyter_code># tentando atribuir um novo valor booleano, mas com tudo minúsculo
boolean_true = true<jupyter_output><empty_output><jupyter_text>**palavras reservadas - exemplos práticos**<jupyter_code>True = 'variavel'
else = 'senao'
true = 'variavel'
print(true)
boolean = True # pode ser falso

print(boolean)<jupyter_output>True<jupyter_text>Operadores básicosAgora que entendemos um pouco sobre variáveis, vamos aprender a usá-las efetivamente para realizar operações. Para isso, precisamos conhecer os símbolos que realizam as operações matemáticas com as nossas variáveis:| Símbolo |      Função      ||:-------:|:----------------:|| +       | adição           || -       | subtração        || *       | multiplicação    || /       | divisão          || %       | resto da divisão || **      | potência         |Importante ressaltar que o uso de parênteses determina a ordem que as operações são realizadas.Vejamos alguns exemplos, mas antes:**Nota**: se, quando estiver trabalhando em um IDE ou jupyter notebook, você realizar alguma operação sem atribuir a uma variável, o resultado da operação será impresso na tela.<jupyter_code>pi + pi
2 * pi
# podemos realizar operações com inteiros e decimais:

x / pi<jupyter_output><empty_output><jupyter_text>Operações com textosPodemos definir uma string de diversas formas. Usando:``` t = 'com aspas simples'`````` t = "com aspas duplas"`````` t = """com aspas triplas"""```<jupyter_code>texto_novo = """Estamos aprendendo o básico de python"""

print(texto_novo)<jupyter_output>Estamos aprendendo o básico de python<jupyter_text>Strings podem ser "fatiadas" (slice) para selecionarmos caractereses específicos. Isso é feito através do uso de índices:<jupyter_code># print da primeira letra da nossa string
texto_novo[0]
# print de um pedaço da nossa string
texto_novo[31:]<jupyter_output><empty_output><jupyter_text>Embora possamos acessar os elementos da string, nós **não** podemos substituir algum elemento específico. Se tentarmos, o seguinte erro surgirá:<jupyter_code>texto_novo[0] = 'A'<jupyter_output><empty_output><jupyter_text>Será que conseguimos realizar operações aritméticas com strings?<jupyter_code>2 * texto1<jupyter_output><empty_output><jupyter_text>Neste caso, o python é esperto para entender que você deseja multiplicar o texto contido na variável. Mas e se tentar alguma subtração ou adição?<jupyter_code>2 + texto1<jupyter_output><empty_output><jupyter_text>Ele não realiza, pois somar/subtrair só é permitido entre variáveis que sejam números (inteiros ou decimais) ou textos (strings):<jupyter_code>print(texto1 + texto1)
print(2 * texto1)<jupyter_output>3.143.14
3.143.14<jupyter_text>No entanto, se a sua variável contendo um texto representar algum valor numérico (ex: ``` y = '100'```, você pode converter seu texto em valores numéricos e realizar alguma operação:<jupyter_code>y = '100'

print(x + int(y))
print(x + float(y))<jupyter_output>103
103.0<jupyter_text>No caso acima, realizamos a operação aritmética utilizando duas funções nativas do python que converte nossa variável para o tipo que queremos:- ```int``` - ```float```Isso também serve para ```str``` e ```bool```:<jupyter_code>print(str(11))
print(bool(1))<jupyter_output>11
True<jupyter_text>Estruturas de dadosEstrutura de dados são consideradas formas de armazenar uma coleção de variáveis. No python, temos disponíveis três tipos básicos de estruturas, chamadas de: **lists**, **tuples**, **dictionaries** e **sets**.Estes tipos de estruturas colecionam variáveis de forma arbitrária. Isto quer dizer que podemos colocar em uma mesma estrutura diversos tipos de variáveis, inclusive outras estruturas de dados.Porém, cada uma possui suas particularidades e vamos compreender um pouco mais.  Listas (list)- cria-se com []```python    lista = ['valor1', 10, 'valor3']```- acesso via indexamento (indexing)```python    lista[0]```- indexação inicia em 0 -> n-1, sendo n a quantidade de elementos- matlab: começa em 1 -> n, então tomem cuidado- indexação funciona com números negativos, pegando a partir o último```python    lista[-1]```- provavelmente a que mais será usada durante o desenvolvimento de um algoritmo<jupyter_code># criando uma lista:
lista = ['primeiro item tem índice 0', 100.10, ['outra lista', 'também rola']]

# tamanho da nossa lista usando a função nativa len, de length:
n = len(lista)

print(f"Nossa lista possui: {n} elementos que são:") # opa, coisa nova!
print(lista)
print(f"Qual o índice do primeiro item? {lista[0]}")<jupyter_output>O primeiro elemento possui índice 0: primeiro item tem índice 0<jupyter_text>conseguimos acessar o último elemento usando n?  Por que não?<jupyter_code>lista[n]
# print dos dois primeiros itens (de 0 a 2, porém 2 não está incluso)
print(lista[0:2])
# podemos omitir o 0 neste caso, mas se quisermos a partir do elemento 1, não.
print(lista[:2])<jupyter_output>['primeiro item tem índice 0', 100.1]<jupyter_text>Podemos substituir elementos, através de seus índices:<jupyter_code>lista[0] = 'mudei o valor do primeiro elemento'

print(lista)<jupyter_output>['mudei o valor do primeiro elemento', 100.1, ['outra lista', 'também rola']]<jupyter_text>Realizar cópia de listas pode parecer algo simples, mas aqui tem uma pegadinha no python.Se fizermos simplesmente uma cópia através da atribuição da nossa lista à uma outra variável:```nova_lista = lista```vamos ter alguns problemas, pois neste caso o python duplicou a lista, mas ambas apontam para a mesma alocação de memória do seu computador. Assim, se fizermos alguma operação na lista nova, esta alteração se reflete na nossa lista original. Vamos ver isso na prática:<jupyter_code># exemplo de cópia "rasa" (shallow copy)
nova_lista = lista

print(lista)
print(nova_lista)
nova_lista[0] = 'primeiro item tem índice 0'

print(lista)
print(nova_lista)<jupyter_output>['primeiro item tem índice 0', 100.1, ['outra lista', 'também rola']]
['primeiro item tem índice 0', 100.1, ['outra lista', 'também rola']]<jupyter_text>Para resolver este problema, fazemos uma cópia "profunda", forçando o python da seguinte forma:<jupyter_code># exemplo de cópia profunda (deep copy)
nova_lista = lista[:]

nova_lista[0] = 'mudei o valor do primeiro elemento'

print(lista)
print(nova_lista)<jupyter_output>['primeiro item tem índice 0', 100.1, ['outra lista', 'também rola']]
['mudei o valor do primeiro elemento', 100.1, ['outra lista', 'também rola']]<jupyter_text>Métodos de listasVamos falar de alguns métodos muito úteis das nossas listas, mas que funcionamente __somente__ para listas.- **.append(novo_valor)**: para adicionarmos um novo elemento à nossa lista- **.count(valor)**: retorna quantas vezes o elemento enviado como argumento para o método ocorre dentro da lista:- **.insert(arg1, arg2)**: insere um novo valor em uma posição específica da lista. O primeiro argumento é o índice e o segundo o valor- **.sort()**: ordena a lista em ordem crescente. Mas só funciona se tivermos homogeneidade dos tipos de variáveis dentro da lista- **.index()**: retorna o índice do elemento que enviamos como argumento.<jupyter_code>lista.append('novo valor no final')

print(lista)
print(lista.count(100.1))
lista.insert(0,0)
print(lista)
print(lista.index(100.1))
print(lista.sort())<jupyter_output><empty_output><jupyter_text>Tuplas (tuple)- cria-se com ()```python    tupla = (1,2,3, 'texto', ['lista', 'tambem'])```- são imutáveis, isto é, ao contrário das listas não podemos alterar os valores- muito utilizada para transmitir informações estáticas dentro de um código- Ex: coordenadas geográficas para plotar em um mapa.<jupyter_code>coords = (-44.460789, -23.006711)

print(coords)
type(coords)
print(coords[0])
tupla[0] = 0<jupyter_output><empty_output><jupyter_text>Dicionários (dict)- cria-se com {} ou com ```dict```:```python    dicionario = {}    dicionario = dict([(key, value)])```- obrigatório o uso do conceito de chaves e valores- acesso é feito via chaves- as chaves devem ser únicas no dicionário!<jupyter_code># criando dicionário da primeira forma
dicionario = {}

# adicionando informações dentro de um dicionário já existente
dicionario['nova-chave'] = ['novo', 'valor', 'aqui']

dicionario
type(dicionario)<jupyter_output><empty_output><jupyter_text>Atribui-se uma chave a um valor, podendo ser qualquer valor (lista, string, tupla, variável).Vamos construir um dicionário utilizando as coordenadas das estaçoes automáticas do CPTEC:<jupyter_code># criando dicionário da segunda forma, para duas estações meteorológias do CPTEC e suas coordenadas geográficas
estAutomaticas = {
    'A701': (-23.496294, -46.620088),
    'A728': (-23.041668, -45.520841)
}

estAutomaticas
type(dicionario2)<jupyter_output><empty_output><jupyter_text>Pode-se acessar os valores utilizando as chaves:<jupyter_code>print(estAutomaticas['A701'])
estAutomaticas['A000'] = (-23.041668, -45.520841)
estAutomaticas.keys()
estAutomaticas. # tab to consult methods available
estAutomaticas.items()<jupyter_output><empty_output><jupyter_text>SetsSet é uma estrutura de dados não ordenadas e imutáveis sem valores duplicados.- criada com {} ou usando ```set()```:```python    especies = set([...])```<jupyter_code>S = set(['3.0', 1, 0.1, '3', 1.0])
S<jupyter_output><empty_output><jupyter_text>Note que:- a ordem foi alterada automaticamente quando criamos o set- veja o que ocorre com os valores duplicados  Métodos importantes- Podemos usar:    - **.copy()**    - **.add()**    - **.intersection()**    - **.difference()**    - **.clear()**- mais informações sobre set: https://www.python-course.eu/python3_sets_frozensets.php<jupyter_code># criando um set com nomes populares de peixes
nomes_populares = set(['tilápia', 'dourado', 'carpa', 'pintado'])
nomes_populares<jupyter_output><empty_output><jupyter_text>Podemos também realizar cópias usando o método ```.copy()```, porém neste caso é feita uma cópia independente, diferente das listas.<jupyter_code>nomes_populares_copia = nomes_populares.copy()

nomes_populares_copia<jupyter_output><empty_output><jupyter_text>Podemos adicionar novos elementos a um set e a ordenação é feita automaticamente:<jupyter_code># não precisa atribuir à uma variável nova
nomes_populares.add('tambaqui')

print(nomes_populares)
print(nomes_populares_copia)<jupyter_output>{'carpa', 'dourado', 'pintado', 'tilápia', 'tambaqui'}
{'dourado', 'tilápia', 'pintado', 'carpa'}<jupyter_text>Ainda, podemos descobrir qual a diferença e a intersecção entre dois sets:<jupyter_code>nomes_populares.difference(nomes_populares_copia)
nomes_populares.intersection(nomes_populares_copia)<jupyter_output><empty_output><jupyter_text>Finalmente, podemos limpar um set com:<jupyter_code>nomes_populares_copia.clear()
nomes_populares_copia<jupyter_output><empty_output><jupyter_text>----------  Blocos de códigoBlocos de código indicam à linguagem de programação instruções que estão dentro ou fora de uma estrutura (repetição, desvios, função, etc). Cada linguagem de programação oferece uma forma de determinar blocos de código, no caso do python usamos a **identação** (4 espaços a esquerda). Isso é muito bom, pois o código fica legível para "lermos" mais facilmente.Um exemplo (real):```python dias para plotardias = ['2020-01-01', '2020-01-02', '2020-01-03'] loop nos diasfor dia in dias:     condição para plotar apenas dados de 2020    if(dia[:5] == '2020'):        print('Ano de 2020')        ds.isel(time=dia).sst.plot.pcolormesh(x='lon', y='lat')```Percebam que existem dois 3 níveis de identação neste pequeno trecho de código:- nível 1: aonde defino minha lista de dias e começo a definidr meu loop for (vamos entender o que é esse tal loop já já)- nível 2: aonde defino minha condição if (vamos entender em breve)- nível 3: aonde, efetivamente, executamos algum código. No caso seria plotar um mapa de temperatura da superfície do mar que veremos nas próximas semanas como fazer.<jupyter_code># E se errarmos a identação?
dias = ['2020-01-01', '2020-01-02', '2020-01-03']

for dia in dias:
    if(dia[:5] == '2020'):
    print(dia)<jupyter_output><empty_output><jupyter_text>Estruturas (loops) de repetiçãoLembrando da última aula, durante a elaboração de um diagrama de blocos, nós vimos que às vezes podemos fazer repetições no código (chamamos de loop), de modo a testar expressões matemáticas até que algo aconteça e possamos sair deste loop.Vamos ver um pouco mais estas estruturas, estes loops, no python.Basicamente, temos 2 tipos (alguns dirão 3) mais utilizados no desenvolvimento em python: **for** e **while** (**while...else**).Entendendo um pouco melhor a sintaxe de cada estrutura: ```python    for item in lista:         serie de códigos que acontecerão enquanto o for estiver ativado        print('estamos dentro de um loop de repetição for')            while(expressao):        print('estamos dentro de um loop de repetição while')```Note que, para que estruturas de repetição funcionem, precisamos usar duas coisas importantíssimas (e razões de muitos códigos que dão erro):- dois ponto (:) após a definição da expressão- precisamos identar o código que será rodado dentro do loopAs duas estruturas são iterativas, isto é, realizam uma sequência de comandos. No entanto, a estrutura **for** nos permite acessar sequencialmente os items de uma lista, sem precisar sabermos o índice deles, e aplicar um determinado código em cima deste valor. Enquanto que a estrutura **while** nos permite rodar o mesmo bloco de código, até que uma condição, uma expressão matemática, seja satisfeita.Exemplos aleatórios:<jupyter_code>for x in ['estamos', 'na', 'segunda', 'aula', 'do', 'curso']:
    print(x)
string = 'string'
for s in string:
    print(s)<jupyter_output>s
t
r
i
n
g<jupyter_text>Podemos aplicar um **for** em uma string!![image.png](../figures/mind-blow.gif)  Desvios condicionais (statement) Da mesma forma que estruturas de repetição, podemos criar Desvios condicionais que são testes básicos do tipo "se...senão" (**if**, **elif**, **else**), que podemos utilizar no código para só fazer determinada ação se uma expressão for verdadeira.A sintaxe básica é: Importante ressaltar que os desvios condicionais podem ser classificados como: simples, compostos e encadeados. No primeiro caso, bastaria utilizarmos:```pythonif expressao:    print('desvio simples')```Já no segundo caso, precisamos complementar com:```pythonif expressao:    print('desvio composto')else:    print('expressao não é verdadeira')```Já no terceiro, utilizamos a sintaxe completa do desvio:```pythonif expressao1:    print('expressao 1 foi atendida')elif expressao2:    print('expressao 2 foi atentida, mas somente porque a primeira não foi')else:    print('nenhuma expressao atendida')``` Pratique com a célula abaixo, variando as variáveis ```expressao1``` e ```expressao2``` entre ```True``` e ```False```.<jupyter_code>expressao1 = False
expressao2 = False

if expressao1:
    print('expressao 1 foi atendida')
elif expressao2:
    print('expressao 2 foi atentida, mas somente porque a primeira não foi')
else:
    print('nenhuma expressao atendida')<jupyter_output><empty_output><jupyter_text>Da mesma forma que podemos rodar uma estrutura de repetição em uma string, também podemos utilizar os desvios condicionais para pesquisar por sequências específicas de caracteres:<jupyter_code>variavel = 'python'

if 'yth' in variavel:
    print(True)<jupyter_output>True<jupyter_text>Operadores condicionais e lógicosAntes de vermos exemplos práticos destas estruturas, precisamos entender o conceito da expressão matemática que vamos inserir como condição para que o loop rode.Para isso, inserimos novos operadores (**operadores condicionais**):| Símbolo |      Função      ||:-------:|:----------------:|| ==      | igual            || !=      | diferente        || >       | maior que        || <       | menor que        || >=      | maior ou igual a || <=      | menor ou igual a |Nós tambéms podemos combinar condições, usando operadores lógicos:- **not**: negação- **and**: conjunção- **or**: disjunçãoNeste caso, é preciso compreender o que será retornado pelo teste combinado das condições, pois isto pode acarretar em um erro de lógica e seu código não funcionará da forma como você gostaria. | Expressão 1 | operador lógico | Expressão 2 | resultado lógico ||-------------|-----------------|-------------|------------------|| True        | and             | True        | True             || True        | and             | False       | False            || False       | and             | True        | False            || False       | and             | False:      | True             || True        | or              | True        | True             || True        | or              | False       | True             || False       | or              | True        | True             || False       | or              | False:      | False            |Percebam que o uso correto do operador lógico é de fundamental importância para que possamos ter a combinação correta como resposta deste teste.<jupyter_code># testando
True and False<jupyter_output><empty_output><jupyter_text>Combinando, agora, os operadores condicionais e lógicos para testes complexos reais, podemos testar:```A é igual a B e C é igual a D?``````python((A==B) and (C==D))``````A é igual a B e C é diferente a D?``````python((A==B) and (C!=D))```  Vamos aos exemplosAgora com essas novas ferramentas em mãos, podemos criar exemplos reais de aplicações das estruturas de repetição! Podemos utilizar a estrutura ```for``` para iterar em uma sequência de números ou variáveis, para realizar alguma ação:<jupyter_code># nova função nativa: range
for i in range(10):
    print(i)<jupyter_output>0
1
2
3
4
5
6
7
8
9<jupyter_text>![image.png](../figures/loops-repeticao.png)<jupyter_code>ponto_ebulicao = 100 # graus Celsius

temperatura_agua = 20 # graus Celsius, temperatura ambiente

# enquanto a temperatura da agua for menor ou igual ao ponto de ebulição, continuamos a aquecer
# a água.
while temperatura_agua <= ponto_ebulicao:
    # a expressão acima é o equivalente à pergunta do diagrama "Ferveu?"
    temperatura_agua += 1

print(f"Temperatura da água: {temperatura_agua}ºC")
print('Hora de adicionar miojo')
# retomando o exemplo da última aula (do miojo):
tempo = 0 # segundos
miojo_pronto = False

while miojo_pronto != True:
    # vamos exibir na tela o tempo passando a cada min:
    if(((tempo%60) == 0) and ((tempo/60) != 0)):        
        print(f"Já se passaram: {int(tempo/60)}min")
        
    if tempo == 180: # 360 igual a segundos em 3min
        miojo_pronto = True
        print('Miojão tá pronto!')
        
        # outra forma de exibir mensagens com variáveis
        print('Tempo necessário: {}s'.format(tempo))
    else:
        # adicionamos um segundo no nosso tempo
        tempo += 1<jupyter_output>Já se passaram: 1min
Já se passaram: 2min
Já se passaram: 3min
Miojão tá pronto!
Tempo necessário: 180s<jupyter_text>Vejam que, para traduzir aquele pequeno trecho do diagrama de blocos, é necessário criar variáveis auxiliares que nos ajudarão a rodar as estruturas de repetição, a iteração em si, etc. --------------------------------------------  Exercício 1Para sairmos um pouco deste monte de teoria, vamos realizar alguns exercícios utilizando o que aprendemos até aqui.**Exercício 1**: vamos exercitar um pouco a lógica de programação calculando quantos números pares temos dentro de uma sequência de números.Começamos pelo mais simples:1. crie uma lista de números inteiros aleatórios que você quiser2. selecione a melhor estrutura que aprendemos para iterar nessa lista3. faça testes para checar se o número em questão é par4. caso seja, concatene +1 a uma variável auxiliarPodemos agorar selecionar uma lista maior. Utilize a função ```range``` para iterar em uma lista de 0 a 100, descobrindo quantos pares temos nesta lista.**dica**:Um número será par quando o resto de sua divisão por 2 for 0. Temos um operador específico para calcular o resto de uma divisão (%), use-o. **Exercício 2**Passando para algo mais temático, vamos fazer uma série de exercícios em cima de uma lista de espécies (que peguei de um artigo científico para a região sudeste brasileira). Esta lista é fornecida na próxima célula.<jupyter_code># codigo para baixar o arquivo, caso você esteja rodando este notebook no Google Colab
!wget --directory-prefix=../dados/ https://raw.githubusercontent.com/nilodna/python-basico/feature_iojr-shortcourse/dados/lista_de_especies.txt
# lista aleatória de organismos

# vamos abrir um arquivo txt usando a função nativa do python open(). Caso tenha dúvidas de como essa função trabalha, abra uma célula nova e digite open? e rode. Um 
# pequeno manual da função abrirá para você
lista_especies = open('../dados/lista_de_especies.txt', 'r').read()

# infelizmente, a função open nos retorna toda uma lista como uma unica string. 
lista_especies
# resolvemos recortando essa string com o método .split() usando um caracter específico
lista_especies = lista_especies.split('\n')

# neste caso, \n representa uma quebra de linha 

lista_especies<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.10448357088673295, 'fraction_numerical': 0.015610651974288337, 'mean_word_length': 4.392465016146394, 'pattern_counts': {'":': 0, '<': 132, '<?xml version=': 0, '>': 133, 'https://': 6, 'lorem ipsum': 0, 'www.': 3, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '36', 'dir': 'jupyter-structured-clean-dedup', 'id': '165290', 'license': 'Apache-2.0', 'n_tokens_mistral': 8941, 'n_tokens_neox': 8593, 'n_words': 2887, 'path': 'material_acompanhamento/lecture02.ipynb', 'repo_name': 'nilodna/python-basico', 'size': '25047'}