Specifying libcpp.string type for __contains__ in cython

I am implementing a cython shell for some C ++ data structure that will have C ++ strings as both keys and values.

I have C ++ methods prototyped in pxd for a class with key / value type templates (sorry, I never worked with C ++, only C, so I'm not sure of the correct terminology, let me know if this is unclear)

Then I define the class in the .pyx file to be able to call from python that terminates the instance my_type[string, string]:

from libcpp.string cimport string
cdef class MyType:
    ## This field is declared in .pxd:
    # cdef my_type[string, string]* thisptr

    def __cinit__(self, f=None):
        self.thisptr = new my_type[string, string]()

    def __init__(self, arg=None):
        if hasattr(arg, 'fileno'):
            self.load(arg)
        elif isinstance(arg, int):
            self.thisptr.resize(arg)
        elif isinstance(arg, str):
            with open(arg, 'rb') as f:
                self.load(f)
        elif arg is not None:
            raise ValueError("Cannot interpret argument of type %s" % type(arg))        

    def __contains__(self, string item):
        return self.thisptr.count(item) > 0

now I have another .pyx script in which I test this functionality in which I define a python string, assign bytes to a C ++ string and try to use the operator in:

from libcpp.string cimport string

def test():
    m = MyType()
    bytes_key = 'asdf'
    bytes_val = 'jkl;'
    cdef string key = bytes_key
    cdef string val = bytes_val
    m[key] = val
    print('len(): %d' % len(m))
    assert len(m) == 1, len(m)
    print('__repr__(): %r' % (m, ))
    assert key in m

if I comment the last line, everything compiles and I get output

len(): 0
len(): 1
__repr__(): {'asdf': 'jkl;'}

, assert, :

Error compiling Cython file:
------------------------------------------------------------
...
    cdef string val = bytes_val
    m[key] = val
    print('len(): %d' % len(m))
    assert len(m) == 1, len(m)
    print('__repr__(): %r' % (m, ))
    assert key in m
              ^
------------------------------------------------------------

test_internal.pyx:72:15: Invalid types for 'in' (string, MyType)

libcpp.string.string , , libc.stdint.uint16_t, . , . !

, assert m.__contains__(key), .

cimport MyType if not my_obj.__contains__(key) ( key cdef 'd, string), , TypeError: an integer is required...

+4
1

, . , , : , , __setitem__...

, , :

def __contains__(MyType self, item):
    if not isinstance(item, bytes):
        item = bytes(item, "UTF-8")
    return (self.thisptr.count(item) > 0)

python 3 str bytes ( ++ string), : string , .

, mwe:

decl.pxd

from libcpp.map cimport map as my_type
from libcpp.string cimport string

cdef class MyType:
   cdef my_type[string, string]* thisptr

decl.pyx

cdef class MyType:

    def __cinit__(MyType self, arg=None):
        self.thisptr = new my_type[string, string]()     

    def __contains__(MyType self, item):
        if not isinstance(item, bytes):
            item = bytes(item, "UTF-8")
        return (self.thisptr.count(item) > 0)

    def __setitem__(MyType self, key, value):
        if not isinstance(key, bytes):
            key = bytes(key, "UTF-8")
        if not isinstance(value, bytes):
            value = bytes(value, "UTF-8")
        self.thisptr[0][key] = value

    def __len__(MyType self):
       return self.thisptr.size()

EDIT: setup.py ( test.pyx ctest.pyx)

from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext

setup(
      cmdclass = {'build_ext': build_ext},
      package_data = { '': ['*.pxd'] },
      ext_modules = [
         Extension("ctest",
                   ["ctest.pyx"],
                   language='c++',
                   include_dir=["."]),
         Extension("decl",
                   ["decl.pyx"],
                   language='c++',
                   include_dir=["."])]
)

EDIT2: , , , ++ string :

key1 = b'asdf'
key2 = 'asdf'
assert key1 in m
assert key2 in m
+2

All Articles