Последовательность байтовых строк фиксированного размера в Cython - PullRequest
0 голосов
/ 17 мая 2018

Я новичок в Cython и у меня очень мало опыта работы с C, так что терпите меня.

Я хочу сохранить последовательность неизменяемых байтовых объектов фиксированного размера. Объект будет выглядеть так:

obj = (b'abc', b'1234', b'^&$#%')

Элементы в кортеже неизменны, но их длина произвольна.

То, что я пробовал, было чем-то вроде:

cdef char[3] *obj
cdef char* a, b, c
a = b'abc'
b = b'1234'
c = b'^&$#%'
obj = (a, b, c)

Но я получаю:

Storing unsafe C derivative of temporary Python reference

Может кто-нибудь указать мне правильное направление?

Бонусный вопрос: как набрать произвольно длинную последовательность этих 3-кортежей?

Спасибо!

1 Ответ

0 голосов
/ 17 мая 2018

Вы определенно близко!Кажется, есть две проблемы.

Во-первых, нам нужно изменить объявление obj так, чтобы оно читало, что мы пытаемся создать массив char* объектов, фиксированных до размера 3. Для этого вам нужнопоставить тип, затем имя переменной и только потом размер массива.Это даст вам желаемый массив char* в стеке.

Во-вторых, когда вы объявляете char* a, b, c, только a является char*, тогда как b и c являются просто char!Это проясняется в cython во время фазы компиляции, которая выводит для меня следующее предупреждение:

Non-trivial type declarators in shared declaration (e.g. mix of pointers and values). Each pointer declaration should be on its own line.

Поэтому вы должны сделать это вместо этого:

cdef char* obj[3]
cdef char* a
cdef char* b
cdef char* c
a = b'abc'
b = b'1234'
c = b'^&$#%'
obj = [a, b, c]

В качестве примечания выможно минимизировать ввод cdef, выполнив это для своего кода:

cdef:
    char* obj[3]
    char* a
    char* b
    char* c
a = b'abc'
b = b'1234'
c = b'^&$#%'
obj = [a, b, c]

Бонус:

На основе вашего уровня опыта работы с C и указателями вВ общем, я просто покажу более удобный для новичков подход с использованием структур данных C ++.C ++ имеет простые встроенные структуры данных, такие как vector, что эквивалентно списку Python.Альтернативой C было бы иметь указатель на структуру, обозначающую «массив» triplets.Затем вы лично отвечаете за управление памятью, используя такие функции, как malloc, free, realloc и т. Д.

Вот кое-что, с чего можно начать;Я настоятельно рекомендую вам самостоятельно следовать некоторым онлайн-учебникам по C или C ++ и адаптировать их к Cython, что после некоторой практики должно быть довольно тривиальным.Я показываю как файл test.pyx, так и файл setup.py, который показывает, как вы можете скомпилировать его с поддержкой c ++.

test.pyx

from libcpp.vector cimport vector

"""
While it can be discouraged to mix raw char* C "strings" wth C++ data types, 
the code here is pretty simple.
Fixed arrays cannot be used directly for vector type, so we use a struct.
Ideally, you would use an std::array of std::string, but std::array does not 
exist in cython's libcpp. It should be easy to add support for this with an
extern statement though (out of the scope of this mini-tutorial).
"""
ctypedef struct triplet:
    char* data[3]

cdef:
    vector[triplet] obj
    triplet abc
    triplet xyz

abc.data = ["abc", "1234", "^&$#%"]
xyz.data = ["xyz", "5678", "%#$&^"]
obj.push_back(abc)#pretty much like python's list.append
obj.push_back(xyz)

"""
Loops through the vector.
Cython can automagically print structs so long as their members can be 
converted trivially to python types.
"""
for o in obj:
    print(o)

setup.py

from distutils.core import setup
from Cython.Build import cythonize
from distutils.core import Extension

def create_extension(ext_name):
    global language, libs, args, link_args
    path_parts = ext_name.split(".")
    path = "./{0}.pyx".format("/".join(path_parts))
    ext = Extension(ext_name, sources=[path], libraries=libs, language=language,
            extra_compile_args=args, extra_link_args=link_args)
    return ext

if __name__ == "__main__":
    libs = []#no external c libraries in this case
    language = "c++"#chooses c++ rather than c since STL is used
    args = ["-w", "-O3", "-ffast-math", "-march=native", "-fopenmp"]#assumes gcc is the compiler
    link_args = ["-fopenmp"]#none here, could use -fopenmp for parallel code
    annotate = True#autogenerates .html files per .pyx
    directives = {#saves typing @cython decorators and applies them globally
        "boundscheck": False,
        "wraparound": False,
        "initializedcheck": False,
        "cdivision": True,
        "nonecheck": False,
    }

    ext_names = [
        "test",
    ]

    extensions = [create_extension(ext_name) for ext_name in ext_names]
    setup(ext_modules = cythonize(
            extensions, 
            annotate=annotate, 
            compiler_directives=directives,
        )
    )
...