标签: cpython

为什么Python中的每个新对象的ref都增加2?

在定义新对象后,交互式环境中的refs数增加2对我来说有点奇怪.我只创建了一个对象,不是吗?

>>> v
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'v' is not defined
[41830 refs]
>>> v = "v"
[41832 refs]
Run Code Online (Sandbox Code Playgroud)

python cpython python-internals

6
推荐指数
1
解决办法
234
查看次数

python扩展模块初始化-多个文件

创建了一个由许多源文件和头文件组成的 C 库后,我现在需要用 Python 层包装它,以便我可以“导入”它。

我已经实现了从 Python 调用的静态方法,并且我需要指定模块应向解释器公开哪些方法。

然而,在指定可以调用的内容时,文档似乎只处理具有单个源文件的非常简单的情况,因为唯一的非静态方法必须是 init,它注册方法。

据我所知,如果其他源文件中的方法在 C 中声明为静态,则不可能调用它们(如果我错了,请纠正我),因此,每个 python 模块只能有一个 C 文件,因为整个过程中只允许使用一种非静态方法。

事实真的如此吗?如果你想从 Python 访问你的代码,你的代码结构必须很糟糕/根本不需要吗?

编辑:

因此,我最终实现此目的的方法是使用Cython。重写 c/python 接口不仅需要大约一个小时(由于所有引用计数规则等原因,之前需要大约一天的时间),而且它还为您处理所有构建问题,并且有清晰的文档准确描述了哪些问题方法可以从 python 获得。

特别是,我使用的文档章节包括构建说明、如何调用 C 库、语言基础知识以及如何转换类型(尤其是指针)。

对于任何想要将现有的复杂结构 C 代码(即不仅仅是单个文件的代码)包装为 python 库的人,我强烈推荐 Cython。

python static cpython

6
推荐指数
1
解决办法
1486
查看次数

将 python 代码转换为共享对象

我想从 python 模块准备一个共享对象(.so)。我遇到了 Cython,它 a) 首先将 *.pyx 模块转换为 *.c 代码,b) 然后这个 *.c 代码将转换为共享对象 (.so)。Cython 的所有示例都说明了如何将这个 .so 导入到 python 中。

\n\n

但是,我有兴趣从 C 代码中读取这个共享对象。当我编写示例 C 代码来读取 .so 时,它会抛出一个错误,指出 .pyx 中实际存在的方法并不存在于 .so 对象中。

\n\n

我想知道 \na) 是否可以从不同的语言(例如 C)读取 Cython 的共享对象 \nb) 而且,如果上述语句为 True,我必须在代码中进行哪些更改,以便我将能够从 C 读取共享对象。

\n\n

谢谢,

\n\n

Python代码(保存为square_number.pyx)

\n\n
def square_me(int x):\n    return x * x\n
Run Code Online (Sandbox Code Playgroud)\n\n

Cython 对应的 setup.py 文件

\n\n
from distutils.core import setup\nfrom Cython.Build import cythonize\n\nsetup(\n    ext_modules=cythonize("square_number.pyx"),\n     )\n
Run Code Online (Sandbox Code Playgroud)\n\n

将上述 .pyx 转换为 .So 的命令行语句(通过 cython)

\n\n
python setup.py …
Run Code Online (Sandbox Code Playgroud)

c python cpython

6
推荐指数
1
解决办法
7078
查看次数

如何禁止在实例上调用类方法?

我一直在寻找 的源代码peewee,特别Model是该update函数:https://github.com/coleifer/peewee/blob/a33e8ccbd5b1e49f0a781d38d40eb5e8f344eee5/peewee.py#L4718

我不喜欢这样的事实:如果语句未与子句正确耦合,则任何更新操作都会影响模型中的每一行,可以从行实例调用此方法where。因此,我想找到某种方法来禁止从模型实例调用此类方法。

一些谷歌搜索让我相信这可能相当困难。delattr从__init__似乎没有工作。从 update 函数运行isclass(self)总是返回 True,因为当我们在类方法内部时,我们实际上是类而不是实例。

有什么建议么?

python cpython class-method peewee

6
推荐指数
1
解决办法
844
查看次数

嵌入 CPython:如何构造 Python 可调用对象来包装 C 回调指针?

假设我将 CPython 解释器嵌入到一个用 C 编写的较大程序中。该程序的 C 组件偶尔需要调用用 Python 编写的函数,并将回调函数作为参数提供给它们。

使用 CPython扩展和嵌入API,如何构造一个包装 C 函数指针的 Python“可调用”对象,以便我可以将该对象传递给 Python 代码并让 Python 代码成功回调到 C 代码中?

注意:这是最初由用户dhanasubbu发布的问题的修订版本,我回答了该问题,但随后被删除。我认为这实际上是一个好问题,所以我将我所写的内容转换为我自己对问题的陈述的自我回答。欢迎其他答案。

c python cpython python-c-api

6
推荐指数
1
解决办法
664
查看次数

python 管理大变量分配/释放的策略是什么?

作为这个问题的后续,似乎 (C)Python 中的小变量和大变量有不同的分配/释放策略。
更准确地说,对象大小似乎存在一个边界,超过该边界,分配的对象使用的内存可以返回给操作系统。低于此大小,内存不会返回给操作系统。

引用 Numpy 内存释放策略中的答案:

例外情况是,对于大型单个分配(例如,如果您创建多兆字节数组),则使用不同的机制。如此大的内存分配可以释放回操作系统。因此,可能是程序中的非 numpy 部分产生了您看到的问题。

事实上,这两种分配策略很容易显示。例如:

  • 第一个策略:不将内存返还给操作系统
import numpy as np
import psutil
import gc

# Allocate  array
x = np.random.uniform(0,1, size=(10**4))

