标签: cpython

提取 SWIG 包装的 C++ 实例/指针以在 Cython 中使用

我有一个来自 SWIG 包装的 C++ 库的类的实例,我想从中提取其引用,以便能够在 Cython 文件中使用它,在该文件中,我通过使用直接链接到同一个 C++ 库更轻量级的自制 Cython 同类包装器。

我知道这不会像访问某些隐藏属性那么容易,但我想 SWIG 或 CPython 中可能有一些函数,如果从 Cython 中链接到它(也许是某些 PyObject_*?),可能会这样做。

不幸的是,我对 SWIG 或 CPython 内部的了解不够,无法知道如何做到这一点,或者在不修改 SWIG 绑定的源代码的情况下这是否真的可行。

c++ python swig cpython cython

4
推荐指数
1
解决办法
931
查看次数

CPython 的垃圾收集是否会进行压缩?

我正在和一个朋友聊天,比较语言,他提到 Java 的自动内存管理优于 Python,因为 Java 的压缩,而 Python 则没有——因此对于长时间运行的服务器,Python 是一个糟糕的选择。

没有进入哪个更好或更坏,他的说法是否正确 - CPython 的垃圾收集器是否不会压缩内存,因此,长时间运行的 Python 进程是否会随着时间的推移变得越来越碎片化?

我知道运行 CPython 的垃圾收集器是可选的。大多数情况下,它使用自动引用计数进行自动内存管理,一旦引用计数达到零,对象就会被释放——因此,就释放对象而言,CPython 的垃圾收集器唯一需要做的就是检测没有根集中的对象有一个引用。但我不知道除此之外它是否进行任何压缩的细节。

如果没有,那么长时间运行的 CPython 进程如何解决内存碎片问题?

python garbage-collection memory-management cpython

4
推荐指数
1
解决办法
707
查看次数

`PyTuple_Pack` 段错误

foo在 Python 扩展模块中有一个函数,它应该向 Python 返回一个整数元组。这可以使用Py_BuildValue以下方法轻松完成:

static PyObject* 
foo(PyObject* self, PyObject* args)
{
    int a = 0;
    int b = 0;

    /* calculations and stuff */

    PyObject* out = Py_BuildValue("(iii)", a, b, a+b);
    Py_INCREF(out);

    return out;
}
Run Code Online (Sandbox Code Playgroud)

而不是Py_BuildValue,我想使用PyTuple_Pack,它确保返回值确实是一个元组。

Python的C API文档说,PyTuple_Pack(3, a, b, a+b)相当于Py_BuildValue("(iii)", a, b, a+b)。这两个函数都返回一个新的类型引用PyPbject*

因此,鉴于上面的代码,

