Python массив строк в корне TTree

Я делаю некоторую работу с модулем CERN pyROOT и пытаюсь сохранить массив строк в виде листа в двоичном дереве. Чтобы сделать это, я должен передать ему массив, очевидно, используя не списки или словари, а модуль массива. Модуль поддерживает стандартные массивы C, из символов, целых чисел и т. Д., Но кто-нибудь знает, как я могу их вложить, чтобы получить массив строк или, фактически, массив символьных массивов? Или я зашел слишком далеко, и мне нужно ненадолго отступить от клавиатуры:)?

Код:

import ROOT

rowtree = ROOT.TTree("rowstor", "rowtree")

ROOT.gROOT.ProcessLine(
    "struct runLine {\
    Char_t test[20];\
    Char_t test2[20];\
    };" );
from ROOT import runLine
newline = runLine()
rowtree.Branch("test1", newline, "test/C:test2")

newline.test = ["AbcDefgHijkLmnOp","aaaaaaaaaaaaaaaaaaa"]

rowtree.Fill()

Ошибка:

python branchtest
Traceback (most recent call last):
  File "branchtest", line 14, in <module>
    newline.test = ["AbcDefgHijkLmnOp","aaaaaaaaaaaaaaaaaaa"]
TypeError: expected string or Unicode object, list found

Мне интересно, можно ли превратить список, показанный в этом примере, в массив строк.

2 ответа

Решение

Массив char и список Python строк Python - это две совершенно разные вещи.

Если вы хотите ветку, содержащую массив символов (одну строку), тогда я предлагаю использовать встроенный в Python bytearray тип:

import ROOT
# create an array of bytes (chars) and reserve the last byte for null
# termination (last byte remains zero)
char_array = bytearray(21)
# all bytes of char_array are zeroed by default here (all b'\x00')

# create the tree
tree = ROOT.TTree('tree', 'tree')
# add a branch for char_array
tree.Branch('char_array', char_array, 'char_array[21]/C')
# set the first 20 bytes to characters of a string of length 20
char_array[:21] = 'a' * 20
# important to keep the last byte zeroed for null termination!
tree.Fill()
tree.Scan('', '', 'colsize=21')

Выход из tree.Scan('', '', 'colsize=21') является:

************************************
*    Row   *            char_array *
************************************
*        0 *  aaaaaaaaaaaaaaaaaaaa *
************************************

Итак, мы знаем, что дерево правильно принимает байты.

Если вы хотите сохранить список строк, то я предлагаю использовать std::vector<std::string>:

import ROOT

strings = ROOT.vector('string')()

tree = ROOT.TTree('tree', 'tree')
tree.Branch('strings', strings)
strings.push_back('Hello')
strings.push_back('world!')
tree.Fill()
tree.Scan()

Выход из tree.Scan() является:

***********************************
*    Row   * Instance *   strings *
***********************************
*        0 *        0 *     Hello *
*        0 *        1 *    world! *
***********************************

В цикле вы хотели бы strings.clear() перед заполнением новым списком строк в следующей записи.

Теперь пакет rootpy (см. Также репозиторий на github) обеспечивает лучший способ создания деревьев в Python. Вот пример того, как вы можете использовать массивы char более дружественным образом с rootpy:

from rootpy import stl
from rootpy.io import TemporaryFile
from rootpy.tree import Tree, TreeModel, CharArrayCol

class Model(TreeModel):
    # define the branches you want here
    # with branchname = branchvalue
    char_array = CharArrayCol(21)
    # the dictionary is compiled and cached for later
    # if not already available
    strings = stl.vector('string')

# create the tree inside a temporary file
with TemporaryFile():
    # all branches are created automatically according to your model above
    tree = Tree('tree', model=Model)

    tree.char_array = 'a' * 20
    # attemping to set char_array with a string of length 21 or longer will
    # result in a ValueError being raised.
    tree.strings.push_back('Hello')
    tree.strings.push_back('world!')
    tree.Fill()
    tree.Scan('', '', 'colsize=21')

Выход из tree.Scan('', '', 'colsize=21') является:

***********************************************************************
*    Row   * Instance *            char_array *               strings *
***********************************************************************
*        0 *        0 *  aaaaaaaaaaaaaaaaaaaa *                 Hello *
*        0 *        1 *  aaaaaaaaaaaaaaaaaaaa *                world! *
***********************************************************************

Смотрите другой пример использования TreeModelс рупией здесь:

https://github.com/rootpy/rootpy/blob/master/examples/tree/model_simple.py

Вы определили test член runLine как массив из 20 символов:

Char_t test[20];\

Но затем вы пытаетесь передать ему список из двух строк:

newline.test = ["AbcDefgHijkLmnOp","aaaaaaaaaaaaaaaaaaa"]

Это не имеет никакого смысла в C (или CINT) или в Python, поэтому, конечно, это не имеет никакого смысла и в PyROOT.

Кроме того, в вашем вопросе, кажется, много путаницы. Вы говорите, что вам нужно передать PyROOT "массив, очевидно, используя не списки или словари, а модуль массива"… но PyROOT не особенно заботится о Python array модуль. Вы отметили свой вопрос numpyЭто означает, что вы можете думать о numpy скорее, чем array как "модуль массива", но в прошлый раз, когда я проверял (что, правда, довольно давно), они вообще не взаимодействовали; вам нужно было явно попросить numpy экспортировать буферы, если вы хотите что-то, что вы можете передать PyROOT.

Другие вопросы по тегам