# gc
del x
gc.collect()
# We go from 41295.872 KB to 41295.872 KB
# using psutil.Process().memory_info().rss / 10**3; same behavior for VMS
Run Code Online (Sandbox Code Playgroud)

=> 没有内存返回给操作系统

  • 第二种策略:释放的内存返回给操作系统

当做相同的实验,但使用更大的数组时:

x = np.random.uniform(0,1, size=(10**5))

del x
gc.collect()
# We go from 41582.592 KB to 41017.344 KB
Run Code Online (Sandbox Code Playgroud)

=> 内存被释放给操作系统

似乎8*10**4使用第二种策略分配大约大于字节的对象。

所以:

  • 这种行为有记录吗?(分配策略发生变化的确切边界是什么?)
  • 这些策略的内部原理是什么(不仅仅是假设使用mmap …

python numpy cpython

6
推荐指数
1
解决办法
641
查看次数

如何在 Cython 中使用 `restrict` 关键字?

我在 CPython 3.6 中使用 Cython,我想将一些指针标记为“无别名”,以提高性能并在语义上明确。

在 C 中,这是通过restrict( __restrict, __restrict__) 关键字完成的。但是如何使用Cython 代码中的变量restrict呢?cdef.pyx

谢谢!

python cpython cython

6
推荐指数
1
解决办法
178
查看次数

即使我使用的是 Rosetta,MacOS M1 系统也被 Python 包检测为 ARM

我在配备 M1(Apple ARM 架构)的 Macbook 上,尝试使用layoutparser库运行以下 Python 代码,该库间接使用pycocotools:

import layoutparser as lp
lp.Detectron2LayoutModel()
Run Code Online (Sandbox Code Playgroud)

我收到了错误:

[...]
ImportError: 
dlopen([...]/.venv/lib/python3.9/site-packages/pycocotools/_mask.cpython-39-darwin.so, 0x0002): 
tried: 
'[...]/.venv/lib/python3.9/site-packages/pycocotools/_mask.cpython-39-darwin.so' 
(mach-o file, but is an incompatible architecture (have 'x86_64', need 'arm64e')), 
'/usr/local/lib/_mask.cpython-39-darwin.so' (no such file), 
'/usr/lib/_mask.cpython-39-darwin.so' (no such file)
Run Code Online (Sandbox Code Playgroud)

对我来说最重要的信息似乎是[...] is an incompatible architecture (have 'x86_64', need 'arm64e') [...]。确实,我使用的是Apple ARM架构,有时有些软件不支持。这通常可以通过使用模拟 Intel-x64 架构的 Rosetta 来解决。所以我用 Rosetta ( arch -x86_64 zsh) 启动一个终端,创建一个新的虚拟环境,重新安装依赖项,然后尝试再次运行代码......

...我收到了与没有 Rosetta 时遇到的相同错误:

[...] is an incompatible architecture (have 'x86_64', need 'arm64e') [...] …

python cpython rosetta apple-m1

6
推荐指数
1
解决办法
8272
查看次数

Python这里不重用内存吗?Tracemalloc 的输出是什么意思?

我创建了一个包含一百万个对象的列表int,然后用其负值替换每个对象。tracemalloc报告 28 MB 额外内存(每个新int对象 28 字节)。为什么?intPython 不会为新对象重用垃圾收集对象的内存吗?或者我误解了tracemalloc结果?为什么会提到这些数字,它们的真正含义是什么?

\n
import tracemalloc\n\nxs = list(range(10**6))\ntracemalloc.start()\nfor i, x in enumerate(xs):\n    xs[i] = -x\nprint(tracemalloc.get_traced_memory())\n
Run Code Online (Sandbox Code Playgroud)\n

输出(在线尝试!):

\n
(27999860, 27999972)\n
Run Code Online (Sandbox Code Playgroud)\n

如果我替换xs[i] = -x为x = -x(因此新对象而不是原始对象被垃圾收集),则输出仅仅是(56, 196)(尝试一下)。我保留/丢失这两个物品中的哪一个有什么区别?

\n

如果我循环两次,它仍然只报告(27992860, 27999972)(尝试一下)。为什么不是 56MB?第二次运行与第一次运行有何不同?

\n

python memory cpython python-internals tracemalloc

6
推荐指数
1
解决办法
786
查看次数

为什么这个特定代码在 Python 3.11 中运行得更快?

我在一个名为 的 Python 文件中有以下代码benchmark.py:

source = """
for i in range(1000):
    a = len(str(i)) 
"""

import timeit

print(timeit.timeit(stmt=source, number=100000))
Run Code Online (Sandbox Code Playgroud)

当我尝试运行多个 python 版本时,我发现性能存在巨大差异。

C:\Users\Username\Desktop>py -3.10 benchmark.py
16.79652149998583

C:\Users\Username\Desktop>py -3.11 benchmark.py
10.92280820000451
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,这段代码在 python 3.11 中运行得比以前的 Python 版本更快。我尝试反汇编字节码以了解此行为的原因,但我只能看到操作码名称的差异(CALL_FUNCTION被替换为PRECALL和CALL操作码)。

我很不确定这是否是性能变化的原因。所以我正在寻找一个参考 cpython 源代码来证明合理的答案。

python 3.11字节码:

  0           0 RESUME                   0

  2           2 PUSH_NULL
              4 LOAD_NAME                0 (range)
              6 LOAD_CONST               0 (1000)
              8 PRECALL                  1
             12 CALL                     1
             22 GET_ITER
        >>   24 FOR_ITER                22 …
Run Code Online (Sandbox Code Playgroud)

python performance cpython python-3.x python-3.11

6
推荐指数
1
解决办法
1096
查看次数