Hello world
Getting started
This tutorial demonstrates how to create a Swift class that can be called from Python using PythonSwiftLink. You'll learn how to wrap Swift code to make it accessible from Python, including passing data between the two languages and implementing callbacks. We'll build a simple HelloWorld class that showcases the fundamental patterns you'll use when bridging Swift and Python code.
HelloWorld Part 1
Call Swift from Python:
Let's start with a basic Swift class that we want to use from Python. This class has a simple method that prints a string to the console.
public class HelloWorld {
init() {
}
func send_string(text: String) {
print(text)
}
}
To make this Swift class accessible from Python, we need to add PySwiftKit decorators. The @PyClass decorator marks the class as exportable to Python, @PyInit wraps the initializer, and @PyMethod exposes methods to Python. We also need to define a module structure using @PyModule that lists all the classes we want to export.
Here's the same class with the necessary wrappers:
import PySwiftKit
import PySerializing
import PySwiftWrapper
@PyClass
class HelloWorld {
@PyInit
init() {
}
@PyMethod
func send_string(text: String) {
print(text)
}
}
@PyModule
struct hello_world: PyModuleProtocol {
static var py_classes: [any (PyClassProtocol & AnyObject).Type] = [
HelloWorld.self
]
}
The @PyModule struct defines a Python module named hello_world that contains our HelloWorld class. The py_classes array lists all classes that should be available in the module.
Once compiled, this creates a Python module that can be imported and used like any native Python class:
HelloWorld Part 2
Now let's explore how to implement callbacks from Swift back to Python. This is useful when you want Swift code to notify Python about events or results. We'll pass a Python function to Swift and call it from within a Swift method.
Make callback from Swift to Python:
@PyClass
class HelloWorld {
var _callback: PyPointer
@PyInit
init(callback: PyPointer) {
_callback = callback
}
@PyMethod
func send_string(text: String) {
callback(
text + " World"
)
}
/*
{} is not needed, PyCall will automatic fill out the function body
by default PyCall will target a variable that should be a underscored name
of the function, this case _callback.
but you can use the name: "another_name" in the argument input on @PyCall
to target another name.
*/
@PyCall
func callback(text: String)
}
from hello_world import HelloWorld
def callback(text: str):
print(text)
hw = HelloWorld(callback)
hw.send_string("Hello")
hw = HelloWorld(lambda text: print(text))
hw.send_string("Hello")
HelloWorld Part 3
Make callback from Swift to Python by converting a Py-Function/Method into a Swift Function Closure:
- Pros
- No need for storing a variable to call, that happens inside the closure.
- Cons
- By default the swift closure can't keep a strong ref to the temporary object of passed pyfunction. so its important that one of the following conditions are meet 1. The callback should happen within the life cycle of the function that was passed to it. 2. If the callback is ment to be called later on, then its importamt the pyfunction should be stored in python as a strongref that will keep the temporary object to the pyfunction alive, while callback is happening.