백엔드 개발 파이썬 튜토리얼 使用C语言来扩展Python程序和Zope服务器的教程

使用C语言来扩展Python程序和Zope服务器的教程

Jun 10, 2016 pm 03:15 PM
python

有几个原因使您可能想用 C 扩展 Zope。最可能的是您有一个已能帮您做些事的现成的 C 库,但是您对把它转换成 Python 却不感兴趣。此外,由于 Python 是解释性语言,所以任何被大量调用的 Python 代码都将降低您的速度。因此,即使您已经用 Python 写了一些扩展,您仍然要考虑把其中最常被调用的部分改用 C 来写。不论哪种方式,扩展 Zope 都是从扩展 Python 开始。此外,扩展 Python 会给您带来其它的好处,因为您的代码将可以从任何 Python 脚本访问,而不只是从 Zope。这里唯一要提醒的是在写本文的时候,Python 的当前版本是 2.1,但是 Zope 仍然只能和 Python 1.5.2 一起运行。对 C 扩展来说,两个版本并没有什么变化,但如果您有兴趣对您的库进行 Python 包装,又想让它们都能在 Zope 下工作,您就得注意不要使用任何比 1.5.2 更新的东西。
Zope 是什么?

Zope 代表“Z Object Publishing Environment(Z 对象发布环境)”,它是用 Python 实现的应用程序服务器。“太棒了,”您说,“但应用程序服务器的确切含义是什么呢?”应用程序服务器就是一个长期运行的进程,它为“活动的内容”提供服务。Web 服务器在运行期间调用应用程序服务器来构建页面。
扩展 Python:有趣又有益

想扩展 Zope,您首先要扩展 Python。虽然扩展 Python 不像“脑外科手术”那样复杂,但也不像“在公园中散步”那样悠闲。有两个基本组件用于 Python 扩展。第一个显然是 C 代码。我将马上探讨它。 另一个部分是 安装文件。安装文件通过提供模块名称、模块的 C 代码的位置和您可能需要的所有编译器标志来描述模块。该文件被预处理,以创建 makefile(在 UNIX 上)或 MSVC++ 工程文件(MSVC++ project file,在 Windows 上)。先说一下 ― Windows 上的 Python 事实上是用 Microsoft 编译器编译的。Python.org 的人也推荐用 MSVC++ 编译扩展。显然,您应该能够成功说服 GNU 的编译者们,但我本人还没试过。

无论如何,还是让我们来定义一个叫做‘foo'的模块吧。‘foo'模块会有一个叫做‘bar'的函数。当我们要使用时,我们可以用 import foo; 来把这个函数导入到 Python 脚本中,就跟导入任何模块一样。安装文件非常简单:
清单 1. 一个典型的安装文件

# You can include comment lines. The *shared* directive indicates
# that the following module(s) are to be compiled and linked for
# dynamic loading as opposed to static: .so on Unix, .dll on Windows.
*shared*
# Then you can use the variables later using the $(variable) syntax
# that 'make' uses. This next line defines our module and tells
# Python where its source code is.
foo foomain.c

로그인 후 복사

编写代码

那么我们实际上该怎样写 Python 知道如何使用的代码呢,您问? foomain.c (当然,您可以随意命名它)文件包含三项内容:一个方法表,一个初始化函数和其余的代码。方法表简单地将函数名与函数联系起来,并告知 Python 各个函数所使用的参数传递机制(您可以选择使用一般的位置参数列表或位置参数和关键词参数的混合列表)。Python 在模块装入时调用初始化函数。初始化函数将完成模块所要求的所有初始化操作,但更重要的是,它还把一个指向方法表的指针传回给 Python。

那我们就来看看我们的小型 foo 模块的 C 代码。
清单 2. 一个典型的 Python 扩展模块

#include <Python.h>
/* Define the method table. */
static PyObject *foo_bar(PyObject *self, PyObject *args);
static PyMethodDef FooMethods[] = {
  {"bar", foo_bar, METH_VARARGS},
  {NULL, NULL}
};
/* Here's the initialization function. We don't need to do anything
  for our own needs, but Python needs that method table. */
void initfoo()
{
  (void) Py_InitModule("foo", FooMethods);
}
/* Finally, let's do something ... involved ... as an example function. */
static PyObject *foo_bar(PyObject *self, PyObject *args)
{
  char *string;
  int  len;
  if (!PyArg_ParseTuple(args, "s", &string))
    return NULL;
  len = strlen(string);
  return Py_BuildValue("i", len);
}

로그인 후 복사

深入研究

