Hi, I am curios whether it is possible to have a class define specific members based on a "type". I want to implement something like this:
enum type {
REQUEST_A = 1,
REQUEST_B = 2
};
struct packet {
enum type type;
union {
struct a_args_s {
int arg1;
} a_args;
struct b_args_s {
int arg1;
int arg2;
} b_args;
};
};
The
enum type
can be done with
enum.IntEnum
but I am not sure how to do the
struct packet
. I know it could be done with
ctypes
but I want to do with with pure Python.
I could think of something with the
__setattr__()
method, where only the correct attributes are allowed to be set but I was wondering if there was a better way?
In Python I would create a base class and two subclasses
from abc import ABC
class Packet(ABC):
pass
class APacket(Packet):
def __init__(self, arg1: int):
self.arg1 = arg1
class BPacket(Packet):
def __init__(self, arg1: int, arg2: int):
self.arg1 = arg1
self.arg2 = arg2
(Apr-07-2025, 04:54 PM)Gribouillis Wrote: [ -> ]In Python I would create a base class and two subclasses
Yes, I thought of that too. But that does not achieve the goal because you have *two* different classes, not one class that has different members like the struct.
Could you elaborate in plain English what you want to achieve? For those not familiar with c++
I don't understand how "to have a class define specific members based on a "type"" relates to example. I see union of two methods with one/two arguments, but not different types (as I said, I am not familiar with c++)
As I understand it so far
functools.singledispatchmethod()
may be what you look for
https://docs.python.org/3/library/functo...atchmethod
(Apr-07-2025, 05:38 PM)buran Wrote: [ -> ]Could you elaborate in plain English what you want to achieve? For those not familiar with c++
I don't understand how "to have a class define specific members based on a "type"" relates to example. I see union of two methods with one/two arguments, but not different types (as I said, I am not familiar with c++)
As I understand it so far functools.singledispatchmethod()
may be what you look for https://docs.python.org/3/library/functo...atchmethod
The structure that I described can hold two different "packet" types. I can transfer the structure over a socket and on the receiving end decide what packet type it is based on the common
type
member. Based on that
type
member I know what other members are valid.
singledisplatchmethod
is pretty close but it works on methods, not members.
(Apr-07-2025, 05:05 PM)voidtrance Wrote: [ -> ]But that does not achieve the goal because you have *two* different classes, not one class that has different members like the struct.
The goal is far from clear. With my design, an instance of Packet can be either an instance of APacket or BPacket. You can still define functions that take Packet arguments and do whatever you want. You can also use polymorphism to implement methods that work transparently differently for APackets or BPackets.
Perhaps you could show us examples of how you want to use the type and why it would be better to have something that resembles a C union. The reason for the existence of C unions is mainly that C doesn't have classes and also that C structures are a very thin syntactic layer above the physical memory.
it looks like you try to write python code with C paradigm in mind and that is the problem
Maybe having two classes and singledispatch function on receiving end to process what you get would do..
If your interest is sending packets over a socket you should look at struct.
A literal interpretation of the C code.
import struct
from enum import IntEnum
class Request(IntEnum):
REQUEST_A = 0
REQUEST_B = 1
class Packet:
def __init__(self, request: Request, arg1: int, arg2: int = 0) -> None:
self.type = request
self.arg1 = arg1
self.arg2 = arg2
def as_bytes(self):
if self.type == Request.REQUEST_A:
return struct.pack(">II", self.type, self.arg1)
return struct.pack(">III", self.type, self.arg1, self.arg2)
print(Packet(Request.REQUEST_A, 42).as_bytes().hex())
print(Packet(Request.REQUEST_B, 42, 7).as_bytes().hex())
Output:
000000000000002a
000000010000002a00000007
If the only difference between the packet types is the number of arguments. I would do this:
import struct
class Packet:
def __init__(self, *args) -> None:
self.args = args
def as_bytes(self):
return struct.pack(f">I{len(self.args)}I", len(self.args), *self.args)
print(Packet(42).as_bytes().hex())
print(Packet(42, 7).as_bytes().hex())
Output:
000000010000002a
000000020000002a00000007