首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >手工复制dict底层代码中的一个问题:值不能是对象

手工复制dict底层代码中的一个问题:值不能是对象
EN

Stack Overflow用户
提问于 2019-10-10 20:01:56
回答 1查看 81关注 0票数 0

我尝试手动复制 python dict底层代码(它只能实现setitemgetitem),但我遇到了一个问题:我编写的 hashmap 只有在值类型是基本数据类型(如int、str等)时才能很好地工作--值的类型是object,hashmap只能设置项,python在获取对象类型的值时才会崩溃。

错误消息是“致命错误: GC对象已经跟踪”

我想有几个可能的问题:

definition

  • The getitem方法返回的PyObject*中有什么问题,但是python无法解析对象的指针

这是一些我要检查的病例

案例1:键和值类型都是基本的数据类型,运行良好

例2:键的类型是object,但是值类型是基本数据类型,它运行良好

例3:键‘type是基本数据类型,但是值类型是object,python在获取项时崩溃,即使值是空对象

案例4:键类型和值类型都是对象,结果与case3相同

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// the PyTypeObject
static PyTypeObject PyHashMap_Type = {
    PyVarObject_HEAD_INIT(NULL, 0)
    "hashmap",
    sizeof(PyMapObject),
    0,
    (destructor)PyHashMap_dealloc,              /* tp_dealloc */
    0,                                          /* tp_print */
    0,                                          /* tp_getattr */
    0,                                          /* tp_setattr */
    0,                                          /* tp_reserved */
    (reprfunc)repr_func,                        /* tp_repr */
    0,                                          /* tp_as_number */
    0,                                          /* tp_as_sequence */
    0,                                          /* tp_as_mapping */
    0,                                          /* tp_hash */
    0,                                          /* tp_call */
    0,                                          /* tp_str */
    PyObject_GenericGetAttr,                    /* tp_getattro */
    0,                                          /* tp_setattro */
    0,                                          /* tp_as_buffer */
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
        Py_TPFLAGS_BASETYPE | Py_TPFLAGS_DICT_SUBCLASS,         /* tp_flags */
    0,                              /* tp_doc */
    0,                              /* tp_traverse */
    0,                              /* tp_clear */
    0,                              /* tp_richcompare */
    0,                                          /* tp_weaklistoffset */
    0,                                          /* tp_iter */
    0,                                          /* tp_iternext */
    0,                               /* tp_methods */
    0,                                          /* tp_members */
    0,                                          /* tp_getset */
    0,                                          /* tp_base */
    0,                                          /* tp_dict */
    0,                                          /* tp_descr_get */
    0,                                          /* tp_descr_set */
    0,                                          /* tp_dictoffset */
    0,                                  /* tp_init */
    PyType_GenericAlloc,                        /* tp_alloc */
    _HashMap_New,                                   /* tp_new */
    PyObject_GC_Del,                            /* tp_free */
};

// the hashmap struct
typedef struct _mapkeysobject PyMapKeysObject;

typedef struct {
    Py_hash_t me_hash;                          
    PyObject *me_key;                           
    PyObject *me_value;                         
} PyMapKeyEntry;

struct _mapkeysobject {
    Py_ssize_t dk_size;                         
    Py_ssize_t dk_usable;
    PyMapKeyEntry dk_entries[1];                
};

typedef struct {
    PyObject_HEAD
    Py_ssize_t ma_used;
    PyMapKeysObject *ma_keys;
    PyObject **ma_values;
} PyMapObject;
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// get item methods, the python call GET_ITEM_WRAPPER
static PyObject* GET_ITEM_WRAPPER(PyObject* self, PyObject* args){
    PyObject * o = NULL;
    PyObject * key = NULL;
    if (!PyArg_ParseTuple(args, "OO",&o,&key)) {
        printf("error: arg list error");
        Py_RETURN_NONE;
    }
    PyObject* value = PyMap_GetItem(o, key);
    if (value == NULL) Py_RETURN_NONE;
    return value;
}

static PyObject* PyMap_GetItem(PyObject* o, PyObject* key){
    PyMapObject *mp;
    Py_hash_t hash;
    mp = (PyMapObject *)o;

    hash = PyObject_Hash(key);  
    if (hash == -1)
        return NULL;
    return searchmap(mp, key, hash);
}

static PyObject* searchmap(PyMapObject* mp, PyObject* key, Py_hash_t hash){
    PyObject **value_addr;  
    PyMapKeyEntry *ep;

    ep = lookup_function(mp, key, hash, &value_addr);

    if (ep == NULL) return NULL;
    return ep->me_value;
}