我们来看会儿这些代码。首先,请注意您必须包含 Python.h 。除非您已在包含路径(include path)中设置了该文件的路径,否则您可能需要在安装文件中包含 -I 标志以指向该文件。

初始化函数必须命名为 init <模块名>,在我们的例子中是 initfoo 。初始化函数的名称,毫无疑问,是 Python 在装入模块时所知道的关于模块的全部信息,这也是初始化函数的名称如此死板的原因。顺便说一下,初始化函数必须是文件中唯一未被声明为 static 的全局标识符。这对静态链接比对动态链接更重要,因为非 static 标识符将是全局可见的。对动态链接来说,这不是一个很大的问题,但如果您打算在编译期间链接所有东西,又没有把所有可以声明为 static 的东西声明为 static ,那么您很可能就会碰到名称冲突的问题。

现在我们来观察实际的代码,看看参数是怎样被处理的,返回值又是怎样被传递的。当然,一切都是 PyObject ― Python 堆上的对象。您从参数中得到的是一个对“this”对象的引用(this 用于对象方法,对类似 bar() 这样的无参数的老式函数来说是 NULL)和一个存储在 args 中的参数元组。您用 PyArg_ParseTuple 找回您的参数,然后用 Py_BuildValue 把结果传回去。这些函数(还有更多)都归档在 Python 文档的“Python/C API”部分中。不幸的是,没有按名称排列的简单的函数清单,文档是按主题排列的。

另请注意,函数在出错的情况下返回 NULL。返回 NULL 表示出错了;如果想让 Python 做得更好,您应该抛出异常。我会指点您去查阅关于如何做这件事的文档。

编译扩展

现在剩下的全部问题是编译模块。您可以通过两种方式进行。第一种是按照文档中的指导,运行 make -f Makefile.pre.in boot ,这样将会使用您的 Setup 来编译一个 Makefile。然后您就用该 Makefile 编译您的工程。这种方式只适用于 UNIX。对 Windows 来说,存在一个叫“compile.py”的脚本(请参阅本文后面的 参考资料)。原始脚本很难找到;我从一个邮件列表中找到了一个来自 Robin Dunn(wxPython 的幕后工作者)的被大量改动了的副本。这个脚本能在 UNIX 和 Windows 上工作;在 Windows 上,它将从您的 Setup 开始编译 MSVC++ 工程文件。

要进行编译,您必须使包含的文件和库都可用。Python 的标准 Zope 安装没有包含这些文件,因此您需要从 www.python.org(请参阅 参考资料)安装 Python 的常规安装。在 Windows 上,您还必须从源代码安装的 PC 目录中获取 config.h 文件;它是 UNIX 安装为您编译的 config.h 的手工版。因此,在 UNIX 上,您应该已经拥有它了。

一旦这些都完成后,您就会得到一个以“.pyd”为扩展名的文件。把这个文件放到 Python 安装目录下的“lib”目录(在 Zope 下,Python 位于“bin”目录,因此您的扩展得结束于“bin/lib”目录,奇怪吧。)然后您就可以调用它了,就像调用任何源生的 Python 模块一样。

 >>> import foo;
 >>> foo.bar ("This is a test");
 14

로그인 후 복사

做到这里时,我的第一个问题是问自己该如何用 C 定义从 Python 中可见的 类。事实上,我可能问了一个错误的问题。在我已研究的示例中,特定于 Python 的一切都只 用 Python 来完成,也都只调用从您的扩展中导出的 C 函数。

把它带到 Zope 中去

一旦完成了您的 Python 扩展,下一步就是使 Zope 能和它一起工作。您有几种方式可以选择,但在一定程度上,您希望您的扩展以什么方式与 Zope 一起工作将首先影响到您编译扩展的方式。从 Zope 内使用 Python(以及用 C 所做的扩展)代码的基本方式是:

  • 如果函数很简单,您可以把它当作一个变量。这些被叫做“外部方法”。
  • 更复杂的类,可以从 Zope 脚本中调用(这是 Zope 2.3 的一个新功能)。
  • 您可以定义一个 Zope Product,然后可以用 ZClass(一组已做好的、Web 可访问的对象)扩展它,在脚本中使用它,根据它的自有权限发布它(它的实例被当作页来对待)。

当然,您自己的应用程序可以使用这些方式的组合。

创建外部方法

