Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/283.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/15.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引用计数以便调试c扩展_Python_Python 3.x_Pytest_Reference Counting_Python C Extension - Fatal编程技术网

了解python引用计数以便调试c扩展

了解python引用计数以便调试c扩展,python,python-3.x,pytest,reference-counting,python-c-extension,Python,Python 3.x,Pytest,Reference Counting,Python C Extension,我正在编写一个c扩展,并想在pytest中测试它 我测试的部分内容是对象上的引用计数是否正确。因此,我用纯python构建了一个小测试,这让我感到困惑 从Ipython我得到: In [1]: x = 153513514215 In [2]: import sys In [3]: sys.getrefcount(x) Out[3]: 2 所以,一切都很好,一份来自作业,一份来自来电者 但是,下面的脚本(stackoverflow_test.py)给出了以下结果 import sys de

我正在编写一个c扩展,并想在pytest中测试它

我测试的部分内容是对象上的引用计数是否正确。因此,我用纯python构建了一个小测试,这让我感到困惑

从Ipython我得到:

In [1]: x = 153513514215

In [2]: import sys

In [3]: sys.getrefcount(x)
Out[3]: 2
所以,一切都很好,一份来自作业,一份来自来电者

但是,下面的脚本(stackoverflow_test.py)给出了以下结果

import sys

def test_ref_count_int():
    x = 677461248192962146784178
    assert sys.getrefcount(x) == 2

def test_ref_count_str():
    y = 'very long and probbably very unique string'
    assert sys.getrefcount(y) == 2

def normal_te_st():
    x = 222677461248192962146784178
    y = '!!!!very long and probbably unique string!!!!'
    print ('x refcount = {}'.format(sys.getrefcount(x)))
    print ('y refcount = {}'.format(sys.getrefcount(y)))

if __name__ == '__main__':
    normal_te_st()
当我将其作为普通python脚本运行时

$ python3 stackoverflow_test.py
x refcount = 4
y refcount = 4
为什么是4而不是2

当我用pytest运行它时

$ python3 -m pytest stackoverflow_test.py
=================== test session starts ===================
platform linux -- Python 3.4.3, pytest-3.0.7, py-1.4.33, pluggy-0.4.0
rootdir: /opt/projects/0001_Intomics/00005_TextMining/jcr/textmining/tests, inifile:
collected 2 items

stackoverflow_test.py FF

======================== FAILURES =========================
___________________ test_ref_count_int ____________________

    def test_ref_count_int():
        x = 677461248192962146784178
>       assert sys.getrefcount(x) == 2
E       assert 3 == 2
E        +  where 3 = <built-in function getrefcount>(677461248192962146784178)
E        +    where <built-in function getrefcount> = sys.getrefcount

stackoverflow_test.py:7: AssertionError
___________________ test_ref_count_str ____________________

    def test_ref_count_str():
        y = 'very long and probbably very unique string'
>       assert sys.getrefcount(y) == 2
E       AssertionError: assert 3 == 2
E        +  where 3 = <built-in function getrefcount>('very long and probbably very unique string')
E        +    where <built-in function getrefcount> = sys.getrefcount

stackoverflow_test.py:11: AssertionError
$python3-m pytest stackoverflow\u test.py
=========================测试会话开始===================
平台linux——Python 3.4.3、pytest-3.0.7、py-1.4.33、pluggy-0.4.0
rootdir:/opt/projects/0001_Intomics/00005_TextMining/jcr/TextMining/tests,文件:
收集2项
stackoverflow_test.py FF
=====================================故障=========================
___________________测试参考计数____________________
def test_ref_count_int():
x=677461248192962146784178
>断言sys.getrefcount(x)==2
E断言3==2
E+式中3=(677461248192962146784178)
E+where=sys.getrefcount
stackoverflow_test.py:7:AssertionError
___________________测试参考计数____________________
def test_ref_count_str():
y='非常长且可能非常独特的字符串'
>断言sys.getrefcount(y)==2
断言错误:断言3==2
E+式中3=(“非常长且可能非常独特的字符串”)
E+where=sys.getrefcount
stackoverflow_test.py:11:AssertionError
为什么是3而不是2

