Python cython中不同字符串的相同内存地址

Python cython中不同字符串的相同内存地址,python,string,memory,cython,Python,String,Memory,Cython,我用cython编写了一个树对象,它有许多节点,每个节点包含一个unicode字符。我想测试如果我使用Py_UNICODE或str作为变量类型,字符是否会被插入。我试图通过创建node类的多个实例并获取每个实例的字符内存地址来测试这一点,但不知何故,我最终得到了相同的内存地址,即使不同的实例包含不同的字符。这是我的密码: 来自libc.stdint cimport uintptru\t cdef类节点(): cdef: 公共str字符 公共无符号整数计数 公共节点lo、eq、hi 定义初始化(s

我用cython编写了一个树对象,它有许多节点,每个节点包含一个unicode字符。我想测试如果我使用Py_UNICODE或str作为变量类型,字符是否会被插入。我试图通过创建node类的多个实例并获取每个实例的字符内存地址来测试这一点,但不知何故,我最终得到了相同的内存地址,即使不同的实例包含不同的字符。这是我的密码:

来自libc.stdint cimport uintptru\t
cdef类节点():
cdef:
公共str字符
公共无符号整数计数
公共节点lo、eq、hi
定义初始化(self,str字符):
self.character=字符
def存储器(自):
返回并返回self.character[0]
我试图比较Python中的内存位置,如下所示:

a=节点(“a”)
a2=节点(“a”)
b=节点(“b”)
打印(a.内存(),a2.内存(),b.内存())

但是打印出来的内存地址都是一样的。我做错了什么?

显然,你正在做的并不是你认为你会做的

self.character[0]
不返回第一个字符的地址/引用(例如,数组的情况就是这样),而是一个-value(即使用的32位整数),它被复制到堆栈上的一个(本地、临时)变量

在函数中,
&self.character[0]
获取堆栈上局部变量的地址,每次调用
内存
时,该地址始终相同

为了更清楚,这里是与
char*c_字符串
的区别,其中
&c_字符串[0]
提供了
c_字符串
中第一个字符的地址

比较:

%%cython
from libc.stdint cimport uintptr_t

cdef char *c_string = "name";
def get_addresses_from_chars():
    for i in range(4):
        print(<uintptr_t>&c_string[i])

cdef str py_string="name";
def get_addresses_from_pystr():
    for i in range(4):
        print(<uintptr_t>&py_string[i])
您可以这样看:
c_字符串[…]
是一个
cdef
功能,但是
py_字符串[…]
是一个python功能,因此无法返回每个构造的地址

要影响堆栈布局,可以使用递归函数:

def memory(self, level):
    if level==0 :
        return <uintptr_t>&self.character[0]
    else:
        return self.memory(level-1)
或者在Cython中,执行与
id
相同的操作(稍微快一点):


如果要获取unicode对象中第一个代码点的地址(与字符串的地址不同),可以使用
self.character
,Cython将用调用来替换它,例如:


i、 e.
“a”
是实习生,地址与
“b”
不同,代码点Buffer的地址与包含它的对象的地址不同(正如人们所期望的)。

我在Cython中不知道的尾部调用优化投票@BlueSheepToken尾部调用优化可以由c编译器(例如gcc)在编译生成的c代码时执行,但大多数情况下不会发生,因为Cython创建的代码并不是尽可能直接的。谢谢您的回答!我有一些后续问题:如果我将str更改为Py_UNICODE,那么memory()会以某种方式返回字符的序号值,而不是内存地址?以上是否意味着如果我像这样使用str,角色将被拘留?casting不会创建一个新的python str,它将被拘留吗?因为如果我用str替换Py_UNICODE,看起来内存消耗实际上会增加。如果我使用更长的字符串[a=Node(“aaa”);a2=Node(“aaa”)],它们仍然具有相同的地址:|@克里斯蒂安娜丹:我试图让我的答案更清楚。但我不明白你在说什么:1)str在Python3中是unicode。2) 什么是角色?字符串不是字符。3) 字符串是否被插入取决于很多事情,并且是一个实现细节,它会随着版本的变化而变化(例如)-我不会依赖它。@如果我不清楚,很抱歉。1) 我知道字符串是unicode对象。我的意思是,我可以将节点类中的变量类型声明从“cdef public str character”更改为“cdef public Py_UNICODE character”。如果这样做,a)memory()将返回字符的序数值,而不是内存地址;b)内存消耗将减少。2) 如何确保每个Node.character中存储的内容都是interned?我知道我在那里只有一个字符,所以我怎样才能实习这些字符并只存储指针——这应该会大大减少内存,不是吗?
def memory(self, level):
    if level==0 :
        return <uintptr_t>&self.character[0]
    else:
        return self.memory(level-1)
>>> id(a.character) == id(a2.character)
# True
%%cython
from libc.stdint cimport uintptr_t
from cpython cimport PyObject
...
    def memory(self):
        # cast from object to PyObject, so the address can be used
        return <uintptr_t>(<PyObject*>self.character)
 >>> ...
 >>> print(a.memory(), a2.memory(), b.memory())
 # ...5800 ...5800 ...5000
%%cython
...   
def memory(self):
    return <uintptr_t>(<Py_UNICODE*>self.character), id(self.character)
>>> ...
>>> print(a.memory(), a2.memory(), b.memory())
# (...768, ...800) (...768, ...800) (...144, ...000)