从 Zope 调用 Python 的最简单的方式是把您的 Python 代码做成 外部方法。外部方法是被放到 Zope 安装目录下的“Extensions”目录中的 Python 函数。一旦那里有了这样一个 Python 文件,您就可以转到任意文件夹,选择“添加外部方法”,并添加调用要使用的函数的变量。然后您就可以往该文件夹中显示调用结果的任意页添加 DTML 字段。我们来看一个使用了上面所定义的 Python 扩展 ― foo.bar ― 的简单示例。

首先,来看扩展本身:我们把它放到一个例如叫 foo.pyd 的文件中。记住,这个文件位于 Zope 下的 Extensions 目录。为了能够顺利进行,当然,我们在上面创建的 foo.pyd 必须在位于 bin/lib 的 Python 库中。一个出于这个目的的、简单的包看起来可能像这样:
清单 3. 一个简单的外部方法(文件:Extensions/foo.py)

import foo
def bar(self,arg):
  """A simple external method."""
  return 'Arg length: %d' % foo.bar(arg)

로그인 후 복사

很简单,不是吗?它定义了一个可以用 Zope 管理界面附加到任意文件夹的外部方法“bar”。要从该文件夹中的任何页中调用我们的扩展,我们只需简单地插入一个 DTML 变量引用,如下所示:

 <dtml-var bar('This is a test')>

로그인 후 복사

当用户查看我们的页时,DTML 字段将被文本“Arg length: 14”代替。我们就这样用 C 扩展了 Zope。

Zope 脚本:Cliff Notes 版

Zope 脚本是 Python 2.3 的一个想用来代替外部方法的新功能。外部方法能做到的,它都能做到,而且它能和安全性及管理系统更好地集成,在集成方面提供更多的灵活性,它还有很多对 Zope API 中公开的全部 Zope 功能的访问。

一个脚本基本上就是一个短小的 Python 程序。它可以定义类或函数,但不是必须的。它被作为对象安装在 Zope 文件夹中,然后就可以把它当作 DTML 变量或调用(就像一个外部方法)来调用或者“从 Web 中”(在 Zope 中的意思就是它将被当作页来调用)调用它。当然,这意味着脚本可以像 CGI 程序那样生成对表单提交的响应,但却没有 CGI 的开销。确实是一个很棒的功能。此外,脚本有权访问被调用者或调用者对象(通过“context”对象)、对象所在的文件夹(通过“container”对象)和其他一些零碎信息。要获得更多关于脚本的知识,请参阅 Zope 手册(请参阅 参考资料)中的“高级 Zope 脚本编制(Advanced Zope Scripting)”那一章。

您可能会错误地认为可以直接从脚本简单地导入 foo 并使用 foo.bar(我知道我确实犯过这种错误)。但事实并非如此。由于安全性限制,只有 Product 可以被导入,而不是什么模块都可以。一般而言,Zope 的设计者们认为任何脚本编制都需要访问文件系统,既然脚本对象是由 Web 使用 Zope 管理界面来管理,所以它们不是完全可信的。所以我打算就此打住,不给您展示示例脚本了,而是来讨论 Product 和基础类。

专注于 Product

Product 是扩展 Zope 的强大工具方法。从安装目录的级别来看,Product 就是位于 Zope 目录下的“lib/python/Products”目录中的一个目录。在您自己的 Zope 安装目录中,您可以看到很多 product 示例,但本质上,最小的 Product 只由位于该目录的两个文件组成:一个可任意命名的代码文件和一个 Zope 在启动时调用来初始化 Product 的称为 __init__.py 的文件。(请注意:Zope 只在启动时读取 Product 文件,这意味着为了测试,您必须能够停止和重新启动 Zope 进程)。本文只是尽量多提供一些您能通过使用 Zope Product 做到的事的提示。

要知道的是 Product 封装了一个或多个可从 ZClass、脚本或直接从 Web 上的 URL 使用的类。(当然,在最后一种情况下,Product 的实例被当作文件夹看待;那么 URL 的最后部分指定了将被调用的方法,该方法返回任意的 HTML。)您不必一定要把 Product 当作“可添加的”对象来对待,虽然这是它的主要目的。要看一个优秀的、现实存在的示例,可以去看 ZCatalog 实现,它是标准 Zope 分发的一部分。那里您可以在 __init__.py 中看到一个非常简单的安装脚本,可以在 ZCatalog.py 中看到 ZCatalog 类,该类提供了很多发布方法。请注意 Zope 采用一种奇怪的约定来确定哪些方法可以通过 Web 访问 ― 如果一个方法包含有一个 doc 字符串,那么该方法可通过 Web 访问;否则,就被认为是私有的。

