Nim for Python Programmers PT_BR (original) (raw)

Índice

Comparação Objetos [Eu tenho que conhecer C?](#do -eu tenho que saber-c) [Tuplas nomeadas](#named -tuple-1)
Variáveis self.__init__() Strings, F-Strings Listas
[Nomeando de variáveis](#variable -naming) [Espaçamento consistente](#consistent -spacing) Escopo [Argumentos mutáveis](#mutable -arguments)
Imports Intervalos [Operações com cadeias de caracteres](#string -ops) List Comprehensions
try/import/except [Verificações estática de limites](#static -bounds-check) [Coalescência nula](#null -coalescência) [with Gerenciador de Contextos](#with -context-manager)
Matrizes Fatias Tuplas [Dict Compreensions](#Dict -Compreensões)
[Set Comprehensions](#Set -Compreensões) [Lendo e gravando arquivos](#Reading -and-writing-files) Decoradores Lambdas
Conjuntos JSON [Map e filter](#map —filter) [Indentação opcional](#Optional -Indentação)
Dicionários CamelCase DocStrings [Importar arquivos Nim em Python](#Import -Nim-files-on-Python)
[Operadores ternários](#Ternary -operadores) Testes unitários [def x proc/func](#def -vs-procfunc) [Autoexecução do módulo principal](#Self -Execução do módulo principal)
[Sintaxe Python para Nim](#Python -Syntax-for-NIM) [Publicar no PYPI](#Publish para PYPI) [Compilação silenciosa](#Silent -Compilação) [Ajuda do compilador](#Compiler -Help)
[Modos de construção](#Build -Modes) ABC - Classes básicas abstratas Decoradores WebAssembly
Modelos Nim executando interpretado Nim no navegador Equivalentes da biblioteca padrão
Assíncrono Instale o Nim do PIP Folha de dicas em PDF Funções Arrow
Como compartilhar variáveis entre funções? [Alterar permissões do arquivo](#Change -File-Permissions) [Alterar pasta temporariamente](#Temporarily -Change-Folder) Pattern Matching - Correspondência de padrões
Melhores práticas [No local versus fora do lugar](#in -Place-vs-Out-Place) Executar no NodeJS [Expansão de código](#run -time-code-expansion)
Arduino, MicroPython, ESP32, RTOS grátis Codificação ao vivo, FoxDot, SuperCollider Nim instalável por PIP incorporado em Python Instale pacotes Nim do PIP

Comparação

Característica 🐍 Python 👑 Nim
Modelo de execução Máquina virtual (interpretador) Código de máquina via C/C++ (compilador)
Escrito usando C (CPython) Nim
Licença Licença da Python Software Foundation MIT
Versão (principal) 3.x 1.x
Metaprogramação ✔️ metaclass, exec, eval, ast
(expansão de código em tempo de execução) ✔️ modelo, macros
(expansão do código em tempo de compilação)
Gerenciamento de memória Coletor de lixo Gerenciamento de memória multiparadigma
(coletores de lixo, ARC/ORC,
manual)
Tipagem Dinâmica, Duck Typing Estática
Tipos dependentes ✔️ Suporte parcial
Genéricos Duck Typing ✔️
tipos
int8/16/32/64 ✔️
tipos uint8/16/32/64 ✔️
tipos float32/float64 ✔️
Tipos de caractere ✔️
Tipos de subfaixa ✔️ ✔️
Tipos de enum ✔️ ✔️
Bigints (tamanho arbitrário) ✔️ ✔️ jsbigints,
#14696
Maior número inteiro embutido Desconhecido, limitado pela memória livre 18_446_744_073_709_551_615 para o tipo uint64
Matrizes ✔️ ✔️
Inferência de tipo Duck typing ✔️
Closures ✔️ ✔️
Sobrecarga do operador ✔️ ✔️ em qualquer tipo
Operadores personalizados ✔️
Orientado a objetos ✔️ ✔️
Métodos ✔️ ✔️
Exceções ✔️ ✔️
Funções anônimas ✔️ várias linhas, expressão única ✔️ várias linhas, várias expressões
List comprehensions ✔️ ✔️
Dict comprehensions ✔️ ✔️
Set comprehensions ✔️ ✔️
Compreensões personalizadas de objetos ✔️ expressão geradora ✔️
Pattern Matching embutido ✔️ A partir do Python 3.10 ✔️
Imutabilidade dos tipos Tipos básicos (número, string, bool), tuple, frozenset ✔️
Imutabilidade das variáveis ✔️
Imutabilidade dos argumentos da função Dependendo do tipo Imutável
Literais de string formatados ✔️ f-strings ✔️ strformat
FFI ✔️ ctypes, API de extensão C (Cython via pip) ✔️ C, C++, Objective C, JS (dependendo do backend usado)
Assíncrono ✔️ ✔️
Tópicos ✔️ GIL - Bloqueio de intérprete global ✔️
Regex ✔️ compatível com Perl ✔️ compatível com Perl
Comentários da documentação ✔️ cadeias de texto simples com várias linhas (reStructuredText
via Sphinx) ✔️ reStructuredText/Markdown
Publicação de pacotes ✔️ não embutido, requer twine ✔️ embutido, nimble
Gerenciador de pacotes ✔️ pip ✔️ nimble
Formatador automático de código ✔️ black e outros via pip ✔️ nimpretty embutido, nimlint
Extensões de arquivo .py, .pyw, .pyc, .pyd, .so .nim, .nims
Formato de representação intermediária temporária (IR) .pyc (código de bytes da VM do CPython) C, C++, Objective C (LLVM IR via nlvm)
Usa #! shebang em arquivos ✔️ ✔️ nimr, nimcr
REPL ✔️ [inim](https://github.com/inim-repl/INim#inim-interactive-nim-shell —),
Nim4Colab
Indentação Tabulações e espaços, uniformes por bloco de código, 4 espaços por convenção Somente espaços, uniforme por bloco de código, 2 espaços por convenção

Notas:

Variáveis

A criação de uma nova variável usa var ou let ou const. Nim tem imutabilidade e execução de funções em tempo de compilação. Você pode atribuir funções às variáveis.

Característica const let var
Tempo de execução NÃO ✔️ SIM ✔️ SIM
Tempo de compilação ✔️ SIM NÃO NÃO
Imutável ✔️ SIM ✔️ SIM NÃO
Inicializado automaticamente ✔️ SIM ✔️ SIM ✔️ SIM
Reatribuível NÃO NÃO ✔️ SIM
Requer atribuição ✔️ SIM ✔️ SIM NÃO
Pode ser global ✔️ SIM ✔️ SIM ✔️ SIM

Para usuários avançados, é possível ignorar a inicialização automática de variáveis.

Nomeação de variáveis

As variáveis podem ter várias linhas sem “escapar” delas ou usar parênteses. Isso é útil para linhas longas e operadores ternários longos. Exemplo mínimo:

variable = 666 +
420 *
42 -
9

assert variable == 18297

⬆️ Python ⬆️ ⬇️ Nim ⬇️

var variable = 666 + 420 * 42 - 9

assert variable == 18297

Isso também funciona com chamadas de função:

import std/strutils

var variable = " 12345 " .strip .parseInt

assert variable == 12345

Você pode usar sublinhados, novas linhas (new lines) e espaços em branco nos nomes das variáveis:

let this must be positive: Positive = 42

assert this_must_be_positive == 42

const this is my nice named variable = 42

Você pode usar palavras-chave reservadas como nomes de variáveis.

Não há problema em usar var enquanto aprende Nim ou para prototipagem rápida, embora seja muito melhor aprender a diferença entre diferentes declarações de variáveis.

Espaçamento consistente

Os espaços devem ser consistentes em seu código, principalmente em torno dos operadores:

echo 2 - 1 # OK echo 2-1 # OK

Espaços inconsistentes incorretos:

echo 2 -1 # Error

^ parses as "-1"

Omitir espaços em seu código não afeta o desempenho.

Todos os operadores são funções no Nim.

Escopo

for x in range(0, 9): if x == 6: print(x)

print(x)

Saída:

⬆️ Python ⬆️ ⬇️ Nim ⬇️

for x in 0..9: if x == 6: echo x

echo x

Saída:

Error: undeclared identifier: 'x'

Observe que, no exemplo acima, usamos um simples int, então o problema pode não parecer grave. Mas se x tivesse alguns gigabytes de RAM, ele “vazaria” do loop for para o resto do escopo externo ou principal, em vez de ser recuperado. Nim evita esse problema.

Outro exemplo:

x = 0 y = 0

def example(): x = 1 y = 1 class C: nonlocal x, y assert x == 1 and y == 1 x = 2

example()

⬆️ Python ⬆️ ⬇️ Nim ⬇️

var x = 0 var y = 0

proc example() = var x = 1 var y = 1 type C = object assert x == 1 and y == 1 x = 2

example()

Outro exemplo:

x = 0 y = 0

def example(): x = 1 y = 1 class C: nonlocal x, y assert x == 1 and y == 1 x = 2 try: raise except Exception as _: pass

example()

⬆️ Python ⬆️ ⬇️ Nim ⬇️

var x = 0 var y = 0

proc example() = var x = 1 var y = 1 type C = object assert x == 1 and y == 1 x = 2 try: raise except Exception as y: discard

example()

Condicionais booleanos

Falha com o erro:

SyntaxError: invalid syntax.

⬆️ Python ⬆️ ⬇️ Nim ⬇️

O exemplo do Nim é compilado e executado sem incidentes; a precedência do operador é resolvida corretamente:

Outro exemplo:

assert False + 1 assert not True - 1

Isso é executado porque bool é um subtipo de int em Python, portanto, ele suporta as mesmas operações matemáticas. Em Nim, esse não é o caso:

⬆️ Python ⬆️ ⬇️ Nim ⬇️

assert false + 1 assert not true - 1

Não compila:

Error: type mismatch: got <bool, int>

bloco

block cria explicitamente um novo escopo, sem a sobrecarga de uma função. Ele pode ter um “nome” sem que o nome polua o namespace local e pode ser interrompido em qualquer lugar sem exigir retornar.

block também pode ser usado com var, let e const.

Imagine que você precise sair de um if aninhado, sem executar nenhum outro código de outros blocos if e else. Você pode fazer:

print("Before")

this is a function, has overhead, pollutes namespace, must return to interrupt, etc.

def example(): if True: print("Inside if true") if 42 > 0: print("Inside if 42 > 0") if 'z' > 'a': print("Inside if z > a") return # Must return to interrupt if 3.14 > 0.0: print("Inside if 3.14 > 0.0") else: print("else of z > a") else: print("else of 42 > 0") else: print("else of true")

example() # example in namespace print("After")

⬆️ Python ⬆️ ⬇️ Nim ⬇️

echo "Before"

block example: # Creates a new explicit named scope. This is not a function; there is no overhead. if true: echo "Inside if true" if 42 > 0: echo "Inside if 42 > 0" if 'z' > 'a': echo "Inside if z > a" break example # Gets out of block example. if 3.14 > 0.0: echo "Inside if 3.14 > 0.0" else: echo "else of z > a" else: echo "else of 42 > 0" else: echo "else of true"

No function call. "example" is not polluting the local namespace.

echo "After"

Argumentos mutáveis

def example(argument = [0]): argument.append(42) return argument

print(example()) print(example()) print(example())

Saída:

[0, 42] [0, 42, 42] [0, 42, 42, 42]

⬆️ Python ⬆️ ⬇️ Nim ⬇️

func example(argument = @[0]): auto = argument.add 42 return argument

echo example() echo example() echo example()

Saída:

Error: type mismatch: got <seq[int], int literal(42)>

but expected one of: proc add[T](x: var seq[T]; y: sink T) first type mismatch at position: 1 required type for x: var seq[T] but expression 'argument' is immutable, not 'var'

Importações

Importar 🐍 Python 👑 Nim
Apenas um símbolo, use não qualificado from math import sin from std/math import sin
Todos os símbolos, use sem qualificação from math import * **import std/math (recomendado) **
Todos os símbolos, use totalmente qualificados **import math (recomendado) ** from std/math import nil
“importar as” outro nome import math as batata import std/math as batata
Ambos os itens acima ao mesmo tempo from std/math as m import nil
Todos os símbolos, exceto um, usam sem qualificação import std/math except sin
Todos os símbolos, exceto vários, usam sem qualificação import std/math except sin, tan, PI
Incluir outro módulo neste módulo incluir algum módulo

**Seus módulos e tipos não vão colidir! , mesmo que você tenha tipos chamados de módulos, relaxe e continue codificando... **

No Nim, import std/math importa todos os símbolos do módulo math (sin,cos, etc) para que eles possam ser usados sem qualificação. O equivalente em Python é from math import *.

Se você preferir não importar todos os símbolos e sempre usar nomes qualificados, o código Nim é from std/math import nil. Então você pode chamarmath.sin () , math.cos (), etc. O equivalente em Python é import math.

Geralmente, é seguro importar todos os nomes no Nim porque o compilador não compilará nenhuma função não utilizada (portanto, não há sobrecarga). Além disso, como o Nim é estaticamente tipado, ele geralmente pode distinguir entre as duas funções importadas com os mesmos nomes com base nos tipos de argumentos com os quais são chamadas. Nos raros casos em que os tipos são iguais, você ainda pode qualificar totalmente o nome para desambiguar.

O prefixo std/ impõe que o módulo seja importado da biblioteca padrão. Se um pacote Nimble tiver um módulo com o mesmo nome, o compilador pode resolver a ambiguidade e isso está explícito no código.

Módulos locais e módulos Nimble não precisam do prefixo std/.

Python e Nim compartilham essas declarações de importação:

# Python and Nim
import foo, bar, baz

import foo
import bar
import baz

Sintaxes alternativas:

Python

import foo,
bar,
baz

Nim

import foo, bar, baz

Useful for small diffs when adding/removing imports

import foo, bar, baz

import foo, bar, baz, more, imports

A variante com uma instrução import por linha é comum em Python e Nim, mas em Nim a forma import foo, bar, baz também é vista com frequência.

Mais exemplos:

This is documentation for the module.

This is a comment.

include prelude import std/sugar as stevia from std/math import nil from std/with as what import nil

Programaticamente

⬆️ Python ⬆️ ⬇️ Nim ⬇️

template imports(s) = import s imports math

Código sem importações

Às vezes, na natureza, você pode ver exemplos de código ou arquivos sem as importações, mas eles de alguma forma funcionam de qualquer maneira. O motivo é que Nim pode usar import do comando compile ou de um arquivo .nims:

Às vezes, projetos ou exemplos de código rápido usam isso para evitar a digitação. Graças ao Dead Code Elimination (Eliminação de código morto), se os símbolos importados não forem usados, eles não existirão na saída compilada.

Veja também:

Prelúdio

Às vezes, você pode achar que o Python tem mais símbolos disponíveis por padrão sem qualquer importação em comparação com o Nim. Para ter uma experiência semelhante de ter as estruturas básicas de dados e as importações mais comuns prontas para que você possa começar a codificar imediatamente, você pode usarprelude:

include prelude

echo now()
echo getCurrentDir() echo "Hello $1".format("World")

prelude é um arquivo includeque simplesmente importa módulos comuns para sua conveniência, para evitar a digitação. prelúdio também funciona para destinos em JavaScript.

De onde vêm os símbolos?

Dado que foo () é um símbolo:

Normalmente, o Editor/IDEdeve sugerir de onde vêm os símbolos, como em qualquer outra linguagem de programação:

!

O Nim vem integrado com o NimSuggestpara integrações de editor/IDE.

Ao contrário do Python, o sistema de tipos de Nim tem todas as informações sobre todos os símbolos:

import std/macros macro findSym(thing: typed) = echo thing.getType.lineInfo

findSym: echo # Where echo comes from?.

echo vem de:

Ao aprender Nim ou para prototipagem rápida, não há problema em usar os símbolos totalmente qualificados. Fazer isso não produz erros, mas o Nim idiomático evita isso.

Exportações

Em Python, todos os símbolos no módulo são visíveis e mutáveis dos módulos que o importam, incluindo símbolos que não devem ser usados ou alterados fora do módulo.

No Nim, tudo é privado por padrão e, portanto, não é visível em outros módulos. Para tornar os símbolos públicos e visíveis em outros módulos, você precisa usar o asterisco *:

let variable* = 42 const constant* = 0.0 proc someFunction*() = discard template someTemplate*() = discard type Platypus* = object fluffyness*: int

O asterisco não apenas torna o símbolo visível para o mundo exterior, mas também aparecerá na documentação gerada (nim doc). Quando você importa o módulo, o símbolo será automaticamente adicionado ao namespace, mas símbolos privados (não exportados) sem * não estarão visíveis. O asterisco é como uma dica visualpara humanos. Você pode entender imediatamente quais símbolos fazem parte da “API pública” apenas examinando o código-fonte do módulo. O asterisco * é pronunciado como “estrela”.

Para obter mais informações, leia:https://narimiran.github.io/2019/07/01/nim-import.html

try/import/except

Em Python, os imports são uma operação em tempo de execução e podem falhar. É um padrão bastante comum que os imports dependentes da plataforma sejam colocadas dentro de um bloco try e uma alternativa ou fallback dentro do bloco except:

try: import module except ImportError: import othermodule as module

try: from module import some_func except ImportError: # Fallback implementation def somefunc(): return some_value

O Nim resolve todas as importações em tempo de compilação, então algo como umImportError não existe. Não há necessidade de lidar com erros de importação em tempo de execução.

Matrizes

As matrizes em Nim são de tamanho fixo, começam no índice 0 e devem conter elementos do mesmo tipo.

Ao passar uma matriz para uma função em Nim, o argumento é uma referência imutável. O Nim incluirá verificações em tempo de execução nos limites das matrizes.

Você pode usar um openarraypara aceitar uma matriz de qualquer tamanho nos argumentos da função, e você pode usar low (seu_array) e high (seu_array) para consultar os limites da matriz.

Nim string é compatível com openArray [char] para evitar cópias desnecessárias para otimização, e char é compatível com int. Portanto, a manipulação de strings pode ser feita com a matemática no local de forma transparente. Uma função que usa openArray [char] aceita "abcd" e ['a', 'b', 'c', 'd'].

O conteúdo da matriz é sempre contíguo na memória, assim como as matrizes de matrizes.

Veja também:

Tamanhos dos tipos de dados

import std/json

type Foo = object
type Bar = enum true, false

(Weird spacing intended)

assert sizeOf( Foo ) == 1 assert sizeOf( Bar ) == 1 assert sizeOf( bool ) == 1 assert sizeOf( {true} ) == 1 assert sizeOf( [true] ) == 1 assert sizeOf( (true) ) == 1 assert sizeOf( int8 ) == 1

assert sizeOf( {'k': 'v'} ) == 2 assert sizeOf( int16 ) == 2

assert sizeOf( int32 ) == 4 assert sizeOf( float32 ) == 4

assert sizeOf( int ) == 8 assert sizeOf( float ) == 8 assert sizeOf( @[true] ) == 8 assert sizeOf( %*{} ) == 8 assert sizeOf( pointer ) == 8

Essa é apenas uma aproximação para as primitivas vazias em 64 bits.

Objetos

Objetos em Nim se comportam de forma bem diferente das classes em Python. Os objetos suportam herança e OOP. As classes são denominadas tipos em Nim. Funções (procs) são funções flutuantes livres, não vinculadas a objetos (no entanto, você pode usá-las de uma forma muito semelhante ao Python). Você pode chamar uma função em objetos com a sintaxe object.function () , bem comofunction (object); estes são totalmente equivalentes. Nim não tem um eu implícito nem isso. É uma boa prática colocar todos os tipos no topo do arquivo, mas isso não é obrigatório.

Uma forma de imaginar isso é que procs ficam “grudados” nos tipos de seus argumentos em tempo de compilação e, em seguida, você pode usá-los em tempo de execução como se fossem classes e métodos do Python.

Do Python ao Nim, o mínimo possível exemplo:

class Kitten: """ Documentation Here """

def purr(self):
    print("Purr Purr")

Kitten().purr()

⬆️ Python ⬆️ ⬇️ Nim ⬇️

type Kitten = object ## Documentation Here proc purr(self: Kitten) = echo "Purr Purr" Kitten().purr()

Exemplo de herança mínima:

type Animal = object of RootObj type Kitten = object of Animal assert Kitten is Animal

Exemplos de orientação de objetos semelhantes aos do Python:

type Animal = ref object of RootObj ## Animal base object. age: int
name: string ## Attributes of base object.

type Cat = ref object of Animal ## Cat inherited object. playfulness: float ## Attributes of inherited object.

func increase_age(self: Cat) = self.age.inc() # Cat object function, access and modify object.

var kitten = Cat(name: "Tom") # Cat object instance. kitten.increase_age() # Cat object function used.

assert kitten.name == "Tom" # Assert on Cat object. assert kitten.age == 1

Exemplo de herança:

type LUCA = ref object of RootObj Archea = ref object of LUCA Prokaryota = ref object of Archea Eukaryota = ref object of Prokaryota Animalia = ref object of Eukaryota Chordata = ref object of Animalia Mammalia = ref object of Chordata Primates = ref object of Mammalia Haplorhini = ref object of Primates Simiiformes = ref object of Haplorhini Hominidae = ref object of Simiiformes Homininae = ref object of Hominidae Hominini = ref object of Homininae Homo = ref object of Hominini Homosapiens = ref object of Homo

assert Homosapiens() is LUCA assert LUCA() isnot Homosapiens assert sizeOf(Homosapiens) == sizeOf(LUCA) let human = Homosapiens() assert human is Homosapiens

Veja também:

self.__init__()

Depois do exemplo do Cat, você provavelmente está se perguntando como fazerdef __init__ (self, arg) :.

Python __init__ () é Nim newObject () ou initObject () . Vamos fazer um__init__ () para o Cat:

type Cat = object # Cat object. age: int
name: string # Attributes of Cat object.

func initCat(age = 2): Cat = # Cat.init(self, age=2)
result.age = age # self.age = age
result.name = "adopt_me" # self.name = "adopt_me"

var kitten = initCat() # Cat object instance.

assert kitten.name == "adopt_me" # Assert on Cat object. assert kitten.age == 2

A nomenclatura é uma convenção e uma boa prática. Quando você quiser init paraFoo, basta criar newFoo () ou initFoo (). Como você pode notar, initCaté apenas uma função que retorna um Cat.

Leia a documentação para nomear coisas seguindo as convenções e as melhores práticas.

Valores padrão do atributo do objeto

O construtor de objetos também é a forma de definir valores padrão personalizados para os atributos de seus objetos:

type Cat = object age: int # AutoInitialized to 0 name: string # AutoInitialized to "" playfulness: float # AutoInitialized to 0.0 sleeping: bool # AutoInitialized to false func initCat(): Cat =
result.age = 1 # Set default value to 1 result.name = "Bastet" # Set default value to "Bastet" result.playfulness = 9.0 # Set default value to 9.0 result.sleeping = true # Set default value to true

Uma estrutura mais completa para um programa básico pode ser algo como:

Simple application to do Foo with the Bar.

type Animal = ref object of RootObj age: int
name: string

Cat = ref object of Animal playfulness: float

func initCat(age = 2): Cat =
result.age = age
result.name = "adopt_me"

func increase_age(self: Cat) = self.age.inc()

proc main() = var kitten = Cat(name: "Tom")
kitten.increase_age()

assert kitten.name == "Tom"
assert kitten.age == 1

when isMainModule: main()

runnableExamples: echo "Optionally some documentation code examples here" assert 42 == 42

Expansão do código de execução

Objetos Python que internamente usam geração de código são muito, muito lentos, escalonando com o tamanho. Quanto mais você o usa, mais lento ele executa. dataclass, metaclasse, decoradores, etc. podem ser mais de 25 ~ 50x mais lentos do que uma classe normal. [Pathlib.path e seus métodos podem ser mais de 25 ~ 50x mais lentos do que um str] normal (https://youtu.be/tFrh9hKMS6Y) e anulam qualquer otimização, incluindo um arquivo .pyc. O Cython não tem CTFE, então isso não ajuda especificamente.

Por exemplo, você pode ver o resultado da expansão do código ARC durante a compilação usando —expandArc. É assim que o Nim faz o gerenciamento de memória em tempo de compilação (aproximação):

!

Veja também:

Unsafe Type Hints (dicas de tipagem inseguras)

As “type hints” do Python podem ser quase qualquer coisa e são executadas implicitamente em tempo de execução. Não é preciso dizer que isso pode ser muito inseguro:

$ cat example.py class X: _: "print('PWNED')" # os.system("rm -rf /folder ") import("typing").get_type_hints(X)

$ python3 example.py

'PWNED'

$

Os tipos de Nim devem ser válidos; os tipos são verificados no momento da compilação:

$ cat example.nim type X = object a: "echo('PWNED')" echo X()

$ nim r example.nim # Will not compile.

Error: type expected, but got: "echo('PWNED')"

$

Outro exemplo

$ cat example.nim var example: "echo('PWNED')" echo example

$ nim r example.nim # Will not compile.

Error: type expected, but got: "echo('PWNED')"

$

Por valor x por referência

O compilador Nim determina automaticamente se um parâmetro é passado por valor ou por referência com base no tamanho do tipo de parâmetro.

Se um parâmetro precisar ser passado por valor ou por referência (como ao fazer interface com uma biblioteca C), use os pragmas {.bycopy.} ou {.byref.}.

Nim passa objetos maiores que 3 * sizeOf (int) por referência para desempenho, mas isso é arquitetura e implementação definidas. Portanto, as informações a seguir são apenas uma aproximação para x86_64:

Declaração Valor ou referência? Implícito ou explícito? Gerenciado ou não gerenciado? Observações
symbol: int Por valor Implícito Gerenciado Uso frequente
symbol: var int Por referência Implícito Gerenciado Uso frequente
symbol: ref int Por referência Explícito Gerenciado Raro
symbol: ptr int Por referência Explícito Não gerenciado C/C++ FFI
symbol: var ref int Por referência Implícito Gerenciado Raro
symbol: var ptr int Por referência Implícito Não gerenciado Raro
symbol: pointer Por referência Explícito Ponteiro não gerenciado C/C++ FFI

Intervalos

Em Python, um número inteiro simples para loops usa a função geradora range. Para as formas de argumento 1 e 2 dessa função, o .. iteratorde nim funciona quase da mesma maneira:

for i in 0 .. 10: echo i # Prints 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10

for i in 5 .. 10: echo i # Prints 5, 6, 7, 8, 9, 10

Observe que o operador .. inclui o final do intervalo, enquanto orange (a, b) do Python não inclui b. Se você preferir esse comportamento, use o iterador .. <em vez disso:

for i in 0 ..< 10: echo i # Prints 0, 1, 2, 3, 4, 5, 6, 7, 8, 9

O range () do Python também tem um terceiro parâmetro opcional, que é o valor a ser incrementado em cada etapa. Isso pode ser positivo ou negativo. Se você precisar desse comportamento, use os iteradores countupou countdown:

for i in countup(1, 10, 2): echo i # Prints 1, 3, 5, 7, 9

for i in countdown(9, 0, 2): echo i # Prints 9, 7, 5, 3, 1

Converta de range para seq:

import sequtils

const subrange = 0..9 const seqrange = toSeq(subrange) assert seqrange is seq[int]

Veja também:

Fatias

A sintaxe dos intervalos de fatias é diferente. a [x:y] do Python éa [x.. < y] de Nim.

let variable = [1, 2, 3, 4] assert variable[0 .. 0] == @[1] assert variable[0 .. 1] == @[1, 2] assert variable[0 ..< 2] == @[1, 2] assert variable[0 .. 3] == @[1, 2, 3, 4]

Fatias de índice reverso

Em Nim, um índice reverso ou índice inverso usa ^ com o número, como ^1. Os índices retroativos têm um tipo específico backwardsIndex e também podem ser “preparados” em tempo de compilação como const:

const lastOne = ^1 # Compile-time assert lastOne is BackwardsIndex assert [1, 2, 3, 4, 5][2 .. lastOne] == @[3, 4, 5] assert [1, 2, 3, 4, 5][2 .. ^1] == @[3, 4, 5] var another = ^3 # Run-time assert [1, 2, 3, 4, 5][0 .. another] == @[1, 2, 3] assert [1, 2, 3, 4, 5][^3 .. ^1] == @[3, 4, 5] # 2 Reverse index

Verificação estática de limites

Vamos comparar exemplos muito simplificados:

[0, 1, 2][9] # No Index 9

Isso falha em tempo de execução porque não há índice 9:

$ python3 example.py Traceback (most recent call last): File "example.py", line 1, in [0, 1, 2][9] IndexError: list index out of range

$

Vamos ver Nim:

discard [0, 1, 2][9] # No Index 9

Compile e execute:

$ nim compile --run example.nim example.nim(1, 19) Warning: can prove: 9 > 2 [IndexCheck] example.nim(1, 18) Error: index 9 not in 0..2 [0, 1, 2][9]

$

Nim verifica em tempo de compilação que [0, 1, 2] não tem índice 9, porque9 > 2. Portanto, ele não será compilado nem executado.

Isso também funciona com o Subrange. Digamos que você tenha uma variável inteira que deva ser positiva:

let must_be_positive: Positive = -9

Compile e execute:

$ nim compile --run example.nim example.nim(1, 34) Warning: can prove: 1 > -9 [IndexCheck] example.nim(1, 34) Error: conversion from int literal -9 to Positive is invalid.

$

Nim verifica em tempo de compilação se must_be_positive não é Positivoporque 1 > -9. Ele não será compilado nem executado.

Outro exemplo:

var variable0: 5..8 = 5 # int range type, value must be between '5' and '8'. variable0 = 8 variable0 = 7 assert not compiles(variable0 = 4) assert not compiles(variable0 = 9) assert not compiles(variable0 = 0) assert not compiles(variable0 = -1) assert not compiles(variable0 = -9)

var variable1: 3.3..7.5 = 3.3 # float range type, value must be between '3.3' and '7.5'. variable1 = 7.5 variable1 = 5.5 assert not compiles(variable1 = 3.2) assert not compiles(variable1 = 7.6) assert not compiles(variable1 = 0.0) assert not compiles(variable1 = -1.0) assert not compiles(variable1 = -9.0)

var variable2: 'b'..'f' = 'b' # char range type, value must be between 'b' and 'f'. variable2 = 'f' variable2 = 'c' assert not compiles(variable2 = 'g') assert not compiles(variable2 = 'a') assert not compiles(variable2 = 'z') assert not compiles(variable2 = '0') assert not compiles(variable2 = '9')

var variable3: Positive = 1 # Positive type, value must be > 0. variable3 = 1 variable3 = 999 assert not compiles(variable3 = 0) assert not compiles(variable2 = -1) assert not compiles(variable2 = -9)

var variable4: Natural = 0 # Natural type, value must be >= 0. variable4 = 1 variable4 = 999 assert not compiles(variable4 = -1) assert not compiles(variable4 = -9)

Você pode controlar isso com —staticBoundChecks:on ou —staticBoundChecks:off.

Com —staticBoundChecks:off, isso pode gerar um erro em tempo de execução, como o Python faz.

Coalescência nula

O Python não tem um operador de coalescência nula(no momento em que este artigo foi escrito).

Em vez disso, os programadores de Python usam o operador condicional ternário:

other = bar if bar is not None else "default value" # "bar" may be null?, or not ?.

Nim tem um módulo wrapnils com um ?. operador de coalescência nula, que simplifica o código ao reduzir a necessidade de ramificações if.. elif... else em torno de valores intermediários que podem ser nulos.

assert ?.foo.bar.baz == "" # "bar" may be Null?, or not ?.

Null é None em Python. Null é nil em Nim.

Veja: https://nim-lang.github.io/Nim/wrapnils.html

With Context Manager

Não há equivalente nativo direto à construção with do Python. No Nim, existem as seguintes opções:

Consulte a seção Modelos para ver exemplos.

Strings

Lang String String de várias linhas String Raw String Raw de múltiplas linhas Literais formatados Quote (mascarando)
🐍 Python "foo" """"foo""" r"foo" r"""foo""" f"" "{1 + 2}" "" "``'
👑 Nim "foo" """"foo""" r"foo" r"""foo""" fmt"" "{1 + 2}" "" "

Operações de string

Operações 🐍 Python 👑 Nim
Lower "ABCD” .lower () "ABCD".toLowerAscii()
Strip ” ab “.strip () ” ab “.strip ()
Split "a,b,c".split(",") "a,b,c".split(",")
Concatenação "a” + “b" "a” e “b"
Find "abcd".find("c") "abcd".find("c")
Começa com "abc".startswith("ab") "abc".startswith("ab")
Termina com "abc".endswith("ab") "abc".endswith("ab")
Dividindo por Linha "1\n2\n3".splitlines() "1\n2\n3".splitlines()
Fatiando "abcd"[0:2] "abcd"[0 ..< 2]
Cortando 1 caractere "abcd"[2] "abcd"[2]
Corte reverso "abcd"[-1] "abcd"[^1]
Normalize unicodedata.normalize("NFC", "Foo") "Foo".normalize()
Contando Linhas len("1\n2\n3".splitlines()) "1\n2\n3".countLines()
Repeat (repetir) "foo" * 9 "foo".repeat(9)
Recuar (indent) textwrap.indent("foo", " " * 9) "foo".indent(9)
Unindent [textwrap.dedent(“foo”)](https://docs.python.org/3/library/textwrap.html#textwrap.dedent
“textwrap.dedent () Remove TODA a indentação!”) "foo".unindent(9)
Parse Bool [bool(distutils.util.strtobool (“fALse”)) ](https://stackoverflow.com/q/715417
“bool ('FalSE') == True”) :pergunta: parseBool("fALse")
Parse Int int("42") parseInt("42")
Parse Float float("3.14") parseFloat("3.14")
Literais de string formatados f"foo {1 + 2} bar {variable}" fmt"foo {1 + 2} bar {variable}"
Distância de Levenshtein editDistance (“Kitten”, “Bitten”)

Eficiência de String

Strings podem ser alocadas em memória de uma só vez comnewStringOfCap (capacity = 42) , que retorna uma nova string vazia "", mas com capacidade alocada de 42. Se você ultrapassar a capacidade, ela não falhará nem estourará o buffer:

variable = "" assert variable == "" # length is 0, capacity is 0, 1 allocations, 0 copies variable += "a" # length is 1, capacity is 1, 2 allocations, 1 copies variable += "b" # length is 2, capacity is 2, 3 allocations, 2 copies variable += "c" # length is 3, capacity is 3, 4 allocations, 3 copies variable += "d" # length is 4, capacity is 4, 5 allocations, 4 copies assert variable == "abcd"

TOTAL: 5 allocations, 4 copies

⬆️ Python ⬆️ ⬇️ Nim ⬇️

var variable = newStringOfCap(2) assert variable == "" # length is 0, capacity is 2, 1 allocations, 0 copies variable.add "a" # length is 1, capacity is 2, 1 allocations, 0 copies variable.add "b" # length is 2, capacity is 2, 1 allocations, 0 copies variable.add "c" # length is 3, capacity is 3, 2 allocations, 0 copies variable.add "d" # length is 4, capacity is 4, 3 allocations, 0 copies assert variable == "abcd"

TOTAL: 3 allocations, 0 copies

Essa diferença pode ficar maior para strings dentro de laços for ou while.

F-Strings

Nim strformat implementa literais de string formatados inspirados nas f-strings do Python. O strformat é implementado usando metaprogramação e a expansão do código é feita em tempo de compilação. Também funciona para o destino JavaScript.

Semelhante às f-strings do Python, você pode depurar o valor da chave dentro da string usando um sinal de igual.fmt "{key=}" se expande para fmt"key= {value} ":

let x = "hello" assert fmt"{x=}" == "x=hello" assert fmt"{x = }" == "x = hello"

Nim strformat suporta barra invertida, enquanto as strings f do Python não:

print( f"""{ "yep\nope" }""" ) # Run-time error. Error: f-string expression part cannot include a backslash.

⬆️ Python ⬆️ ⬇️ Nim ⬇️

echo fmt"""{ "yep\nope" }""" # Nim works.

yep ope

Você pode escolher um par de caracteres personalizado para abrir e fechar a formatação dentro da string passando o char como argumento:

import std/strformat let variable = 42

assert fmt("(variable) {variable}", '(', ')') == "42 {variable}" assert fmt(" {variable}", '<', '>') == "42 {variable}"

Usar caracteres como apóstrofo invertido e espaço ' 'funciona:

assert fmt(" variable{variable}", ' ', '') == "42{variable}"

Usar o mesmo caractere para início e fim funciona:

assert fmt("%variable% {variable}", '%', '%') == "42 {variable}"

String Raw

A string raw do Python não pode terminar em "\", mas a string raw do Nim funciona muito bem:

print(r"") # Run-time error. SyntaxError: EOL while scanning string literal.

⬆️ Python ⬆️ ⬇️ Nim ⬇️

Isso pode ser relevante ao trabalhar com cadeias de caracteres que usam "\", como caminhos de sistemas de arquivos r” C:\mypath\ ", etc.

Equivalentes de biblioteca padrão

Use 🐍 Python 👑 Nim
Sistema operacional os os
Operações de string string strutils
Data e hora datetime times
Random random random
Expressões regulares (Backend) re re
Expressões regulares (Frontend) jsre
HTTP urllib httpclient
Logando logging registro
Executando comandos externos subprocess osproc
Manipulação de caminhos (path) pathlib, os.path os
Matemática math, cmath math
Tipos MIME tipos MIME mimetypes
SQLite SQL sqlite3 db_sqlite
Postgres SQL db_postgres
Distância de Levenshtein editdistance
Serialização pickle json, jsonutils,
marshal
Base64 base64 base64
Abre o URL do navegador da web webbrowser browsers
Assíncrono asyncio asyncdispatch, asyncfile,
asyncnet, asyncstreams
Testes unitários unittest unittest
Diff difflib diff
Cores colorsys colors
MD5 hashlib.md5 md5
SHA1 hashlib.sha1 sha1
Servidor HTTP http.server asynchttpserver
Lexer shlex lexbase
Multi-Threading threading threadpool
URL E URI urllib.parse uri
CSV csv parsecsv
Parâmetros da linha de comando argparse parseopt
SMTP smtplib smtp
Cookies HTTP http.cookies cookies
Estatísticas statistics stats
Empacotamento de texto (Text Wrapping) textwrap wordwrap
Registro do Windows winreg registry
POSIX posix posix, posix_utils
SSL ssl openssl
CGI cgi cgi
Profiler cprofile, profile nimprof
Tempo monotônico time.monotonic monotimes
Executar funções na saída atexit exitprocs
Definir permissões de arquivo os, stat os, filepermissions
Percurso recursivo do sistema de arquivos os.walk os.walkDirRec,
globs.walkDirRecFilter
Mecanismo de modelagem string.Template strutils.`%` ou Source Code Filters
Deques collections.deque deques
Dicionário ordenado baseado na árvore B btreetables
Critical Bit Tree Dict/Set critbits
Alocação de memória agrupada pools
Analisar JSON json parsejson, json
Analisar INI configparser parsecfg
Analisar XML xml parsexml, xmltree
Analisar HTML html.parser htmlparser
Analisar SQL parsesql
Cores no terminal terminal
Detecção de distribuição Linux distros
Gerador de HTML htmlgen
Funções de seta (arrow) sugar
In-Place para Work-on-Copy sugar.dup
Sintaxe Sugar sugar
JavaScript e frontend dom, asyncjs,
jscore, jsffi,
dom_extensions, jsre

Tuplas

As tuplas têm tamanho fixo, começam no índice 0, podem conter tipos mistos e podem ser anônimas ou nomeadas. Tuplas nomeadas não têm nenhuma sobrecarga extra sobre tuplas anônimas.

Tupla anônima

⬆️ Python ⬆️ ⬇️ Nim ⬇️

Tuple Nomeada

collections.namedtuple("_", "key0 key1")("foo", 42)

⬆️ Python ⬆️ ⬇️ Nim ⬇️

Tuple Nomeada

collections.namedtuple("NameHere", "key0 key1")("foo", 42)

⬆️ Python ⬆️ ⬇️ Nim ⬇️

type NameHere = tuple[key0: string, key1: int] var variable: NameHere = (key0: "foo", key1: 42)

tuple [key0: string, key1: int] é o typedesc para Declarações.(key0: “foo”, key1:42) é o literal para atribuições.

As tuplas do Nim são muito parecidas com Python NamedTuple, pois os membros da tupla têm nomes.

NÃO use tuplas nomeadas para “imitar” objetos apropriados (o compilador reutiliza instanciações genéricas para tuplas “idênticas”).

Veja manualpara uma análise mais aprofundada das tuplas.

Listas

Nim sequences _não_são de tamanho fixo. Eles podem crescer e encolher, começar no índice 0 e devem conter elementos do mesmo tipo.

⬆️ Python ⬆️ ⬇️ Nim ⬇️

@ é uma função que converte de array para seq.

List Comprehensions

variable = [item for item in (-9, 1, 42, 0, -1, 9)]

⬆️ Python ⬆️ ⬇️ Nim ⬇️

let variable = collect: for item in @[-9, 1, 42, 0, -1, 9]: item

Uma comprehension também pode ser atribuída a const e será executada em tempo de compilação.

A comprehension é implementada como uma macro que é expandida em tempo de compilação. Você pode ver o código expandido usando a opção de compilador—expandMacro:

let variable = var collectResult = newSeq(Natural(0)) for item in items(@[-9, 1, 42, 0, -1, 9]): add(collectResult, item) collectResult

As comprehension podem ser aninhadas, com várias linhas e com várias expressões, tudo sem sobrecarga:

import std/sugar

let values = collect: for val in [1, 2]: collect: for val2 in [3, 4]: if (val, val2) != (1, 2): (val, val2)

assert values == @[@[(1, 3), (1, 4)], @[(2, 3), (2, 4)]]

Exemplo de linha única:

print([i for i in range(0, 9)])

⬆️ Python ⬆️ ⬇️ Nim ⬇️

echo collect(for i in 0..9: i)

As comprehension de Python convertem o código em um gerador, mas as compreensões de Nim não convertem o código em um iterador:

import std/sugar

func example() = discard collect: for item in @[-9, 1, 42, 0, -1, 9]: if item == 0: return item

example()

⬆️ Nim ⬆️ ⬇️ Python ⬇️

def example(): [item for item in [-9, 1, 42, 0, -1, 9] if item == 0: return]

example()

Python reclama:

SyntaxError: invalid syntax.

Algumas coisas que em Python são sintaticamente proibidas dentro de compreensões (como return) são permitidas no Nim. Isso ocorre porque as compreensões do Nim são apenas macros que se expandem para o código normal.

collecttakes as argument whatever your returning type uses as the constructor.

Dict Comprehensions

variable = {key: value for key, value in enumerate((-9, 1, 42, 0, -1, 9))}

⬆️ Python ⬆️ ⬇️ Nim ⬇️

let variable = collect: for key, value in @[-9, 1, 42, 0, -1, 9]: {key: value}

Set Comprehensions

variable = {item for item in (-9, 1, 42, 0, -1, 9)}

⬆️ Python ⬆️ ⬇️ Nim ⬇️

let variable = collect: for item in @[-9, 1, 42, 0, -1, 9]: {item}

Conjuntos (sets)

Lang Conjunto (set) Set ordenado Bitset Bit Fields Importações
🐍 Python set()
👑 Nim HashSet() OrderedSet() set Bit Fields import std/sets

Os conjuntos Python não são como o tipo de conjunto Nim. O conjunto “padrão” é um bitset. Para cada valor possível do tipo contido, ele armazena 1 bit indicando se ele está presente no conjunto. Isso significa que você deve usá-lo se o tipo tiver uma faixa finita e limitada de valores possíveis. Se todos os valores possíveis também forem conhecidos em tempo de compilação, você poderá criar um Enum para eles.

O maior número inteiro que você pode caber em um conjunto normalmente é 65535igual a high (uint16) .

Você pode ajustar números inteiros maiores usando um Subrange inteiro, se não precisar de números inteiros pequenos. Um exemplo realmente estressante de definir para caber 2_147_483_647 é igual a high (int32) em um conjunto em tempo de compilação:

const x = {range2147483640..2147483647} assert x is set # Equals to {2147483647}

O tipo de conjunto (set) básico do Nim é rápido e economiza memória, em comparação com o HashSet, que é implementado como um dicionário. Para tipos de flags simples e pequenos conjuntos matemáticos, use set. Para coleções maiores, ou se você está apenas aprendendo, use o HashSet.

Dicionários

Use tables para dicionários semelhantes ao Python.

Lang Dicionário Dicionário ordenado Counter Importações
🐍 Python dict() OrderedDict() Counter() import std/collections
👑 Nim Table() OrderedTable() CountTable() import std/tables

Construtores de tabela

dict(key="value", other="things")

⬆️ Python ⬆️ ⬇️ Nim ⬇️

{"key": "value", "other": "things"}.toTable

Dicionário ordenado

collections.OrderedDict([(8, "hp"), (4, "laser"), (9, "engine")])

⬆️ Python ⬆️ ⬇️ Nim ⬇️

{8: "hp", 4: "laser", 9: "engine"}.toOrderedTable

Contadores

collections.Counter("abcabb")

⬆️ Python ⬆️ ⬇️ Nim ⬇️

**Exemplos: **

import std/tables

var dictionary = {"hi": 1, "there": 2}.toTable

assert dictionary["hi"] == 1 dictionary["hi"] = 42 assert dictionary["hi"] == 42

assert len(dictionary) == 2 assert dictionary.has_key("hi")

for key, value in dictionary: echo key, value

As tabelas são apenas açúcar de sintaxe para uma matriz de tuplas:

assert {"key": "value", "k": "v"} == [("key", "value"), ("k", "v")] assert {"key": true, "k": false} == @[("key", true), ("k", false)]

Tabelas Árvores-B

Tabelas ordenadas genéricas baseadas em Árvore-Busando a mesma API.

Veja também:

Operadores ternários

"result0" if conditional else "result1"

⬆️ Python ⬆️ ⬇️ Nim ⬇️

if conditional: "result0" else: "result1"

Em Nim, o “operador ternário” é simplesmente um if.. else em linha. Ao contrário do Python, o if.. else comum é uma expressão, portanto, ele pode ser atribuído a uma variável. Esses trechos são equivalentes:

var foo = if 3 < 10: 50 else: 100

var foo = if 3 < 10: 50 else: 100

Lendo e escrevendo arquivos

Lendo arquivos linha por linha

with open("yourfile.txt", "r") as f: for line in f: print(line)

⬆️ Python ⬆️ ⬇️ Nim ⬇️

for line in lines("yourfile.txt"): echo line

**Lendo e gravando arquivos: **

write_file("yourfile.txt", "this string simulates data") assert read_file("yourfile.txt") == "this string simulates data"

**Lendo arquivos em tempo de compilação: **

const constant = static_read("yourfile.txt") # Returns a string at compile-time

Alterar permissões de arquivo

import std/os os.chmod("file.txt", 0o777)

⬆️ Python ⬆️ ⬇️ Nim ⬇️

import fusion/filepermissions chmod "file.txt", 0o777

Esses exemplos assumem que existe um arquivo ” file.txt “. Ambos usam as permissões octais de arquivo Unix. Além disso, uma API de nível inferior está disponível no módulo os.

Veja https://nim-lang.github.io/fusion/src/fusion/filepermissions.html

Alterar pasta temporariamente

import std/os

class withDir: # Unsafe without a del()

def __init__(self, newPath):
    self.newPath = os.path.expanduser(newPath)

def __enter__(self):
    self.savedPath = os.getcwd()
    os.chdir(self.newPath)

def __exit__(self, etype, value, traceback):
    os.chdir(self.savedPath)

with withDir("subfolder"): print("Inside subfolder") print("Go back outside subfolder")

⬆️ Python ⬆️ ⬇️ Nim ⬇️

import fusion/scripting

withDir "subfolder": echo "Inside subfolder" echo "Go back outside subfolder"

Esses exemplos assumem que existe uma pasta "subfolder". Opcionalmente, o Python tem dependências de terceiros que fazem a mesma coisa; os exemplos usam a biblioteca padrão. Algumas dependências de terceiros do Python podem converter o código dentro de withDir em um gerador, forçando você a alterar o código (comoreturn para yield etc), exemplos usam biblioteca padrão.

Veja https://nim-lang.github.io/fusion/src/fusion/scripting.html

Map e filter

def isPositive(arg: int) -> bool: return arg > 0

map(isPositive, [1, 2,-3, 5, -9]) filter(isPositive, [1, 2,-3, 5, -9])

⬆️ Python ⬆️ ⬇️ Nim ⬇️

proc isPositive(arg: int): bool = return arg > 0

echo map([1, 2,-3, 5, -9], isPositive) echo filter([1, 2,-3, 5, -9], isPositive)

Lambdas

variable: typing.Callable[[int, int], int] = lambda var1, var2: var1 + var2

⬆️ Python ⬆️ ⬇️ Nim ⬇️

var variable = proc (var1, var2: int): int = var1 + var2

Exemplo em várias linhas:

var anon = func (x: int): bool = if x > 0: result = true else: result = false

assert anon(9)

As funções anônimas do Python não podem usar return, mas podem no Nim:

example = lambda: return 42 assert example() == 42

Reclamações SyntaxError: sintaxe inválida.

⬆️ Python ⬆️ ⬇️ Nim ⬇️

let example = func: int = return 42 assert example() == 42

As funções anônimas do Python não podem usar yield, mas podem no Nim:

example = lambda: for i in range(0, 9): yield i

for _ in example(): pass

Reclamações SyntaxError: sintaxe inválida.

⬆️ Python ⬆️ ⬇️ Nim ⬇️

let example = iterator: int = for i in 0..9: yield i

for _ in example(): discard

Processos anônimos em Nimsão basicamente funções sem nome.

Decoradores

def decorator(argument): print("This is a Decorator") return argument

@decorator def function_with_decorator() -> int: return 42

print(function_with_decorator())

⬆️ Python ⬆️ ⬇️ Nim ⬇️

template decorator(argument: untyped) = echo "This mimics a Decorator" argument

func function_with_decorator(): int {.decorator.} = return 42

echo function_with_decorator()

Nim usa {. e.} porque pode ter vários decoradores juntos.

Também no Nim, trabalha-se com variáveis e tipos:

func function_with_decorator(): int {.discardable, inline, compiletime.} = return 42

let variable {.compiletime.} = 1000 / 2

type Colors {.pure.} = enum Red, Green, Blue

@ é uma função que converte de array para seq.

JSON

Python usa strings de várias linhas com JSON interno, Nim usa JSON literal diretamente no código.

import std/json

variable = """{ "key": "value", "other": true }""" variable = json.loads(variable) print(variable)

⬆️ Python ⬆️ ⬇️ Nim ⬇️

import json

var variable = %*{ "key": "value", "other": true } echo variable

Auto-execução do módulo principal

if name == "main": main()

⬆️ Python ⬆️ ⬇️ Nim ⬇️

when is_main_module: main()

Testes unitários

import std/unittest

def setUpModule(): """Setup: Run once before all tests in this module.""" pass

def tearDownModule(): """Teardown: Run once after all tests in this module.""" pass

class TestName(unittest.TestCase): """Test case description"""

def setUp(self):
    """Setup: Run once before each tests."""
    pass

def tearDown(self):
    """Teardown: Run once after each test."""
    pass

def test_example(self):
    self.assertEqual(42, 42)

if name == "main": unittest.main()

⬆️ Python ⬆️ ⬇️ Nim ⬇️

import std/unittest

suite "Test Name":

echo "Setup: Run once before all tests in this suite."

setup: echo "Setup: Run once before each test."

teardown: echo "Teardown: Run once after each test."

test "example": assert 42 == 42

echo "Teardown: Run once after all tests in this suite."

Assert com mensagens personalizadas

let a = 42 let b = 666 doAssert a == b, block: ("\nCustom Error Message!:" & "\n a equals to " & $a & "\n b equals to " & $b)

Testamento

Uma alternativa ao unittest. Está preparado para grandes projetos e tem mais funcionalidades.

Docstrings

Docstrings em Nim são comentários reStructuredText e MarkDown começando com##. ReStructuredText e MarkDown podem ser misturados, se você quiser.

Gere documentação HTML, Latex (PDF) e JSON a partir do código-fonte comnim doc file.nim.

O Nim pode gerar um gráfico de dependência DOT .dot comnim genDepend file.nim.

Você pode executar a documentação como Unittests com runnableExamples.

"""Documentation of module"""

class Kitten(object): """Documentation of class"""

def purr(self):
    """Documentation of method"""
    print("Purr Purr")

⬆️ Python ⬆️ ⬇️ Nim ⬇️

Documentation of Module ReSTructuredText and MarkDown

type Kitten = object ## Documentation of type age: int ## Documentation of field

proc purr(self: Kitten) =

Documentation of function

echo "Purr Purr"

Indentação opcional

Você pode escrever construções como if.. then e try.. except.. finally em uma única linha sem erros ou avisos; a indentação é opcional. Obviamente, isso só é uma boa ideia se o trecho for curto e simples.

let a = try: 1 + 2 except: 42 finally: echo "Inline try"

let b = if true: 2 / 4 elif false: 4 * 2 else: 0

for i in 0 .. 9: echo i

proc foo() = echo "Function"

(proc () = echo "Anonymous function")()

template bar() = echo "Template"

macro baz() = echo "Macro"

var i = 0 while i < 9: i += 1

when is_main_module: echo 42

CamelCase

Realmente não é, Nim é independente de estilo!

let camelCase = 42 # Declaring as camelCase assert camel_case == 42 # Using as snake_case

let snake_case = 1 # Declaring as snake_case assert snakeCase == 1 # Using as camelCase

let free style = 9000 assert free_style == 9000

**Esse recurso permite que o Nim interopere perfeitamente com várias linguagens de programação com diferentes estilos de nomeação. **

Para obter um código mais homogêneo, você pode aplicar um estilo de caixa padrão usando o comando do compilador —styleCheck:hint. Nim verificará o estilo do seu código antes da compilação, semelhante ao pycodestyle em Python. Se você quiser um estilo ainda mais rígido, você pode usar —styleCheck:error.

O Nim vem com um formatador automático de código embutido chamado Nimpretty.

Muitas linguagens de programação não diferenciam maiúsculas e minúsculas, como: PowerShell, SQL, PHP, Lisp, Assembly, Batch, ABAP, Ada, Visual Basic, VB.NET, Fortran, Pascal, Forth, Cobol, Scheme, Red, Rebol.

Se você está começando do zero, pode usar nomes semelhantes aos do Python enquanto aprende. Isso não produzirá um erro, a menos que você diga ao compilador que deseja isso.

def x proc/func

Nim usa proc para funções normais, que é a abreviação de “procedimento”.

Use func para quando sua rotina não puder e não deve acessar variáveis globais ou locais de thread (veja também: funções puras).

Nim tem rastreamento de efeitos colaterais.

Você não pode usar echo dentro de func, porque echo muda stdout, o que é um efeito colateral. Em vez disso, use debugEcho.

Veja também:

Se você está começando do zero, você pode usar proc para todas as funções enquanto aprende. Isso não dará um erro.

Assíncrono

O Nim tem a assíncrona embutida há muito tempo. Funciona como você pode esperar com async, await, Future, etc.

asyncdispatch é um módulo para escrever código simultâneo usando a sintaxe async/await.

Future é um tipo (como uma Future em Python ou uma Promise em JavaScript).

{.async.} é um pragma que converte funções em assíncronas (como async def em Python).

Vamos converter o asyncio oficial do Python Hello World para Nim:

async def main(): print("Hello ...") await asyncio.sleep(1) print("... World!")

asyncio.run(main())

⬆️ Python ⬆️ ⬇️ Nim ⬇️

proc main() {.async.} = echo("Hello ...") await sleep_async(1) echo("... World!")

wait_for main()

A assíncrona interna é implementada usando metaprogramação (macros, modelos, pragmas, etc.).

Descrição AsyncCheck waitFor await
Espera que a Future seja concluída ✔️ ✔️
Ignora a Future ✔️
Retorna o resultado da Future ✔️ ✔️
Disponível apenas dentro do async ✔️

Async é apenas uma macro em Nim, sem necessidade de alterar a sintaxe da linguagem. É como um decorador em Python, só que mais poderoso.

Também no Nim, a mesma função pode ser assíncrona e síncrona ao mesmo tempo, com o mesmo código, com o mesmo nome.

Em Python, quando você tem uma biblioteca "foo", você pode precisar de foo(sync) e aiofoo (async), que geralmente estão em projetos, repositórios, desenvolvedores e APIs completamente diferentes. Isso não é necessário no Nim, ou raramente visto, graças a esse recurso.

Como o async é apenas uma macro no Nim, você também pode criar seu próprio assíncrono do seu jeito.

Veja também asyncfile, asyncnet,asyncstreams, asyncftpclient,asyncfutures.

Eu tenho que saber C?

Você nunca precisa realmente editar manualmente o C, da mesma forma que no Python você nunca edita manualmente os arquivos .pyc.

No Nim, você codifica escrevendo Nim, da mesma forma que em Python você codifica escrevendo Python.

Modelos (Templates)

Um modelo substitui sua invocação pelo corpo do modelo em tempo de compilação.

Essencialmente, o compilador copiará e colará um pedaço de código para você.

Um modelo nos permite ter construções semelhantes a uma função sem qualquer sobrecarga ou dividir funções enormes em partes menores.

Muitos nomes de funções e variáveis podem poluir o namespace local. As variáveis dentro dos modelos não existem fora do modelo. Os modelos não existem no namespace em tempo de execução (se você não os exportar). Os modelos podem otimizar determinados valores se forem conhecidos em tempo de compilação.

Os templates não podem importar nem exportar de bibliotecas automaticamente implicitamente. Os modelos não “importam automaticamente” símbolos usados dentro de si mesmos. Se você usar qualquer biblioteca importada no corpo de um modelo, deverá importar essa biblioteca ao invocar esse modelo.

Dentro dos modelos, você não pode usar return porque um modelo não é uma função.

Os modelos permitem que você implemente APIs bonitas e de alto nível para o uso diário, mantendo os detalhes otimizados de baixo nível fora de sua cabeça eDRY.

Python with open (” file.txt “, mode = “r”) as file: implementado usando um modelo:

![Animação explicativa do modelo](https://raw.githubusercontent.com/juancarlospaco/nim-presentation-slides/master/templates.gif “Animação explicativa do modelo”)

O GIF não é perfeito, mas uma aproximação preguiçosa e simplificada!

Essa não é a maneira de ler arquivos no Nim, apenas um exercício.

Este modelo não é perfeito, mas uma aproximação preguiçosa. É um exercício para o leitor tentar melhorá-lo ;P

template withOpen(name: string, mode: char, body: untyped) = let flag = if mode == 'w': fmWrite else: fmRead # "flag" doen't exist outside of this template let file {.inject.} = open(name, flag) # Create and inject file variable, file exists outside of this template because of {.inject.} try: body # body is the code passed as argument finally: file.close() # Code after the code passed as argument

withOpen("testing.nim", 'r'): # Mimic Python with open("file", mode='r') as file echo "Hello Templates" # Code inside the template, this 2 lines are "body" argument on the template echo file.read_all() # This line uses "file" variable

Se você está começando do zero, não se preocupe, você pode usar funções para tudo enquanto aprende.

Como compartilhar variáveis entre funções?

O compartilhamento de variáveis entre funções é semelhante ao Python.

**Variável global: **

global_variable = ""

def function0(): global global_variable global_variable = "cat"

def function1(): global global_variable global_variable = "dog"

function0() assert global_variable == "cat" function1() assert global_variable == "dog" function0() assert global_variable == "cat"

⬆️ Python ⬆️ ⬇️ Nim ⬇️

var global_variable = ""

proc function0() = global_variable = "cat"

proc function1() = global_variable = "dog"

function0() assert global_variable == "cat" function1() assert global_variable == "dog" function0() assert global_variable == "cat"

**Atributo do objeto: **

class IceCream:

def init(self): self.object_attribute = None

def function_a(food): food.object_attribute = 9

def function_b(food): food.object_attribute = 5

food = IceCream() function_a(food) assert food.object_attribute == 9 function_b(food) assert food.object_attribute == 5 function_a(food) assert food.object_attribute == 9

⬆️ Python ⬆️ ⬇️ Nim ⬇️

type IceCream = object object_attribute: int

proc functiona(food: var IceCream) = food.object_attribute = 9

proc functionb(food: var IceCream) = food.object_attribute = 5

var food = IceCream() functiona(food) assert food.object_attribute == 9 functionb(food) assert food.object_attribute == 5 functiona(food) assert food.object_attribute == 9

Você pode passar funções como argumentos para outras funções, como em Python. Funções (procs) são objetos de primeira classe.

In-Place x Out-Place

Se você estiver migrando de uma linguagem interpretada, como Python ou JavaScript, você pode encontrar menções estranhas de “In-Place” e “Out-Place” em algum lugar de Nim. Se você não sabe o que isso significa, parece que o Nim tem funções duplicadas.

O Python aloca uma nova string ou objeto quando algo nele muda de alguma forma. Digamos que você tenha uma sequência enorme em uma variável e queira alterar um único caractere. Como as cadeias de caracteres do Python são imutáveis, a única solução é duplicar a string na memória, mas com a nova cópia tendo esse caractere alterado. Devolver uma nova cópia é uma operação “Out-Place”. A maior parte do Python funciona assim.

Por outro lado, as strings de Nim são mutáveis. No Nim, você pode alterar apenas o caractere que deseja alterar, em vez de copiar a string na memória. Algumas funções funcionam no local, outras funcionam em uma nova cópia. A documentação (geralmente) será qual.

usando macro, o Nim pode passar de uma função in-place para uma out-place.

Os módulos Nim stdlib projetados para o destino JavaScript geralmente funcionam em uma nova cópia. É assim que o destino do JavaScript é; não há API local nem benefícios em usá-la.

Alguns módulos Nim stdlib que funcionam em uma nova cópia podem ou não ser alterados para funcionar no local no futuro.

Exemplos:

import std/sugar # sugar.dup

func inplace_function(s: var string) = # Does not use "string" but "var string" s = "CHANGED"

In-Place algo.

var bar = "in-place" inplace_function(bar) ## Variable mutated in-place. assert bar == "CHANGED"

Out-Place algo.

assert "out-place".dup(inplace_function) == "CHANGED" ## Variable mutated on a new copy.

Importar arquivos Nim em Python

Sintaxe Python para Nim

Publicar no PYPI

Compilação silenciosa

Se você quiser que a compilação fique completamente silenciosa (você pode perder avisos e dicas importantes), você pode adicionar ao comando de compilação—hints:off —verbosity:0.

Ajuda do compilador

A ajuda do compilador é longa. Para torná-lo mais fácil de usar, apenas os comandos mais frequentes são mostrados com —help. Se você quiser ver a ajuda completa, você pode usar —fullhelp.

Modos de construção

Quando seu código estiver pronto para produção, você deve usar uma compilação Release, você pode adicionar ao comando de compilação -d:release.

Característica Versão de compilação Compilação de depuração
Rapidez Rápido Lento
Tamanho do arquivo Pequeno Grande
Otimizado ✔️
Tracebacks (Pilhas de Rastreamento) ✔️
Verificações em tempo de execução ✔️ ✔️
Verificações em tempo de compilação ✔️ ✔️
assert ✔️
doAssert ✔️ ✔️

MicroPython

O Nim compila em C, para que possa ser executado no Arduino e em hardware similar.

Tem várias estratégias de gerenciamento de memória para atender às suas necessidades, incluindo gerenciamento manual completo da memória. Os binários Nim são pequenos quando construídos para o Release e podem caber no pequeno armazenamento do hardware.

SuperCollider

O SuperCollider é C++, então ele pode ser reutilizado usando o Nim.

Teoricamente, os plug-ins do Nim SuperCollider devem ser tão rápidos quanto o código C. A metaprogramação de Nim nos permite criar DSLs compatíveis com LiveCoding.

Alguns projetos para o Nim LiveCoding:

ABC

Veja isso

Filosofia

A chave para entender o Nim é que o Nim foi projetado para ser tão rápido quanto C, mas para ser muito mais seguro. Muitas das decisões de design são baseadas em tornar mais difícil dar um tiro no próprio pé. Em Python, não há ponteiros (tudo é tratado como referência). Enquanto o Nim fornece dicas, o Nim oferece outras ferramentas mais seguras para suas necessidades diárias, enquanto os ponteiros são principalmente reservados para a interface com C e a programação de sistemas de baixo nível.

Ao contrário do Python, a maior parte do código Nim pode ser executada em tempo de compilação para realizar metaprogramação. Você pode fazer muitas das DSLs possíveis com decoradores/metaprogramação Python com macros e pragmas Nim. (E algumas coisas que você não pode!). Obviamente, isso requer alguns padrões diferentes e mais segurança de tipos.

⬆️ ⬆️ ⬆️ ⬆️