-
Dear experts, For various reasons, I wrote a class inheriting from ak.Array implementing a few methods. For instance: class Wrapper(ak.Array):
def __init__(self, data):
super().__init__(data)
def test(self):
print("OK")
ak_array = Wrapper([[1,2], [], [3]])
ak_array.test() This worked with version 1.5.1 of awkward array, but does not work anymore with version 1.7.0. The error is the following:
Indeed, the type of Is there a way to write a class deriving from ak.Array or should this be prohibited? |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 7 replies
-
This change was caused by ccd7537. I don't know what @jpivarski expects to happen with custom array classes in this context. A solution that is guaranteed to work in future is the ak.behavior['wrapper_cls'] = Wrapper
ak_array = ak.with_parameter(
[[1,2], [], [3]],
"__array__",
"wrapper_cls"
) Awkward uses the behaviours mechanism to allow an association between methods and data, without binding them together explicitly. This mechanism extends to records, i.e. collections of arrays, which can provide OO interfaces by defining a particular behaviour class for the record. For more information, see here: https://awkward-array.readthedocs.io/en/latest/ak.behavior.html |
Beta Was this translation helpful? Give feedback.
-
Thanks, @agoose77, for answering this! You made all the points I wanted to except the "why". You can make subclasses of https://awkward-array.readthedocs.io/en/latest/ak.behavior.html When you do array manipulations, you end up creating new array objects all the time—every slice is a new array object from Python's point of view (though the data buffers themselves share a lot of memory for efficiency). The
Oh, yeah, the old behavior worked by accident. Before that fix, it wasn't checking |
Beta Was this translation helpful? Give feedback.
-
@agoose77 and @jpivarski thank you very much for your answers. I had completely missed the point of If my class also defines some attributes, and a class inherits from another one, I figured out I can proceed like this: class Wrapper0(ak.Array):
def __init__(self, data):
ak.behavior["Wrapper0"] = Wrapper0
if "__array__" not in ak.parameters(data):
data = ak.with_parameter(
data,
"__array__",
"Wrapper0",
)
super().__init__(data)
self.attr0 = "attr0"
def test0(self):
print("0")
class Wrapper1(Wrapper0):
def __init__(self, data):
ak.behavior["Wrapper1"] = Wrapper1
if "__array__" not in ak.parameters(data):
data = ak.with_parameter(
data,
"__array__",
"Wrapper1",
)
super().__init__(data)
self.attr1 = "attr1"
def test1(self):
print(self.fields)
data = {
"Jet_pt": [[1,2], [], [3]],
"MET": [1, 2, 3],
}
ak_array = Wrapper1(ak.Array(data))
ak_array.test0()
ak_array.test1()
print(ak_array.attr0)
print(ak_array.attr1) (posting in case it is of interest for someone or in case you have a comment about it). Thank you very much again. |
Beta Was this translation helpful? Give feedback.
Thanks, @agoose77, for answering this! You made all the points I wanted to except the "why".
You can make subclasses of
ak.Array
andak.Record
, but you have to assign them throughak.behavior
. There's a big write-up of that here:https://awkward-array.readthedocs.io/en/latest/ak.behavior.html
When you do array manipulations, you end up creating new array objects all the time—every slice is a new array object from Python's point of view (though the data buffers themselves share a lot of memory for efficiency). The
ak.behavior
is a set of rules for applying your subclasses to new array objects depending on "parameters" in the array, so even if your data type is buried deeply in a data struc…