Python Differences
Scriptling is inspired by Python but has intentional limitations for embedded scripting. This page documents what’s NOT supported and key differences.
Python Features NOT Supported
Language Features
| Feature | Notes |
|---|---|
async/await |
Not supported; use runtime.background() for concurrency |
yield from and generator.send() |
Generator functions with yield work, but delegation (yield from iterable) and send(value) are not supported; loop or iterate manually |
| Multiple inheritance | Only single inheritance is supported |
| Metaclasses | Custom metaclasses are not supported |
| Descriptors | The descriptor protocol is not implemented: a __get__ method is never invoked, attribute access returns the object itself |
Regex backreferences (\1, \2) |
RE2 engine used; no backreferences, lookaheads, or lookbehinds: see regex docs |
Built-in Functions NOT Supported
| Function | Alternative |
|---|---|
input() |
Only registered when a stdin reader is attached (CLI scripts); absent in embedded and server evaluators — see sys |
open() |
Use os.read_file() and os.write_file() |
compile(), eval(), exec() |
Dynamic code execution not supported |
globals(), locals() |
Scope introspection not available |
vars() |
vars(obj) works like obj.__dict__; vars() with no argument returns the module-level bindings |
__import__() |
Use import statement |
memoryview(), bytearray() |
Advanced byte manipulation not supported; bytes() and b"..." literals work |
complex() |
Complex numbers not implemented |
Standard Library NOT Included
| Module | Notes |
|---|---|
asyncio |
Use runtime.background() for concurrency |
threading, multiprocessing |
Use runtime.background: shared=True for shared-env threads, default for isolated parallel workers |
socket |
Low-level networking; use requests for HTTP |
pickle, marshal |
Use json for serialization |
struct |
Binary data structures |
array |
Typed arrays |
ctypes, cffi |
Foreign function interfaces |
sqlite3 |
Database access |
xml |
Use html.parser for HTML |
email, smtplib |
Email handling |
argparse, optparse |
Command-line parsing |
unittest, doctest |
Use assert statements |
pdb |
Debugger |
profile, cProfile |
Profiling tools |
Exception Handling Differences
| Feature | Notes |
|---|---|
| Exception hierarchy | Built-in types group as in Python: BaseException, LookupError and ArithmeticError are catchable parents, and the OSError family (FileNotFoundError, FileExistsError, …) derives from OSError |
| Exception groups (Python 3.11+) | Not supported |
except* syntax |
Not supported |
raise X from Y |
Accepted and re-raises X as in Python, but the chain is not introspectable: there is no __cause__/__context__ attribute and no chained traceback |
| Custom exception classes | Can inherit from a built-in exception type (class MyError(Exception)) and from other user exception classes; multiple inheritance does not apply |
Other Differences
| Feature | Notes |
|---|---|
Module __all__ |
Export lists are not used |
__future__ imports |
Not applicable |
__next__ returning a StopIteration() value |
Ends iteration without yielding it — only raising StopIteration signals end-of-iteration |
| Type annotations | Parsed and ignored, including def f(a: int) -> str, x: int = 5, and self.n: int = 0; there is no __annotations__ and no runtime checking, and comma subscripts parse as tuple indexes (dict[str, int]) |
**kwargs order |
The **kwargs dict holds the names in alphabetical order, not call order (deterministic, but not Python’s order) |
| Subclassing built-in containers | class C(dict), class C(list), class C(OrderedDict) and class C(defaultdict) are not supported (Counter can be subclassed) |
OrderedDict |
An ordinary insertion-ordered dict: move_to_end() and popitem(last=False) work, but they are also accepted on plain dicts, and it prints like a plain dict |
obj.__dict__ |
A fresh dict view per access that writes through to the object; obj.__dict__ = {...} is an AttributeError, names are not mangled (__x stays __x), and SomeClass.__dict__ is not available |
| Dicts from other formats | Dicts built from YAML, TOML, MessagePack and plugin results have their keys in sorted order (those formats give no key order); json.loads(), requests .json() and literals keep document/insertion order |
| Walrus in a comprehension | y in [y for x in a if (y := f(x))] binds inside the comprehension and does not leak to the enclosing scope, unlike Python (PEP 572); use the collected list instead |
type(x).__name__ |
type(x) returns the type name directly as a string (type(42) is "INTEGER", a custom class instance gives its class name), so there is no type object to hang .__name__ on — use type(x) itself; a raised built-in exception reports the class it was raised as ("ValueError") |
| Generator expressions | (x for x in a) syntax works but is evaluated eagerly into a list, not a lazy generator object; over an endless iterator such as itertools.count() it raises an error instead of hanging (any(map(f, itertools.count())) does terminate: map/filter and any/all pull lazily over them) |
\N{name} string escapes |
Not supported; use \u with the code point |
| Number methods | bit_length(), bit_count(), is_integer(), hex(), fromhex() and as_integer_ratio() work (see Built-in Functions); other number attributes (x.real, x.imag, (5).to_bytes()) do not exist |
dir() with no argument |
Lists the builtin names, not the local scope |
Everything not listed on this page behaves as in Python 3; see the Language Guide.
Key Behavioral Differences
Library Import
Imports work as in Python, but a library is only importable if the host has made it available. The CLI provides the standard and extended libraries; an embedding Go program registers the ones it wants.
from module import * is not supported. Python 3.15’s lazy import is accepted but imports immediately. See Imports.
Default Timeout
requests calls time out after 5 seconds by default (Python’s requests waits indefinitely). Pass timeout= for slower endpoints:
response = requests.get("https://slow-api.com", timeout=30)File System Access
There is no built-in open(); files are read and written through libraries such as os (os.read_file(), os.write_file()) and pathlib. Whether those libraries exist, and what they can reach, depends on the host: a bare embedded interpreter has no filesystem libraries unless the Go host registers them with allowed paths, while the scriptling CLI registers them with full filesystem access unless --allowed-paths restricts it. See the Security Guide.
import os
content = os.read_file("data.txt") # instead of open("data.txt").read()Errors and Exceptions Are Catchable, Except SystemExit
try/except catches interpreter errors (with the exception type inferred from the message, so except NameError: works) and explicitly raised exceptions. SystemExit (from sys.exit()) is different from Python: no except clause can catch it; finally blocks run and the exit returns to the Go host. See Error Handling.
See Also
- Syntax Rules - Scriptling syntax
- Functions - Function parameters
- Error Handling - try/except, raise, and SystemExit
- Classes - Class limitations