Python Classes
Classes are defined using py.class
method.
| pub const Animal = py.class("Animal", struct {
pub const __doc__ = "Animal docstring";
const Self = @This();
kind: u64,
pub fn __new__(args: struct { kind: u64 }) !Self {
return .{ .kind = args.kind };
}
pub fn get_kind(self: *Self) !u64 {
return self.kind;
}
pub fn get_kind_name(self: *Self) !py.PyString {
return switch (self.kind) {
1 => py.PyString.create("Dog"),
2 => py.PyString.create("Cat"),
3 => py.PyString.create("Parrot"),
else => py.RuntimeError.raise("Unknown animal kind"),
};
}
});
|
The returned type of py.class
is the same struct that has been used to define the class.
You can refer to your own state by taking pointer to self self: *@This()
. Classes' internal
state is only accessible from the extension code. Currently pydust doesn't support declaring
Python class attributes.
Instantiation and constructors
Pydust provides convenience function py.init
that creates an instance of pydust defined class. This
will still create a PyObject internally and return the internal state tied to that object. You can
then call methods on that object as usual which will avoid dispatching the method through Python.
If your class defines a pub fn __new__(args: struct{}) !Self
function, then it is possible to instantiate
it from Python. Otherwise, it is only possible to instantiate the class from Zig using py.init
.
| pub const Owner = py.class("Owner", struct {
pub const __doc__ = "Takes care of an animal";
// Allows this class to be instantiated from Python
pub fn __new__() !@This() {
return .{};
}
pub fn name_puppy(args: struct { name: py.PyString }) !*Dog {
return try py.init(Dog, .{ .name = args.name });
}
});
|
Subclasses
Creating subclasses is similar to classes, with the exception of needing to provide references
to your base classes.
| pub const Dog = py.subclass("Dog", &.{Animal}, struct {
pub const __doc__ = "Adorable animal docstring";
const Self = @This();
// A subclass of a Pydust class is required to hold its parent's state.
animal: Animal,
name: py.PyString,
pub fn __new__(args: struct { name: py.PyString }) !Self {
args.name.incref();
return .{
.animal = .{ .kind = 1 },
.name = args.name,
};
}
pub fn __del__(self: *Self) void {
self.name.decref();
}
pub fn __len__(self: *const Self) !usize {
_ = self;
return 4;
}
pub fn __str__(self: *const Self) !py.PyString {
var pystr = try py.PyString.create("Dog named ");
return pystr.append(self.name);
}
pub fn __repr__(self: *const Self) !py.PyString {
var pyrepr = try py.PyString.create("Dog(");
pyrepr = try pyrepr.append(self.name);
return pyrepr.appendSlice(")");
}
pub fn __add__(self: *const Self, other: py.PyString) !*Self {
const name = try self.name.append(other);
return py.init(Self, .{ .name = name });
}
pub fn get_name(self: *const Self) !py.PyString {
return self.name;
}
pub fn make_noise(args: struct { is_loud: bool = false }) !py.PyString {
if (args.is_loud) {
return py.PyString.create("Bark!");
} else {
return py.PyString.create("bark...");
}
}
pub fn get_kind_name(self: *Self) !py.PyString {
var super = try py.super(Dog, self);
var superKind = try super.get("get_kind_name");
var kindStr = try py.PyString.checked(try superKind.call0());
kindStr = try kindStr.appendSlice(" named ");
kindStr = try kindStr.append(self.name);
return kindStr;
}
});
|
Subclasses can then use builtins like super
to invoke methods on their parent types. Bear in mind that Python superclasses aren't actually fields
on the subtype. Thus it is only possible to refer to supertype methods from that supertype.
Binary Operators
Pydust supports classes implementing binary operators (e.g. __add__
or bitwise operators).
| pub fn __add__(self: *const Self, other: py.PyString) !*Self {
const name = try self.name.append(other);
return py.init(Self, .{ .name = name });
}
|
The self parameter must be a pointer to the class type. The other parameter can be of any Pydust supported type.
Supported binary operators are: __add__
, __sub__
, __mul__
, __mod__
, __divmod__
, __pow__
,
__lshift__
, __rshift__
, __and__
, __xor__
, __or__
, __truediv__
, __floordiv__
,
__matmul__
, __getitem__
.