无论如何,我们还是来看一个使用了 C 模块(我们在上面定义了它)的非常简单的 Product。首先来看非常简单的 __init__.py;请注意它只做了一件事,即告诉 Zope 我们正在安装的类的名称。更复杂的初始化脚本能做 更多的事,包括声明由服务器维护的全局变量以及设置访问权限等等。欲了解更多详细信息,请参阅在线文档中的 Zope 开发者指南,也请研究您的 Zope 安装目录中现成的 Product。您或许已经猜到了,我们的示例 Product 被称为“Foo”。这样您就将在 lib/python/Products 目录下创建一个 Foo 子目录。
清单 4. 基本的 Product 初始化脚本

import Foo
def initialize(context):
  context.registerClass(
    Foo.Foo, 
    permission='Add Foo',
    constructors=Foo.manage_addFoo
    )

로그인 후 복사

现在请注意这个初始化脚本不仅导入了那个类,使它可被 Zope 的其它部件访问,而且还将该类注册成具有“可添加性”。 context.registerClass 调用通过首先命名我们所导入的类,然后指定可被用于添加实例的方法名称(这个方法必须显示一个管理页面,且该方法将自动与 Zope 管理界面集成)的名称来完成这项工作。酷。

我们来小结一下这个短小、简单的 Product。它会把我们的 foo.bar 函数公开给脚本和 ZClass,并且还有一个作为“可添加的”对象的小接口,这就是全部内容。
清单 5. 一个简单的 Zope Product

import foo
class Foo(SimpleItem.Item):
 "A Foo Product"
 meta_type = 'foo'
 def bar(self, string):
   return foo.bar(string)
 def __init__(self, id):
   "Initialize an instance"
   self.id = id
 def index_html(self):
   "Basic view of object"
   return '
My id is %s and its length is %d.
' % (self.id, foo.bar(self.id))
 def manage_addFoo(self, RESPONSE):
   "Management handler to add an instance to a folder."
   self._setObject('Foo_id', Foo('Foo_id'))
   RESPONSE.redirect('index_html')

로그인 후 복사

这只是一个最简单的 Product。不能绝对地说它是可能的 Product 中最小的一个,但已经很接近了。不过,它确实说明了 Product 的一些关键特征。首先,请注意“index_html”方法:它被调用来显示一个对象实例,这是通过构建 HTML 完成的。它实际上是一个页面。 manage_addFoo 方法是 Zope 对象管理的接口;我们在上面的 __init__.py 中引用了它。“__init__”方法初始化对象;实际上它 必须做的全部工作就是记录实例的唯一标识符。

这个微型的 Product 不和 Zope 安全性进行交互操作。它不做很多管理工作。它没有交互功能。所以您可以给它添加很多东西(甚至连很有用的功能它也没有)。我希望这对您是一个很好的开始。

以后该做什么

对 Zope Product 的简单介绍已经告诉您如何把 C 语言函数从 C 代码变为 Zope 中可用的。要学会怎么写 Product,您还得阅读更多文档(其中有很多仍在完善之中),坦率地说,还要研究已有的 Product,看看它们是怎么做的。Zope 模型有很强大的功能和很大的灵活性,它们都很值得探究。

我目前正在做集成 C 和 Zope 的大工程:集成我的工作流工具包(workflow toolkit)。在本文发表之前,我希望能看到它的雏形。它已被列在下面的参考资料中,去看看吧;到您阅读本文时,应该已经能够从中找到一个扩展示例。祝我好运。

본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

Video Face Swap

Video Face Swap

완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

뜨거운 도구

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전

SublimeText3 중국어 버전

중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)

PHP와 Python : 다른 패러다임이 설명되었습니다 PHP와 Python : 다른 패러다임이 설명되었습니다 Apr 18, 2025 am 12:26 AM

PHP는 주로 절차 적 프로그래밍이지만 객체 지향 프로그래밍 (OOP)도 지원합니다. Python은 OOP, 기능 및 절차 프로그래밍을 포함한 다양한 패러다임을 지원합니다. PHP는 웹 개발에 적합하며 Python은 데이터 분석 및 기계 학습과 같은 다양한 응용 프로그램에 적합합니다.

PHP와 Python 중에서 선택 : 가이드 PHP와 Python 중에서 선택 : 가이드 Apr 18, 2025 am 12:24 AM

PHP는 웹 개발 및 빠른 프로토 타이핑에 적합하며 Python은 데이터 과학 및 기계 학습에 적합합니다. 1.PHP는 간단한 구문과 함께 동적 웹 개발에 사용되며 빠른 개발에 적합합니다. 2. Python은 간결한 구문을 가지고 있으며 여러 분야에 적합하며 강력한 라이브러리 생태계가 있습니다.