PyMapKeyEntry* lookup_function(PyMapObject* mp, PyObject* key, Py_hash_t hash, PyObject ***value_addr){
    size_t i;
    size_t perturb;
    size_t mask = DK_MASK(mp->ma_keys);                                
    PyMapKeyEntry *ep0 = &mp->ma_keys->dk_entries[0];                 
    PyMapKeyEntry *ep;

    i = (size_t)hash & mask;                                           
    ep = &ep0[i];
    if (ep->me_key == NULL || ep->me_key == key) {                     
        *value_addr = &ep->me_value;                                    
        return ep;                                                      
    }
    for (perturb = hash; ; perturb >>= PERTURB_SHIFT) {                    
        i = (i << 2) + i + perturb + 1;
        ep = &ep0[i & mask];
        if (ep->me_key == NULL || ep->me_key == key) {                  
            *value_addr = &ep->me_value;                                
            return ep;                                                  
        }
    }
    assert(0);          /* NOT REACHED */
    return 0;
}

我希望值类型可以是对象。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-10-11 05:23:37

我相信您已经搞砸了引用计数(尽管很难完全肯定不完整的代码)。

存储值的引用计数应该至少为一个(以表示将引用作为字典的一部分)。但是,在返回它时,应该是两个(一个用于持有的引用,另一个用于对返回值的引用)。

我在PyMap_GetItem中怀疑你应该这样做:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
PyObject *ret_val = searchmap(mp, key, hash);
Py_XINCREF(ret_val);
return ret_val;

(虽然我似乎没有在PyHashMap_Type中实际设置序列/映射方法,但是谁知道PyMap_GetItem是否真的被使用.)

这似乎适用于ints和string,原因是Python“实习生”小ints和短字符串,本质上保持对它们的持续引用。如果您继续查找,那么它最终会中断(每次您这样做,您失去一个参考)。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58334067