问题:为什么会这样

  • python=4个引用计数
  • pytest=3个参考计数
  • ipython会话=2个参考计数

我希望它在所有3种情况下都像ipython一样,有人能解释发生了什么,并给我一些提示如何最好地测试我正在创建的对象。

代码中的文字存储在代码对象中。字节码堆栈是另一个参考:

>>> import dis
>>> def normal_te_st():
...     x = 222677461248192962146784178
...     y = '!!!!very long and probbably unique string!!!!'
...     print ('x refcount = {}'.format(sys.getrefcount(x)))
...     print ('y refcount = {}'.format(sys.getrefcount(y)))
...
>>> normal_te_st.__code__.co_consts
(None, 222677461248192962146784178, '!!!!very long and probbably unique string!!!!', 'x refcount = {}', 'y refcount = {}')
>>> dis.dis(normal_te_st)
  2           0 LOAD_CONST               1 (222677461248192962146784178)
              2 STORE_FAST               0 (x)

  3           4 LOAD_CONST               2 ('!!!!very long and probbably unique string!!!!')
              6 STORE_FAST               1 (y)

  4           8 LOAD_GLOBAL              0 (print)
             10 LOAD_CONST               3 ('x refcount = {}')
             12 LOAD_ATTR                1 (format)
             14 LOAD_GLOBAL              2 (sys)
             16 LOAD_ATTR                3 (getrefcount)
             18 LOAD_FAST                0 (x)
             20 CALL_FUNCTION            1
             22 CALL_FUNCTION            1
             24 CALL_FUNCTION            1
             26 POP_TOP

  5          28 LOAD_GLOBAL              0 (print)
             30 LOAD_CONST               4 ('y refcount = {}')
             32 LOAD_ATTR                1 (format)
             34 LOAD_GLOBAL              2 (sys)
             36 LOAD_ATTR                3 (getrefcount)
             38 LOAD_FAST                1 (y)
             40 CALL_FUNCTION            1
             42 CALL_FUNCTION            1
             44 CALL_FUNCTION            1
             46 POP_TOP
             48 LOAD_CONST               0 (None)
             50 RETURN_VALUE
LOAD_CONST
opcode从附加到code对象的
co_CONST
元组加载对象;该元组是一个引用
STORE_FAST
然后将其放入局部变量,这是第二个引用

然后是
LOAD\u FAST
opcode,它从本地存储中获取一个名称并将其放在堆栈上

最后但并非最不重要的一点是,将该值传递给
sys.getrefcount()
调用

如果你想了解什么引用了你的对象,你可能想看看;此函数在调用时排除自身和堆栈,因此您可以在心里添加+2:

>>> import gc
>>> def gc_demo():
...     x = 222677461248192962146784178
...     print(gc.get_referrers(x))
...
>>> gc_demo()
[(None, 222677461248192962146784178), <frame object at 0x106a25a98>]
导入gc >>>def gc_demo(): ... x=22267461248192962146784178 ... 打印(gc.get_参考(x)) ... >>>gc_demo() [(无,22267461248192962146784178),] 打印2个对象;
co_consts
元组和当前调用帧(对于局部变量)

py.test
执行一些附加操作,因此参考计数再次不同

您可能还想用C或C++文档来阅读扩展Python,其中的C API参考手册,最后但并非最不相同的,要学习如何创建一个Python构建,帮助您详细跟踪引用计数。


决不应依赖于对对象的特定数量的引用。我可以通过访问函数对象来为对象添加更多引用,例如(
foo=normal\u te\u st.\uuuu code\uuuu.co\u conts[1]
甚至在运行函数之前都会增加引用计数)。需要增加引用计数的是一个实现细节。请确保您自己的代码正确处理引用。

谢谢您的引用,我需要仔细考虑一下,但这个答案正是我所希望的。。。