标签: cpython

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
查看次数

importlib._bootstrap 和 python 解释器初始化

CPython 解释器模块导入系统是用 python 本身编写的,并在importlib._bootstrap. 它的源代码可以在 中看到importlib/_bootstrap.py,但它不是从那里加载的。相反,它是从所谓的冻结模块加载的,该模块的字节码被烘焙到解释器库(python37.dll)中。

解释器通过导入(它是烘焙到解释器中_frozen_importlib的名称importlib._bootstrap)和调用_install在那里定义的函数来初始化自身,并将sys和_imp模块作为参数传递。_install调用_setup,初始化该模块所需的运行时,然后添加 2 个导入器,实现PEP 451。

_bootstrap.py在开发自定义导入器时,我在导入器中遇到了几个错误,因此我需要将一些调试输出添加到_bootstrap.py.

所以我尝试让解释器从磁盘加载_bootstrap.py,而不是从内置的字节码加载。

对 cpython 源代码的分析表明,为了导入内置模块,我不需要大部分规范类。所以可以使用导入内置模块_create_builtin

class UltraSimpleSpec:
    __slots__=("name",)
    def __init__(self, name):
       self.name = name

def _install(sys, _imp):
    io = _imp.create_builtin(UltraSimpleSpec("_io"))
    _bi = _imp.create_builtin(UltraSimpleSpec("builtins"))
    fd = io.open("path/to/_bootstrap.py", "rt") # exits the _install function without any exception, how can …
Run Code Online (Sandbox Code Playgroud)

python cpython initialization python-3.x

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

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
查看次数

常量折叠的具体规则是什么?

我刚刚意识到 CPython 似乎对待常量表达式,它们表示相同的值,在常量折叠方面有所不同。例如:

>>> import dis
>>> dis.dis('2**66')
  1           0 LOAD_CONST               0 (2)
              2 LOAD_CONST               1 (66)
              4 BINARY_POWER
              6 RETURN_VALUE
>>> dis.dis('4**33')
  1           0 LOAD_CONST               2 (73786976294838206464)
              2 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)

对于第二个示例,应用了常量折叠,而对于第一个示例,虽然两者表示相同的值,但并非如此。它似乎与指数的值或结果的大小无关,因为以下表达式也被折叠了:

>>> dis.dis('2.0**66')
  1           0 LOAD_CONST               2 (7.378697629483821e+19)
              2 RETURN_VALUE
>>> dis.dis('4**42')
  1           0 LOAD_CONST               2 (19342813113834066795298816)
              2 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)

为什么前两个表达式的处理方式不同,更一般地说,CPython 遵循的常量折叠的具体规则是什么?


测试:

$ python3.6 --version
Python 3.6.5 :: Anaconda, Inc.
$ python3.7 --version
Python 3.7.1
Run Code Online (Sandbox Code Playgroud)

python cpython python-3.x constantfolding

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

在多处理中,每个进程在 CPython 中都有自己的 GIL 是真的吗?这与创建新的运行时有何不同?

有什么注意事项吗?我有几个与此相关的问题。

创建更多 GIL 的成本是多少?它与创建单独的 python 运行时有什么不同吗?一旦创建了新的 GIL,它是否会根据该过程的需要从头开始创建所有内容(对象、变量、堆栈、堆),或者创建当前堆中所有内容的副本并创建堆栈?(如果垃圾收集处理相同的对象,它们就会发生故障。)正在执行的代码片段是否也被复制到新的 CPU 内核?我也可以将一个 GIL 与一个 CPU 核心联系起来吗?

现在复制东西是一项相当占用 CPU 的任务(如果我错了,请纠正我),决定是否进行多处理的阈值是多少?

PS:我说的是 CPython,但请随意将答案扩展到您认为必要的任何内容。

python cpu cpython multiprocessing gil

6
推荐指数
2
解决办法
383
查看次数

如何在 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
查看次数