复制
相关文章
在 PHP 中如何解码 JSONP
如果是 JSON 数据,使用 json_decode 这个 PHP 函数就能解码,但是有些数据接口只提供了 JSONP 数据如何解码呢?
Denis
2023/04/15
7060
Python3 中文在URL中的编码解码
一些url的编码问题,在浏览器提交请求api时,如果url中包含汉子或者空格这类符号,就会被自动编码掉。呈现的结果是 ==> %xx%xx%xx。如果出现3个百分号为一个原字符则为utf8编码,如果2个百分号则为gb2312编码。下面为大家演示编码和解码的代码。
十四君
2019/11/27
1.5K0
python爬虫小知识,中文在url中的编码解码
有时候我们做爬虫经常会遇到这种编码格式,大概的样式为 %xx%xx%xx,对于这部分编码,python提供了一个quote的方法来编码,对应的解码为unquote方法。
云飞
2018/09/02
2.4K0
python爬虫小知识,中文在url中的编码解码
python爬虫小知识,中文在url中的编码解码
有时候我们做爬虫经常会遇到这种编码格式,大概的样式为 %xx%xx%xx,对于这部分编码,python提供了一个quote的方法来编码,对应的解码为unquote方法。
云飞
2018/09/11
1.6K0
html url编码、url解码
encodeURIComponent()编码的解码函数为 decodeURIComponent(),
全栈程序员站长
2022/07/19
4.8K0
html url编码、url解码
Javascript中的url编码与解码(详解)
摘要 本文主要针对URI编解码的相关问题做了介绍,对url编码中哪些字符需要编码、为什么需要编码做了详细的说明,并对比分析了Javascript中和编解码相关的几对函数escape / unescap
Angel_Kitty
2018/04/17
3K0
URL解码之URLEncoder
答:它是一种编码类型。当URL地址里包含非西欧字符的字符串时,系统会将这些字符转换成application/x-www-form-urlencoded字符串。
全栈程序员站长
2022/09/07
2.2K0
Python URL编解码 encode
python中对URL编码 urllib包中parse模块的quote和unquote from urllib import parse #这个是js的结果 # encodeURIComponent('中国') # "%E4%B8%AD%E5%9B%BD" jsRet='%E4%B8%AD%E5%9B%BD' print(parse.unquote(jsRet)) #输出:中国 print(jsRet==parse.quote('中国')) #输出:True
py3study
2020/01/07
2.6K0
loadrunner 脚本开发-url解码
url解码 by:授客 脚本结构如下: Action.c中的代码如下: int htoi(char *s) { int value = 0; int c = 0; c = ((u
授客
2019/09/12
5940
loadrunner 脚本开发-url解码
drupal linux安装,在Debian 10(Buster) Linux服务器中安装drupal 8.8.0的说明
按照本说明,你就可以成功的在Debian 10(Buster) Linux服务器中安装好drupal 8.8.0版本,已亲测能稳定运行。
全栈程序员站长
2022/09/09
1.3K0
drupal linux安装,在Debian 10(Buster) Linux服务器中安装drupal 8.8.0的说明
在 PostgreSQL 中解码 Django Session
会话(session)是任何基于 HTTP 的 web 框架的重要组成部分。它使得 web 服务器可以记录重复请求的 HTTP 客户端而不需要对每一次请求重新进行认证。记录会话的方式有多种。其中的一些方法不需要你服务器保持会话数据(如 JSON Web Tokens),而另外一些则需要。
Miigon
2022/10/27
3.2K0
在 PostgreSQL 中解码 Django Session
URL解码是什么?为什么要URL编码
我相信有很多朋友并不了解URL编码和解码有什么区别,也不知道这究竟有什么用。其实URL编码就是用来打包互联网上的各种表单输入的格式,对于汉字以及特殊的字符进行编码,就是URL编码。是一种特定的上下文资源定位的编码机制。也就是为了统一的命名网络中的资源。那么URL解码又是什么意思呢?
用户8739990
2021/07/16
2.8K0
URL解码是什么?为什么要URL编码
在 Php 中把 Allow_url_fopen 打開的風險[通俗易懂]
最近老是在我的 /tmp 裡頭, 發現有個多出來的 /tmp/cmdtemp 檔案. 也在 apache 的 error_log 中發現一些訊息如下:
全栈程序员站长
2022/09/13
2K0
go url 参数编码和解码
当需要将参数解码成url.Values{}类型,也就是 map[string][]string,使用
solate
2019/07/22
10.4K0
在HTML网页中巧用URL
首先,先放出一个地址给大家测试 http://cnbruce.com/test/htmlpro/?name=cnbruce&email=cnbruce@126.com 1,时下流行的(可能是吧,因为最
Java架构师必看
2021/03/22
1.7K0
学习PHP中的URL相关操作函数
在日常的业务开发过程中,我们经常会有处理 URL 链接的需求,所以今天学习的函数其实都是大家经常会使用的一些函数。在之前的工作过程中,其实我对这些函数都只是有一个模糊的概念,知道,但是真要用得时候还是要看下文档才能确定真正要使用的是哪一个函数。因此,今天我们就当做是一次复习练习,主要是区分和搞清楚每个函数真正的用处。
硬核项目经理
2021/11/10
2.5K0
Python3的URL编码解码
博主最近在用python3比较强大的Django开发web的时候,发现一些url的编码问题,在浏览器提交请求api时,如果url中包含汉子,就会被自动编码掉。呈现的结果是 ==> %xx%xx%xx。如果出现3个百分号为一个原字符则为utf8编码,如果2个百分号则为gb2312编码。下面为大家演示编码和解码的代码。
十里桃花舞丶
2019/02/20
3.9K0
drupal教程 Drupal安装指南
从开始学习Drupal到现在,安装的都是5.1,5.2的版本,由于使用的是wdp开发工具,所以安装基本上不需要做什么的,大概都是建立数据库名,修改一下settings.php配置文件,在浏览器里面敲入install.php,就可以自动完成安装了。所以说,drupal的安装是极其简单的,而且很容易上手。
全栈程序员站长
2022/08/15
2K0
Web开发须知:URL编码与解码
通常如果一样东西需要编码,说明这样东西并不适合传输。原因多种多样,如Size过大,包含隐私数据,对于Url来说,之所以要进行编码,是因为Url中有些字符会引起歧义。   例如,Url参数字符串中使用k
李海彬
2018/03/27
2.6K0
Web开发须知:URL编码与解码
在Java Web中设计的编解码
数据经过网络传输都是以字节为单位的,所以所有的数据都必须能够被序列化为字节。在Java中数据要被序列化,必须继承Serializable接口。
MickyInvQ
2020/09/27
1.3K0
在Java Web中设计的编解码

相似问题

如何在Firefox & Safari中停止自动url解码?

12

停止PHP解码我的url参数

28

在url php中解码ascii

114

停止Apache解码URL组件

10

PHP解码URL

31
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文