Pular para o conteúdo

18 · Módulos

Python com extern

Funções Python tipadas, pacotes nativos e chamadas async com CPython.

Nesta página

Importe o provider Python e declare a função com tipos Zolo. O corpo usa Python, incluindo indentação, comentários e imports locais. A chamada segue a sintaxe normal de uma função Zolo. O CPython executa dentro do processo.

Use um alias importado, agrupe funções pequenas e capture um valor Zolo em uma expressão Python. O import math local executa quando a função é chamada. Strings com aspas triplas e chaves em comentários mantêm seu significado nativo.

23-extern-python.zolo
Playground
// In-process CPython: ordinary Zolo headers, native Python bodies.

use plugin python::{python as py}

extern py fn add(a: int, b: int) -> int {
    # Braces in comments stay inside Python: } {
    return a + b
}

extern py {
    fn normalize(text: str) -> str {
        return text.strip().lower()
    }

    fn factorial(n: int) -> int {
        result = 1
        for value in range(2, n + 1):
            result *= value
        return result
    }
}

let original = "  Zolo  "
let clean: str = extern py {
    return original.strip().upper()
}
let greeting: str = extern py { return f"Hi {original.strip()}" }

extern py fn native_import(value: float) -> float {
    import math
    return math.sqrt(value)
}

extern py fn literal() -> str {
    value = '''Braces { } and "quotes"'''
    return value
}

print(add(20, 22))
print(normalize(original))
print(factorial(5))
print(clean)
print(greeting)
print(native_import(81.0))
print(literal())

// expected:

// 42

// zolo

// 120

// ZOLO

// Hi Zolo

// 9

// Braces { } and "quotes"

Copie records tipados, preserve inteiros de 64 bits e slots nulos em arrays, transfira bytes, passe uma closure Zolo e chame uma closure devolvida pelo Python. Um objeto Python mantém seus atributos e estado entre chamadas.

24-extern-python-data.zolo
Playground
// Exact values and live Python callables/objects share the ordinary syntax.

use plugin python::{python}

struct Payload { value: int, optional: int?, items: [int] }

extern python {
    fn echo(value: Payload) -> Payload {
        assert "optional" in value and value.optional is None
        return value
    }
    fn nullable(values: [int?]) -> [int?] { return values }
    fn empty() -> [int] { return [] }
    fn binary() -> bytes { return b"\x00\xff\x2a" }
    fn call(callback: fn(int) -> int) -> int { return callback(41) }
    fn factory(delta: int) -> fn(int) -> int { return lambda value: value + delta }
    fn counter() -> Any {
        class Counter:
            def __init__(self):
                self.value = 0
            def add(self, delta):
                self.value += delta
                return self.value
        return Counter()
    }
}

let copy = echo(Payload {
    value: 9223372036854775807,
    optional: nil,
    items: [7, 8, 9],
})
print(copy.value)
print(copy.optional == nil)
print(copy.items.len())
let values = nullable([7, nil, nil])
print(values.len())
print(values[1] == nil)
print(empty().len())
print(binary().len())
print(call(|value: int| value + 1))
let increment = factory(1)
print(increment(41))
let live = counter()
print(live.add(40))
live.value = 41
print(live.add(1))
print(live.value)

// expected:

// 9223372036854775807

// true

// 3

// 3

// true

// 0

// 3

// 42

// 42

// 40

// 42

// 42

Imports de fontes nativos expõem funções e classes anotadas. Caminhos relativos partem do arquivo Zolo que faz o import. Um módulo nativo inline também pode expor funções pelo seu namespace Zolo.

Importe funções e uma classe de tools.py, use um alias para a classe, aguarde um método async e acesse um campo anotado ou uma propriedade.

25-extern-python-imports.zolo
Playground
use plugin python::{python}

extern python from "./python_fixtures/tools.py" use {twice, later, Counter as Count}

extern python mod Tools {
    def greet(name: str) -> str:
        return f"Hello {name}"
}

