Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/299.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python cython中str和Py_UNICODE的内部地址和内存地址_Python_String_Memory_Cython_String Interning - Fatal编程技术网

Python cython中str和Py_UNICODE的内部地址和内存地址

Python cython中str和Py_UNICODE的内部地址和内存地址,python,string,memory,cython,string-interning,Python,String,Memory,Cython,String Interning,上下文:我构建了一个树数据结构,在cython的节点中存储单个字符。现在我想知道如果我实习所有这些角色是否能节省内存。以及我应该使用Py_UNICODE作为变量类型还是常规str。这是我的精简节点对象,使用Py_UNICODE: 来自libc.stdint cimport uintptru\t 从cpython cimport PyObject cdef类节点(): cdef: 公共Py_UNICODE字符 def uu init uu(self,Py_UNICODE字符): self.char

上下文:我构建了一个树数据结构,在cython的节点中存储单个字符。现在我想知道如果我实习所有这些角色是否能节省内存。以及我应该使用Py_UNICODE作为变量类型还是常规str。这是我的精简节点对象,使用Py_UNICODE:

来自libc.stdint cimport uintptru\t
从cpython cimport PyObject
cdef类节点():
cdef:
公共Py_UNICODE字符
def uu init uu(self,Py_UNICODE字符):
self.character=字符
def存储器(自):
返回&自我角色
如果第一次尝试查看字符是否自动插入。如果我在Python中导入该类并创建具有不同或相同字符的多个对象,我将得到以下结果:

a=节点(“a”)
a_py=a个字符
a2=节点(“a”)
b=节点(“b”)
打印(a.内存(),a2.内存(),b.内存())
# 140532544296704 140532548558776 140532544296488
打印(id(a字符)、id(a2字符)、id(b字符)、id(a字符))
# 140532923573504 140532923573504 140532923840528 140532923573504
因此,我会得出结论,Py_UNICODE不是自动插入的,在python中使用id()不会给我实际的内存地址,而是一个副本的内存地址(我假设python会自动插入单个UNICODE字符,然后只返回给我该字符的内存地址)

接下来,我尝试在使用str时做同样的事情。简单地用str替换Py_UNICODE,我现在就是这么做的:

%%cython
从libc.stdint cimport uintpr\t
从cpython cimport PyObject
cdef类节点():
cdef:
公共str字符
定义初始化(self,str字符):
self.character=字符
def存储器(自):
返回(self.character)
我得到的结果如下:

。。。
打印(a.内存(),a2.内存(),b.内存())
# 140532923573504 140532923573504 140532923840528
打印(id(a字符)、id(a2字符)、id(b字符)、id(a字符))
# 140532923573504 140532923573504 140532923840528 140532923573504
基于此,我首先认为cython中也包含单字符str,cython不需要从python复制字符,这就解释了为什么id()和.memory()提供相同的地址。但后来我尝试使用更长的字符串,得到了相同的结果,从中我可能不想得出结论,更长的字符串也会自动插入?如果我使用Py_-UNICODE,我的树也会使用更少的内存,因此如果str被拘留,这没有多大意义,但是Py_-UNICODE不是。有人能给我解释一下这种行为吗?那我怎么去实习呢

(我正在Jupyter进行测试,以防有什么不同)


编辑:删除了不必要的节点id比较,而不是字符。

您有一个误解
PY_UNICODE
不是python对象,它是一个

只有字符串对象(至少是其中的一些对象)被插入,但不是类型为
wchar\u t
的简单C变量(或者实际上是任何C类型的变量)。这也没有任何意义:一个
wchar\u t
很可能是32位大,而保持一个指向内部对象的指针需要花费64位

因此,变量
self.character
(类型
PY_UNICODE
)的内存地址永远不会相同,只要
self
是不同的对象(无论
self.character
具有哪个值)

另一方面,在纯python中调用
a.character
时,Cython知道该变量不是简单的32位整数,并通过将其自动转换为unicode对象(
character
is property right?)。返回的字符串(即
a_py
)可能是“interned”或不是

当此字符的代码点(即latin1)为空时,它将获得-否则不会。前256个仅由一个字符组成的unicode对象具有-not(因此在上一节中使用了“interned”)

考虑:

>>> a="\u00ff" # ord(a) =  255
>>> b="\u00ff"
>>> a is b
# True
但是


关键在于:使用
PY_UNICODE
——即使没有插入,也比插入字符串/UNICODE对象便宜(4字节)(8字节用于引用+一次插入对象的内存)而且比不插入对象便宜得多(这可能发生)

或者,更好,正如@user2357112所指出的,用于确保保证4个字节的大小(这是能够支持所有可能的unicode字符所必需的)
wchar\u t
可以小到1个字节(即使这在当今可能非常罕见)。如果您对所使用的字符了解更多,您可以回到
Py_UCS2
Py_UCS1


但是,当使用
Py_UCS2
Py_USC1
时,必须考虑到Cython不支持从unicode到unicode的转换,如
Py_UCS4
(或弃用的
Py_unicode
)的情况,并且必须手动完成,例如:

%%cython 
from libc.stdint cimport uint16_t

# need to wrap typedef as Cython doesn't do it
cdef extern from "Python.h":
    ctypedef uint16_t Py_UCS2

cdef class Node:
    cdef:
        Py_UCS2 character_

    @property
    def character(self):
        # cython will do the right thing for Py_USC4
        return <Py_UCS4>(self.character_) 

    def __init__(self, str character):
        # unicode -> Py_UCS4 managed by Cython
        # Py_UCS4 -> Py_UCS2 is a simple C-cast
        self.character_ = <Py_UCS2><Py_UCS4>(character)
sizeof(A)
是24而不是17(请参阅)


如果有人真的在追求这两个字节,那么还有一条更大的鱼要钓:不要让节点成为Python对象,因为这会为不需要的多态性和引用计数带来16个字节的开销——这意味着整个数据结构都应该用C编写,并在Python中作为一个整体进行包装。然而,这里也要确保以正确的方式分配内存:通常的C运行时内存分配器有32或64字节对齐,即分配较小的大小仍然会导致使用32/64字节。

显然是的。这是漫长的一天。移除它。(:虽然
PY_UNICODE
更便宜,但仍然不应该使用它。它已被弃用,并且它的大小不总是足以容纳所有字符。您不希望您的应用程序因为有人试图使用鸡蛋而崩溃
%%cython 
from libc.stdint cimport uint16_t

# need to wrap typedef as Cython doesn't do it
cdef extern from "Python.h":
    ctypedef uint16_t Py_UCS2

cdef class Node:
    cdef:
        Py_UCS2 character_

    @property
    def character(self):
        # cython will do the right thing for Py_USC4
        return <Py_UCS4>(self.character_) 

    def __init__(self, str character):
        # unicode -> Py_UCS4 managed by Cython
        # Py_UCS4 -> Py_UCS2 is a simple C-cast
        self.character_ = <Py_UCS2><Py_UCS4>(character)
struct A{
    long long int a;
    long long int b;
    char ch;
};