I have a data structure in my code that (for the sake of an MWE) is a list where the first element is a string, and the second element is an integer. For example:
foo: MyStructure = ["hello", 42]
.
Now, since there is an ordering to this structure, usually I would use a tuple and instead do:
foo: Tuple[str, int] = ("hello", 42)
.
But I explicitly want to be able to easily modify elements within the structure. In particular, I want to be able to set foo[0] = "goodbye"
, which cannot be done if foo
is a tuple.
What is the best way to go about typing this structure?
(I don't think that this question is opinion-based, since I think there is likely clear rationale for how to handle this that would be preferred by most developers.)
Right now, the main solution I can think of is to not actually type the structure correctly, and instead to define my own structure whose true type is listed in a comment:
# MyStructure = [str, int]
MyStructure = List[Union[str, int]]
foo: MyStructure = ["hello", 42]
Is there a better way?
You don't want a list or a tuple; you want a custom class representing the type-level product of str
and int
. A dataclass is particularly useful here.
from dataclasses import dataclass
@dataclass
class MyStructure:
first: str
second: int
foo: MyStructure = MyStructure("hello", 42)
assert foo.first == "hello"
assert foo.second = 42
If you really want to access the components using integer indices, you can add a __getitem__
method to the class:
@dataclass
class MyStructure:
first: str
second: int
def __getitem__(self, key) -> Union[str,int]:
if key == 0:
return self.first
elif key == 1:
return self.second
else:
raise IndexError(key)
In addition, an instance of MyStructure
uses less memory than the corresponding list:
>>> foo = MyStructure("hello", 42)
>>> import sys
>>> sys.getsizeof(foo)
48
>>> sys.getsizeof(["hello", 42])
72