print(twice(21))
print(await later(41))
let counter = Count(40)
print(counter.add(1))
print(await counter.add_later(1))
print(counter.value)
print(counter.total)
print(Tools.greet("Zolo"))

// expected:

// 42

// 42

// 41

// 42

// 42

// 42

// Hello Zolo

Aguarde coroutines Python e callbacks que retornam Futures Zolo. Combine chamadas com Promise.all, capture falhas e solicite o cancelamento de uma tarefa.

26-extern-python-async.zolo
Playground
use plugin python::{python}
use std::async::Promise

extern python async fn transform(value: int, callback: fn(int) -> Future<int>) -> int {
    import asyncio
    await asyncio.sleep(0.001)
    return await callback(value)
}

extern python async fn fail() -> int {
    import asyncio
    await asyncio.sleep(0.001)
    raise ValueError("Python failed")
}

extern python async fn wait_for_cancel() -> int {
    import asyncio
    await asyncio.sleep(60)
    return 0
}

// Completing the entry function keeps its spawned tasks alive.

extern python async fn schedule(callback: fn(int) -> int) -> int {
    import asyncio
    async def later():
        await asyncio.sleep(0.01)
        callback(42)
    asyncio.create_task(later())
    return 42
}

async fn increment(value: int) -> int {
    sleep 2ms
    return value + 1
}

async fn reject(value: int) -> int {
    sleep 1ms
    panic("callback failed")
    return value
}

async fn cancel_soon(future: Future<int>) -> bool {
    sleep 5ms
    future.cancel()
    return future.is_done()
}

let values = await Promise.all([
    transform(41, increment),
    transform(42, increment),
])
print(values[0])
print(values[1])
print(try { await transform(0, reject) } catch error { "callback caught" })
print(try { await fail() } catch error { "Python caught" })
let pending = wait_for_cancel()
print(await cancel_soon(pending))
let background: [int] = []
print(await schedule(|value: int| {
    background.push(value)
    return value
}))
sleep 40ms
print(background[0])

// expected:

// 42

// 43

// callback caught

// Python caught

// true

// 42

// 42

Use Python e C# no mesmo processo. Um callback de qualquer uma das linguagens pode voltar ao Zolo e chamar o outro provider.

28-extern-provider-coexistence.zolo
Playground
use plugin dotnet::{csharp}
use plugin python::{python}

extern csharp fn managed_add(a: int, b: int) -> int { return a + b; }
extern python fn python_add(a: int, b: int) -> int { return a + b }

extern python fn call_python(callback: fn(int) -> int) -> int {
    return callback(41)
}

extern csharp fn call_managed(callback: fn(int) -> int) -> int {
    return callback(41);
}

print(managed_add(20, 22))
print(python_add(20, 22))
print(call_python(|value: int| managed_add(value, 1)))
print(call_managed(|value: int| python_add(value, 1)))
print(python_add(managed_add(20, 1), 21))

// expected:

// 42

// 42

// 42

// 42

// 42

Selecione uma instalação CPython convencional e completa, da versão 3.9 à 3.14 com o GIL, usando ZOLO_PYTHON_HOME antes do primeiro uso e instale dependências nesse ambiente. NumPy precisa da instalação normal; 27-extern-python-numpy.zolo exercita sua extensão nativa. O build retém os fontes necessários, enquanto CPython e pacotes externos continuam como dependências da aplicação. PyTorch ainda não foi validado aqui.

Erros, completion, hover e ajuda de parâmetros analisam o texto atual sem executar código do usuário. VM, native e LLVM compartilham o contrato de execução. Um target wasm sem CPython rejeita o binding. O provider é experimental e foi validado no Windows com CPython 3.12, incluindo NumPy e executáveis sem os fontes originais. Linux/macOS e outras versões do interpretador ainda não foram validados em execução.

Veja também

Índice global

Encontre seu caminho pela Zolo

Experimente uma ideia

Comece por aqui

9 resultados

9 resultados

enpt-br