static PyObject* 
foo(PyObject* self, PyObject* args)
{
    /* ... */

    PyObject* out = PyTuple_Pack(3, a, b, a+b);
    Py_INCREF(out); …
Run Code Online (Sandbox Code Playgroud)

python cpython python-3.x python-extensions

4
推荐指数
1
解决办法
452
查看次数

python中的locals()和对象引用

我发现了一些关于 python 如何跟踪locals().

考虑以下脚本:

import gc


class T(object):
    pass


def func1():

    t = T()

    #locals()
    del t
    #locals()

    for o in gc.get_objects():
        if type(o) is T:
            print("STILL EXISTS")


func1()
Run Code Online (Sandbox Code Playgroud)

运行locals()注释的两个调用(如上)没有给我任何消息,表明T()创建的对象是垃圾收集的。

当我使用第一个locals()命令运行它(删除第一个注释)时,它似乎创建了一个包含对我的t对象的引用的字典。这本词典与任何名字都没有关联,所以我不希望这个 dict 能像没有被垃圾收集一样存在。

问题是,运行代码,我得到"STILL EXISTS". 即使我t从函数命名空间中删除,该对象也不会被垃圾收集,因为返回的 dictlocals()仍在引用它。

有趣的是,如果我locals()再次调用(删除上面代码中的第二条注释),那么字典会以某种方式更新,它不包含t在其中并且对象被成功垃圾收集(并且我没有收到"STILL EXISTS"消息)。

我觉得这种行为有点奇怪。

问题是:

  1. 返回的字典locals()即使没有与任何名称相关联也很长寿命是否正常?
  2. 从当前范围中删除名称时,此字典不会自动更新是正常的还是有任何原因?

编辑:我正在使用 cpython 3.6

谢谢!

python garbage-collection cpython

4
推荐指数
1
解决办法
494
查看次数

如何使用仅包含 pyc 文件的 PyPy2 运行 Python 包?

使用 CPython2 我可以编译我的 Python 源代码包python.exe -c "import mypackage"*.py递归删除所有文件后,我可以简单地导入它import mypackage并像往常一样使用它。

使用 CPython3 我可以编译我的 Python 源代码 pyckage python.exe -m compileall -b "full/path/to/mypackage"*.py递归删除所有文件后,我可以简单地使用import mypackage. 并像往常一样使用它。

这甚至可以以完全相同的方式使用 PyPy3 来完成。

令人惊讶的是,当使用 PyPy2 时,这不起作用!

编译和删除源文件后,我得到以下输出:

Python 2.7.13 (9112c8071614, Feb 06 2019, 23:10:08)
[PyPy 7.0.0 with MSC v.1500 32 bit] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>> import mypackage
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: …
Run Code Online (Sandbox Code Playgroud)

python pypy cpython

4
推荐指数
1
解决办法
481
查看次数

Python 中如何实现冻结集相等?

CPython 中如何实现frozenset 相等?特别是,我想知道 fronzenset 中的各个元素如何相互比较以及它们的总时间复杂度。

我查看了set 和frozenset 在实现/sf/answers/3624485581/ 中的差异

第二个链接中的答案涵盖了比较集合中各个元素之前的步骤,但缺少实际的比较算法。

python cpython frozenset

4
推荐指数
2
解决办法
298
查看次数

使用调试 Python 安装在 Windows 上构建 Python-C-Extension

如果我在 Windows 上从源代码构建 CPython,当我想要 pip 安装包含 C 扩展的包时,我会遇到问题。链接库时似乎发生了错误。

例如,安装 cython 时(但在其他 C 扩展包上也会崩溃并出现相同的错误):

链接:致命错误 LNK1104:无法打开文件“python38.lib”

错误:命令“C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.23.28105\bin\HostX86\x86\link.exe”失败,退出状态为 1104

之所以无法打开“python38.lib”,是因为调试模式下的“.lib”文件名为“python38_d.lib”。

一个最小的可重现示例(在命令行上)基于CPython 开发人员指南的快速参考

git clone --branch v3.8.0 https://github.com/python/cpython.git
cd cpython
git checkout v3.8.0
.\PCbuild\build.bat -e -d
.\PCbuild\win32\python_d.exe -m ensurepip
.\PCbuild\win32\python_d.exe -m pip install pip --upgrade -vv
.\PCbuild\win32\python_d.exe -m pip install setuptools --upgrade -vv
.\PCbuild\win32\python_d.exe -m pip install cython -vv
Run Code Online (Sandbox Code Playgroud)

结果distutils.sysconfig.get_config_vars()是:

{'BINDIR': '...\\cpython\\PCbuild\\win32',
 'BINLIBDEST': ...\\cpython\\Lib',
 'EXE': '.exe',
 'EXT_SUFFIX': '_d.cp38-win32.pyd',
 'INCLUDEPY': '...\\cpython\\include;...\\cpython\\PC',
 'LIBDEST': '...\\cpython\\Lib',
 'SO': '_d.cp38-win32.pyd',
 'VERSION': …
Run Code Online (Sandbox Code Playgroud)

python cpython pip setuptools python-c-api

4
推荐指数
1
解决办法
3764
查看次数

Python 中如何实现变量交换?

下面的代码在 Python 中是如何工作的:

a = input()
b = input()
a, b = b, a  # STATEMENT 1
print(a, b)
Run Code Online (Sandbox Code Playgroud)

语句 1 是否在 Python 堆内存空间中创建第三个变量来交换两个数字,或者是否使用某种算法来进行交换?

python algorithm swap cpython

4
推荐指数
1
解决办法
1821
查看次数

编译为字节码,Java 与 Python。所用时间不同的原因是什么?

Java 和 python(仅讨论 CPython)分别被解释为 Java 和 CPython 字节码。然后,这两个字节码都由它们各自的虚拟机(JVM 和 Cpython VM)解释。(这里我忽略了在 10K 运行后开始的 JIT 编译部分。)

我对此有两个问题:

  1. 与 python 相比,为什么 Java 编译为 Java 字节码需要这么多时间?在 java 中,编译是一个明确的步骤,而在 python 中它发生在运行时。
  2. 为什么在第一次运行中编译到 CPython 字节码并缓存在所有连续运行中使用的 .pyc 文件中时,python 的第一次运行和第 n 次运行之间没有明显区别。这个字节码编译真的是python中几乎零成本的任务吗?

虽然它在运行时扮演着重要的角色,但我认为静态和动态类型在编译过程中不应该扮演太大的角色,也不应该是造成这种时间差异的唯一原因。另外,我认为在这两个实现中,在字节码生成期间进行了一些优化。

有什么我在这里想念的吗?(我没有太多的 Java 工作经验。)

更新:

我实际上对 python 第一次运行和后来的运行做了时间分析,发现语句 2 是错误的。运行大型python文件时有非常明显的区别。

方法很简单。创建了一个包含重复行的大文件

a = 5
b = 6
c = a*b
print(str(c))
Run Code Online (Sandbox Code Playgroud)

然后将其导入文件large.py并运行time python large.py

首次运行结果:

python large.py  1.49s user 0.33s system 97% cpu 1.868 total
Run Code Online (Sandbox Code Playgroud)

第二次运行结果:

python large.py  0.20s user 0.08s system …
Run Code Online (Sandbox Code Playgroud)

python java jvm cpython compilation

4
推荐指数
1
解决办法
808
查看次数

CPython 内存堆损坏问题

我有一个Windows fatal exception: code 0xc0000374- 是的,有多重处理(等待但是......)。Google 表示异常代码 0xc0000374 表示堆损坏。是的,多处理是必须具备的。它是我正在使用的框架的一部分,因为每个机器人都有可能拥有自己的核心来运行。TL;DR 我无法改变存在多处理的事实。但是,我的机器人仅在一个线程上运行,因此实际上应该不会出现问题,而且事实上,这个问题相对较新。

我想我已经找到了问题所在,但这并没有多大意义。我正在用 C 扩展 Python,以缩短运行时间,我认为这就是错误所在。我已将其范围缩小到一个名为 的函数ground_shot_is_viable,因为当我在 Python 中注释掉它时,错误永远不会发生。然而,当我尝试打印垃圾邮件时(在这种情况下,我实际上写入了一个文件,因为这更适合数百次打印),我发现该功能成功完成。我认为错误在于该函数超出了它的内存边界,这会损坏部分数据,导致崩溃回溯指向其他地方。(在这种情况下,这是我正在使用的框架中的一个无辜的行 -File "G:\RLBotGUIX\venv\lib\site-packages\rlbot\utils\rendering\rendering_manager.py", line 104 in end_rendering它将变量设置为False

我还对其他功能进行了测试,由于某种原因它们不会导致此问题。有一个很小很小的潜力,因为他们没有像 那样频繁地被调用ground_shot_is_viable

该错误仅在几分钟后发生,概率总计至少几百次,也许一千次。(机器人的运行速度高达 120tps,因此该函数有可能每秒被调用 120 次。)

我只能通过将环境变量 PYTHONFAULTHANLDER 设置为 1 来获得回溯 - 当我没有这样做时,我的程序只是默默地崩溃了。

当我使用 python.exe 启动程序时,我也没有得到故障转储,但使用 pythonw.exe 确实得到了故障转储。

追溯:

Windows fatal exception: code 0xc0000374

Thread 0x00008004 (most recent call first):
  File "G:\RLBotGUIX\Python37\lib\threading.py", line 296 in wait
  File "G:\RLBotGUIX\Python37\lib\multiprocessing\queues.py", line 224 in _feed
  File "G:\RLBotGUIX\Python37\lib\threading.py", line 870 in …
Run Code Online (Sandbox Code Playgroud)

c python cpython python-3.x

4
推荐指数
1
解决办法
2408
查看次数