Inline python#
Code Example
Runnable Example in Jac and JacLib
# Inline Python - Embedding Python code blocks within Jac
# ===== Part 1: Basic Python Block =====
::py::
def python_hello():
return "Hello from Python!"
def python_add(a, b):
return a + b
::py::
with entry {
print("=== 1. Basic Python Block ===");
print(python_hello());
print(f"Python add: {python_add(10, 20)}");
}
# ===== Part 2: Python Block in Object =====
obj DataProcessor {
has data: list = [];
::py::
def process(self):
"""Process data using Python libraries."""
if not self.data:
return []
# Use Python built-ins
return [x * 2 for x in self.data if x > 0]
def analyze(self):
"""Statistical analysis with Python."""
if not self.data:
return {"mean": 0, "sum": 0}
return {
"mean": sum(self.data) / len(self.data),
"sum": sum(self.data),
"max": max(self.data),
"min": min(self.data)
}
::py::
}
with entry {
print("\n=== 2. Python Methods in Object ===");
processor = DataProcessor(data=[1, -2, 3, 4, -5, 6]);
processed = processor.process();
print(f"Processed data: {processed}");
stats = processor.analyze();
mean_val = round(stats['mean'], 2);
print(f"Statistics: mean={mean_val}, sum={stats['sum']}");
}
# ===== Part 3: Python Block with Jac Data Structures =====
::py::
def python_process_list(jac_list):
"""Python can work with Jac data structures."""
# Lists, dicts, and other collections are compatible
return [x ** 2 for x in jac_list]
def python_process_dict(jac_dict):
"""Process Jac dictionaries in Python."""
return {k: v * 2 for k, v in jac_dict.items()}
::py::
with entry {
print("\n=== 3. Python Processing Jac Data ===");
jac_list = [1, 2, 3, 4, 5];
squared = python_process_list(jac_list);
print(f"Squared: {squared}");
jac_dict = {"a": 10, "b": 20, "c": 30};
doubled = python_process_dict(jac_dict);
print(f"Doubled dict: {doubled}");
}
# ===== Part 4: Python Libraries Integration =====
::py::
import json
import math
def format_json(data):
"""Use Python's json library."""
return json.dumps(data, indent=2)
def math_operations(x):
"""Use Python's math library."""
return {
"sqrt": math.sqrt(x),
"log": math.log(x),
"sin": math.sin(x)
}
::py::
with entry {
print("\n=== 4. Python Libraries ===");
data = {"name": "Jac", "version": 1.0, "features": ["OSP", "Python interop"]};
json_str = format_json(data);
print(f"JSON output:\n{json_str}");
math_result = math_operations(16);
log_val = round(math_result['log'], 2);
print(f"Math: sqrt={math_result['sqrt']}, log={log_val}");
}
# ===== Part 5: Python in Node with State =====
node MathNode {
has value: float = 0.0;
has computed: dict = {};
::py::
def compute_all(self):
"""Compute various mathematical properties."""
import math
v = self.value
self.computed = {
"square": v ** 2,
"cube": v ** 3,
"sqrt": math.sqrt(abs(v)),
"is_even": v % 2 == 0
}
return self.computed
::py::
}
with entry {
print("\n=== 5. Python in Nodes ===");
math_node = MathNode(value=9.0);
results = math_node.compute_all();
print(f"Node value: {math_node.value}");
print(f"Computed: square={results['square']}, cube={results['cube']}");
}
# ===== Part 6: Python Block Accessing Jac Archetypes =====
obj Counter {
has count: int = 0;
::py::
def increment(self, by=1):
"""Increment counter (Python method)."""
self.count += by
return self.count
def reset(self):
"""Reset counter."""
self.count = 0
::py::
}
with entry {
print("\n=== 6. Python Methods Accessing Jac State ===");
counter = Counter();
counter.increment(5);
counter.increment(3);
print(f"Counter after increments: {counter.count}");
counter.reset();
print(f"Counter after reset: {counter.count}");
}
# ===== Part 7: Mixed Jac and Python Methods =====
obj Calculator {
has history: list = [];
# Jac method
def add_jac(value: int) {
self.history.append(value);
return sum(self.history);
}
::py::
# Python method
def add_python(self, value):
"""Python version of add."""
self.history.append(value)
return sum(self.history)
def get_stats(self):
"""Python statistics on history."""
if not self.history:
return {"avg": 0, "total": 0}
return {
"avg": sum(self.history) / len(self.history),
"total": sum(self.history),
"count": len(self.history)
}
::py::
}
with entry {
print("\n=== 7. Mixed Jac/Python Methods ===");
calc = Calculator();
calc.add_jac(10);
calc.add_python(20);
calc.add_jac(30);
stats = calc.get_stats();
avg_val = round(stats['avg'], 1);
print(f"Stats: avg={avg_val}, total={stats['total']}, count={stats['count']}");
}
with entry {
print("\n✓ Inline Python complete!");
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
|
Jac Grammar Snippet
Description
Inline Python in Jac
Jac supports embedding Python code blocks using the ::py::
delimiter syntax, enabling seamless integration with Python libraries and existing Python code.
Basic Python Block
Lines 4-10 demonstrate the simplest Python embedding. Python code is delimited by ::py::
markers at the beginning and end. Functions defined in Python blocks are directly callable from Jac code (lines 14-15).
Python Block Syntax
The ::py::
delimiter:
- Opens a Python code block (line 4)
- Closes the block with a matching ::py::
(line 10)
- Contains valid Python code using Python syntax (indentation-based, no semicolons)
- Can appear at module level or within archetype bodies
Python Methods in Objects
Lines 19-41 show Python methods within a Jac object. Python methods:
- Use self
to access Jac member variables (line 25: self.data
)
- Follow Python syntax and conventions
- Can use Python built-ins and comprehensions
- Are called like normal methods from Jac (lines 46, 49)
Data Interoperability
Lines 55-76 demonstrate Jac-Python data exchange. Data structures seamlessly pass between Jac and Python: - Jac lists work as Python lists (line 70) - Jac dicts work as Python dicts (line 74) - Return values integrate naturally into Jac code
Python Libraries Integration
Lines 79-106 show importing and using Python libraries. Standard Python libraries and third-party packages are fully available within ::py::
blocks. Import statements work normally (lines 80-81).
Python in Nodes
Lines 109-135 demonstrate Python methods in node definitions. Python methods in nodes can:
- Access node state via self.value
(line 117)
- Modify node attributes (line 118)
- Import libraries locally (line 116)
- Return computed results (line 124)
Mixed Jac and Python Methods
Lines 166-205 show combining Jac and Python methods in the same object. Objects can have both Jac methods (lines 170-173) and Python methods (lines 177-191). Both types:
- Access the same self.history
attribute
- Are called the same way from Jac code (lines 198-200)
- Can modify shared state
Usage Contexts for Python Blocks
Context | Example Line | Purpose |
---|---|---|
Global scope | 4-10 | Define utility functions |
Object body | 22-40 | Add Python methods to objects |
Node body | 113-125 | Add Python methods to nodes |
Mixed with Jac | 169-191 | Combine Jac and Python methods |
When to Use Inline Python
Use Python for: - Computationally intensive operations - Leveraging existing Python libraries - Complex numerical/statistical operations - String processing with Python's rich ecosystem - Integration with Python-only APIs
Use Jac for: - Object-Spatial Programming features - Graph operations and traversal - Walker-node interactions - OSP-specific patterns
Data Flow Diagram
flowchart LR
JacCode[Jac Code] -->|Call| PyFunc[Python Function]
PyFunc -->|Access| JacData[Jac Data Structures]
JacData -->|Lists, Dicts| PyProcess[Python Processing]
PyProcess -->|Return| PyResult[Python Result]
PyResult -->|Use| JacCode
PyBlock[::py:: Block] -->|Import| PyLibs[Python Libraries]
PyLibs -->|Use| PyFunc
Method Access Patterns
flowchart TD
Object[Jac Object/Node] --> JacMethod["Jac Methods (def)"]
Object --> PyMethods["Python Methods (::py::)"]
JacMethod -->|Access| State[Shared State<br/>self.attributes]
PyMethods -->|Access| State
State -->|Available| Both[Both Method Types]
Best Practices
Organize imports at the top of Python blocks:
Use Python for library integration:
Mix Python and Jac strategically:
Common Patterns
State modification from Python:
Using Python libraries:
Python comprehensions:
Key Points
::py::
delimiters mark Python code blocks- Python blocks can appear at global scope or in archetypes
- Python code follows Python syntax (indentation, no semicolons)
- Jac data structures (lists, dicts) work seamlessly in Python
- Python methods access Jac state via
self
- Standard and third-party Python libraries are fully available
- Objects can mix Jac and Python methods
- Return values from Python integrate naturally into Jac
- Use Python for computation, Jac for OSP features