Python vs. JavaScript : 학습 곡선 및 사용 편의성 Python vs. JavaScript : 학습 곡선 및 사용 편의성 Apr 16, 2025 am 12:12 AM

Python은 부드러운 학습 곡선과 간결한 구문으로 초보자에게 더 적합합니다. JavaScript는 가파른 학습 곡선과 유연한 구문으로 프론트 엔드 개발에 적합합니다. 1. Python Syntax는 직관적이며 데이터 과학 및 백엔드 개발에 적합합니다. 2. JavaScript는 유연하며 프론트 엔드 및 서버 측 프로그래밍에서 널리 사용됩니다.

PHP와 Python : 그들의 역사에 깊은 다이빙 PHP와 Python : 그들의 역사에 깊은 다이빙 Apr 18, 2025 am 12:25 AM

PHP는 1994 년에 시작되었으며 Rasmuslerdorf에 의해 개발되었습니다. 원래 웹 사이트 방문자를 추적하는 데 사용되었으며 점차 서버 측 스크립팅 언어로 진화했으며 웹 개발에 널리 사용되었습니다. Python은 1980 년대 후반 Guidovan Rossum에 의해 개발되었으며 1991 년에 처음 출시되었습니다. 코드 가독성과 단순성을 강조하며 과학 컴퓨팅, 데이터 분석 및 기타 분야에 적합합니다.

Windows 8에서 코드를 실행할 수 있습니다 Windows 8에서 코드를 실행할 수 있습니다 Apr 15, 2025 pm 07:24 PM

VS 코드는 Windows 8에서 실행될 수 있지만 경험은 크지 않을 수 있습니다. 먼저 시스템이 최신 패치로 업데이트되었는지 확인한 다음 시스템 아키텍처와 일치하는 VS 코드 설치 패키지를 다운로드하여 프롬프트대로 설치하십시오. 설치 후 일부 확장은 Windows 8과 호환되지 않을 수 있으며 대체 확장을 찾거나 가상 시스템에서 새로운 Windows 시스템을 사용해야합니다. 필요한 연장을 설치하여 제대로 작동하는지 확인하십시오. Windows 8에서는 VS 코드가 가능하지만 더 나은 개발 경험과 보안을 위해 새로운 Windows 시스템으로 업그레이드하는 것이 좋습니다.

Python에서 비주얼 스튜디오 코드를 사용할 수 있습니다 Python에서 비주얼 스튜디오 코드를 사용할 수 있습니다 Apr 15, 2025 pm 08:18 PM

VS 코드는 파이썬을 작성하는 데 사용될 수 있으며 파이썬 애플리케이션을 개발하기에 이상적인 도구가되는 많은 기능을 제공합니다. 사용자는 다음을 수행 할 수 있습니다. Python 확장 기능을 설치하여 코드 완료, 구문 강조 및 디버깅과 같은 기능을 얻습니다. 디버거를 사용하여 코드를 단계별로 추적하고 오류를 찾아 수정하십시오. 버전 제어를 위해 git을 통합합니다. 코드 서식 도구를 사용하여 코드 일관성을 유지하십시오. 라인 도구를 사용하여 잠재적 인 문제를 미리 발견하십시오.

터미널 VSCODE에서 프로그램을 실행하는 방법 터미널 VSCODE에서 프로그램을 실행하는 방법 Apr 15, 2025 pm 06:42 PM

vs 코드에서는 다음 단계를 통해 터미널에서 프로그램을 실행할 수 있습니다. 코드를 준비하고 통합 터미널을 열어 코드 디렉토리가 터미널 작업 디렉토리와 일치하는지 확인하십시오. 프로그래밍 언어 (예 : Python의 Python Your_file_name.py)에 따라 실행 명령을 선택하여 성공적으로 실행되는지 여부를 확인하고 오류를 해결하십시오. 디버거를 사용하여 디버깅 효율을 향상시킵니다.

VScode 확장자가 악의적입니까? VScode 확장자가 악의적입니까? Apr 15, 2025 pm 07:57 PM

VS 코드 확장은 악의적 인 코드 숨기기, 취약성 악용 및 합법적 인 확장으로 자위하는 등 악성 위험을 초래합니다. 악의적 인 확장을 식별하는 방법에는 게시자 확인, 주석 읽기, 코드 확인 및주의해서 설치가 포함됩니다. 보안 조치에는 보안 인식, 좋은 습관, 정기적 인 업데이트 및 바이러스 백신 소프트웨어도 포함됩니다.

See all articles