葵花宝典教程,一个自学编程平台

葵花宝典教程,一个自学编程平台

Python - 使用 C 进行扩展编程

您使用任何编译语言(如 C、C++ 或 Java)编写的任何代码都可以集成或导入到另一个 Python 脚本中。此代码被视为“扩展”。


Python 扩展模块只不过是一个普通的 C 库。在 Unix 机器上,这些库通常以.so结尾(用于共享对象)。在 Windows 机器上,您通常会看到.dll(用于动态链接库)。


编写扩展的先决条件

要开始编写扩展,您将需要 Python 头文件。


在 Unix 机器上,这通常需要安装开发人员特定的包,例如python2.5-dev。


Windows 用户在使用二进制 Python 安装程序时将这些标头作为包的一部分。


此外,假设您对 C 或 C++ 有很好的了解,可以使用 C 编程编写任何 Python 扩展。


先看一个 Python 扩展

对于您第一次查看 Python 扩展模块,您需要将您的代码分为四部分 -


头文件Python.h。


您要作为模块接口公开的 C 函数。


将 Python 开发人员看到的函数名称映射到扩展模块内的 C 函数的表。


一个初始化函数。


头文件Python.h

您需要在 C 源文件中包含Python.h头文件,这使您可以访问用于将模块挂接到解释器的内部 Python API。


确保在您可能需要的任何其他标头之前包含 Python.h。您需要遵循包含要从 Python 调用的函数。


C 函数

函数的 C 实现的签名始终采用以下三种形式之一 -


static PyObject *MyFunction( PyObject *self, PyObject *args );


static PyObject *MyFunctionWithKeywords(PyObject *self,

                                 PyObject *args,

                                 PyObject *kw);


static PyObject *MyFunctionWithNoArgs( PyObject *self );

前面的每个声明都返回一个 Python 对象。Python 中没有像 C 中那样的void函数。如果您不希望函数返回值,请返回 Python 的None值的 C 等效项。Python 头文件定义了一个宏 Py_RETURN_NONE,它为我们做这件事。


您的 C 函数的名称可以是您喜欢的任何名称,因为它们在扩展模块之外永远不会出现。它们被定义为静态函数。


您的 C 函数通常通过将 Python 模块和函数名称组合在一起来命名,如下所示 -


static PyObject *module_func(PyObject *self, PyObject *args) {

   /* Do your stuff here. */

   Py_RETURN_NONE;

}

这是一个名为func的 Python 函数,位于模块module中。您将把指向 C 函数的指针放入源代码中通常出现的模块的方法表中。


方法对照表

这个方法表是一个简单的 PyMethodDef 结构数组。该结构看起来像这样 -


struct PyMethodDef {

   char *ml_name;

   PyCFunction ml_meth;

   int ml_flags;

   char *ml_doc;

};

这是该结构成员的描述 -


ml_name - 这是 Python 解释器在 Python 程序中使用时呈现的函数名称。


ml_meth - 这必须是具有前一节中描述的任何一个签名的函数的地址。


ml_flags - 这告诉解释器 ml_meth 正在使用三个签名中的哪一个。


该标志的值通常为 METH_VARARGS。


如果你想允许关键字参数进入你的函数,这个标志可以与 METH_KEYWORDS 进行按位或运算。


这也可以具有 METH_NOARGS 值,表示您不想接受任何参数。


ml_doc - 这是函数的文档字符串,如果您不想写一个,它可能是 NULL。


该表需要使用一个标记来终止,该标记由相应成员的 NULL 和 0 值组成。


例子

对于上述定义的函数,我们有以下方法映射表 -


static PyMethodDef module_methods[] = {

   { "func", (PyCFunction)module_func, METH_NOARGS, NULL },

   { NULL, NULL, 0, NULL }

};

初始化函数

扩展模块的最后一部分是初始化函数。该函数在模块加载时由 Python 解释器调用。需要将函数命名为init Module,其中Module是模块的名称。


初始化函数需要从您将要构建的库中导出。Python 头文件定义 PyMODINIT_FUNC 以包含适当的咒语,以便在我们正在编译的特定环境中发生这种情况。您所要做的就是在定义函数时使用它。


您的 C 初始化函数通常具有以下总体结构 -


PyMODINIT_FUNC initModule() {

   Py_InitModule3(func, module_methods, "docstring...");

}

这是Py_InitModule3函数的描述 -


func - 这是要导出的函数。


module _methods - 这是上面定义的映射表名称。


docstring - 这是您想在扩展中给出的评论。


把这一切放在一起看起来像下面这样 -


#include <Python.h>


static PyObject *module_func(PyObject *self, PyObject *args) {

   /* Do your stuff here. */

   Py_RETURN_NONE;

}


static PyMethodDef module_methods[] = {

   { "func", (PyCFunction)module_func, METH_NOARGS, NULL },

   { NULL, NULL, 0, NULL }

};


PyMODINIT_FUNC initModule() {

   Py_InitModule3(func, module_methods, "docstring...");

}

例子

一个利用上述所有概念的简单示例 -


#include <Python.h>


static PyObject* helloworld(PyObject* self) {

   return Py_BuildValue("s", "Hello, Python extensions!!");

}


static char helloworld_docs[] =

   "helloworld( ): Any message you want to put here!!\n";


static PyMethodDef helloworld_funcs[] = {

   {"helloworld", (PyCFunction)helloworld, 

      METH_NOARGS, helloworld_docs},

      {NULL}

};


void inithelloworld(void) {

   Py_InitModule3("helloworld", helloworld_funcs,

                  "Extension module example!");

}

这里Py_BuildValue函数用于构建 Python 值。将上述代码保存在 hello.c 文件中。我们将看到如何编译和安装这个模块以从 Python 脚本中调用。


构建和安装扩展

distutils包使以标准方式分发 Python 模块(纯 Python 模块和扩展模块)变得非常容易。模块以源代码形式分发,并通过通常称为setup.py的安装脚本构建和安装,如下所示。


对于上述模块,您需要准备以下 setup.py 脚本 -


from distutils.core import setup, Extension

setup(name='helloworld', version='1.0',  \

      ext_modules=[Extension('helloworld', ['hello.c'])])

现在,使用以下命令,它将执行所有需要的编译和链接步骤,使用正确的编译器和链接器命令和标志,并将生成的动态库复制到适当的目录 -


$ python setup.py install

在基于 Unix 的系统上,您很可能需要以 root 身份运行此命令才能获得写入站点包目录的权限。这在 Windows 上通常不是问题。


导入扩展

安装扩展后,您将能够在 Python 脚本中导入和调用该扩展,如下所示 -


#!/usr/bin/python

import helloworld


print helloworld.helloworld()

这将产生以下结果 -


Hello, Python extensions!!

传递函数参数

由于您很可能希望定义接受参数的函数,因此您可以为您的 C 函数使用其他签名之一。例如,接受一些参数的以下函数将被定义如下 -


static PyObject *module_func(PyObject *self, PyObject *args) {

   /* Parse args and do something interesting here. */

   Py_RETURN_NONE;

}

包含新函数条目的方法表如下所示 -


static PyMethodDef module_methods[] = {

   { "func", (PyCFunction)module_func, METH_NOARGS, NULL },

   { "func", module_func, METH_VARARGS, NULL },

   { NULL, NULL, 0, NULL }

};

您可以使用 API PyArg_ParseTuple函数从传递给 C 函数的一个 PyObject 指针中提取参数。


PyArg_ParseTuple 的第一个参数是 args 参数。这是您将要解析的对象。第二个参数是一个格式字符串,描述您希望它们出现的参数。每个参数由格式字符串中的一个或多个字符表示,如下所示。


static PyObject *module_func(PyObject *self, PyObject *args) {

   int i;

   double d;

   char *s;


   if (!PyArg_ParseTuple(args, "ids", &i, &d, &s)) {

      return NULL;

   }

   

   /* Do something interesting here. */

   Py_RETURN_NONE;

}

编译模块的新版本并导入它使您能够使用任意数量的任何类型的参数调用新函数 -


module.func(1, s="three", d=2.0)

module.func(i=1, d=2.0, s="three")

module.func(s="three", d=2.0, i=1)

你可能会想出更多的变化。


PyArg_ParseTuple函数_

这是PyArg_ParseTuple函数的标准签名 -


int PyArg_ParseTuple(PyObject* tuple,char* format,...)

此函数返回 0 表示错误,不等于 0 的值表示成功。tuple 是 PyObject*,它是 C 函数的第二个参数。这里的格式是一个描述强制和可选参数的 C 字符串。


这是PyArg_ParseTuple函数的格式代码列表 -


代码 C型 意义

C 字符 长度为 1 的 Python 字符串变为 C 字符。

d 双倍的 Python float 变成了 C double。

F 漂浮 Python 浮点数变成了 C 浮点数。

一世 整数 Python int 变成了 C int。

l Python int 变成了 C long。

大号 长长的 Python int 变成 C long long

PyObject* 获取对 Python 参数的非 NULL 借用引用。

s 字符* 没有嵌入 C char* 的空值的 Python 字符串。

## 字符*+整数 任何 Python 字符串到 C 地址和长度。

## 字符*+整数 只读单段缓冲区到 C 地址和长度。

Py_UNICODE* Python Unicode 没有嵌入到 C 中的空值。

你# Py_UNICODE*+int 任何 Python Unicode C 地址和长度。

# 字符*+整数 读/写单段缓冲区到 C 地址和长度。

z 字符* 与 s 一样,也接受 None(将 C char* 设置为 NULL)。

z# 字符*+整数 与 s# 一样,也接受 None(将 C char* 设置为 NULL)。

(...) 按照 ... Python 序列被视为每个项目的一个参数。

| 以下参数是可选的。

格式结束,后跟错误消息的函数名称。

; 格式结束,后跟整个错误消息文本。

返回值

Py_BuildValue采用与PyArg_ParseTuple非常相似的格式字符串。不是传入正在构建的值的地址,而是传入实际值。这是一个显示如何实现添加功能的示例 -


static PyObject *foo_add(PyObject *self, PyObject *args) {

   int a;

   int b;


   if (!PyArg_ParseTuple(args, "ii", &a, &b)) {

      return NULL;

   }

   return Py_BuildValue("i", a + b);

}

如果在 Python 中实现,这就是它的样子 -


def add(a, b):

   return (a + b)

您可以从函数中返回两个值,如下所示,这将在 Python 中使用列表进行捕获。


static PyObject *foo_add_subtract(PyObject *self, PyObject *args) {

   int a;

   int b;


   if (!PyArg_ParseTuple(args, "ii", &a, &b)) {

      return NULL;

   }

   return Py_BuildValue("ii", a + b, a - b);

}

如果在 Python 中实现,这就是它的样子 -


def add_subtract(a, b):

   return (a + b, a - b)

Py_BuildValue函数_

这是Py_BuildValue函数的标准签名 -


PyObject* Py_BuildValue(char* format,...)

这里的格式是一个描述要构建的 Python 对象的 C 字符串。Py_BuildValue的以下参数是从中构建结果的 C 值。PyObject *结果是一个新的参考。


下表列出了常用的代码字符串,其中零个或多个连接成字符串格式。


代码 C型 意义

C 字符 AC char 变成长度为 1 的 Python 字符串。

d 双倍的 AC double 成为 Python 浮点数。

F 漂浮 AC 浮点数变成了 Python 浮点数。

一世 整数 AC int 成为 Python int。

l AC long 成为 Python int。

ñ PyObject* 传递一个 Python 对象并窃取一个引用。

PyObject* 传递一个 Python 对象并像往常一样对其进行 INCREF。

欧& 转换+无效* 任意转换

s 字符* C 以 0 结尾的 char* 到 Python 字符串,或 NULL 到 None。

## 字符*+整数 C char* 和长度为 Python 字符串,或 NULL 为无。

Py_UNICODE* C 范围的、以 null 结尾的字符串到 Python Unicode,或 NULL 到 None。

你# Py_UNICODE*+int C 范围的字符串和长度到 Python Unicode,或 NULL 到 None。

# 字符*+整数 读/写单段缓冲区到 C 地址和长度。

z 字符* 与 s 一样,也接受 None(将 C char* 设置为 NULL)。

z# 字符*+整数 与 s# 一样,也接受 None(将 C char* 设置为 NULL)。

(...) 按照 ... 从 C 值构建 Python 元组。

[...] 按照 ... 从 C 值构建 Python 列表。

{...} 按照 ... 从 C 值、交替键和值构建 Python 字典。

代码 {...} 从偶数个 C 值(交替键和值)构建字典。例如,Py_BuildValue("{issi}",23,"zig","zag",42) 返回类似于 Python 的 {23:'zig','zag':42} 的字典。


Python - GUI 编程 (Tkinter)

Python 提供了各种用于开发图形用户界面 (GUI) 的选项。下面列出了最重要的。


Tkinter - Tkinter 是 Python 随附的 Tk GUI 工具包的 Python 接口。我们将在本章中查看此选项。


wxPython - 这是 wxWindows http://wxpython.org的开源 Python 接口。


JPython - JPython 是 Java 的 Python 端口,它使 Python 脚本可以无缝访问本地机器http://www.jython.org上的 Java 类库。


还有许多其他可用的接口,您可以在网上找到它们。


Tkinter 编程

Tkinter 是 Python 的标准 GUI 库。Python 与 Tkinter 结合使用提供了一种快速简便的方式来创建 GUI 应用程序。Tkinter 为 Tk GUI 工具包提供了一个强大的面向对象接口。


使用 Tkinter 创建 GUI 应用程序是一项简单的任务。您需要做的就是执行以下步骤 -


导入Tkinter模块。


创建 GUI 应用程序主窗口。


将一个或多个上述小部件添加到 GUI 应用程序。


进入主事件循环以针对用户触发的每个事件采取行动。


例子

#!/usr/bin/python


import Tkinter

top = Tkinter.Tk()

# Code to add widgets will go here...

top.mainloop()

这将创建一个以下窗口 -


传统知识窗口

Tkinter 小部件

Tkinter 提供各种控件,例如 GUI 应用程序中使用的按钮、标签和文本框。这些控件通常称为小部件。


Tkinter 目前有 15 种类型的小部件。我们在下表中介绍了这些小部件以及简要说明 -


编号 运营商和描述

1 按钮

Button 小部件用于在您的应用程序中显示按钮。


2 帆布

Canvas 小部件用于在您的应用程序中绘制形状,例如线条、椭圆、多边形和矩形。


3 复选按钮

Checkbutton 小部件用于将许多选项显示为复选框。用户可以一次选择多个选项。


4 入口

Entry 小部件用于显示单行文本字段以接受来自用户的值。


5 框架

Frame 小部件用作容器小部件来组织其他小部件。


6 标签

Label 小部件用于为其他小部件提供单行标题。它还可以包含图像。


7 列表框

Listbox 小部件用于向用户提供选项列表。


8 菜单按钮

Menubutton 小部件用于在应用程序中显示菜单。


9 菜单

Menu 小部件用于向用户提供各种命令。这些命令包含在 Menubutton 中。


10 信息

Message 小部件用于显示多行文本字段以接受来自用户的值。


11 单选按钮

Radiobutton 小部件用于将许多选项显示为单选按钮。用户一次只能选择一个选项。


12 规模

Scale 小部件用于提供滑块小部件。


13 滚动条

滚动条小部件用于向各种小部件(例如列表框)添加滚动功能。


14 文本

Text 小部件用于在多行中显示文本。


15 顶层

Toplevel 小部件用于提供单独的窗口容器。


16 纺纱箱

Spinbox 小部件是标准 Tkinter Entry 小部件的变体,可用于从固定数量的值中进行选择。


17 窗格窗口

PanedWindow 是一个容器小部件,可以包含任意数量的窗格,水平或垂直排列。


18 标签框

labelframe 是一个简单的容器小部件。它的主要目的是充当复杂窗口布局的间隔器或容器。


19 tkMessageBox

该模块用于在您的应用程序中显示消息框。


让我们详细研究这些小部件 -


标准属性

让我们看看它们的一些共同属性是如何指定的,例如大小、颜色和字体。


方面


颜色


字体


锚点


浮雕样式


位图


光标


让我们简要研究一下 -


几何管理

所有 Tkinter 小部件都可以访问特定的几何管理方法,这些方法的目的是在整个父小部件区域中组织小部件。Tkinter 公开了以下几何管理器类:pack、grid 和 place。


Pack()方法- 此几何管理器在将小部件放置在父小部件中之前将小部件组织在块中。


grid()方法- 此几何管理器在父小部件中以类似表格的结构组织小部件。


place()方法- 此几何管理器通过将小部件放置在父小部件中的特定位置来组织小部件。


让我们简要研究几何管理方法 -


Python - XML 处理

XML 是一种可移植的开源语言,它允许程序员开发可由其他应用程序读取的应用程序,而不管操作系统和/或开发语言如何。


什么是 XML?

可扩展标记语言 (XML) 是一种与 HTML 或 SGML 非常相似的标记语言。这是万维网联盟推荐的,可作为开放标准使用。


XML 对于跟踪中小型数据量非常有用,无需基于 SQL 的主干。


XML 解析器架构和 API

Python 标准库提供了一组最小但有用的接口来处理 XML。


XML 数据的两个最基本和最广泛使用的 API 是 SAX 和 DOM 接口。


Simple API for XML (SAX) - 在这里,您为感兴趣的事件注册回调,然后让解析器继续处理文档。当您的文档很大或您有内存限制时,这很有用,它会在从磁盘读取文件时解析文件,并且整个文件永远不会存储在内存中。


文档对象模型 (DOM) API - 这是万维网联盟的建议,其中将整个文件读入内存并以分层(基于树的)形式存储,以表示 XML 文档的所有特征。


在处理大文件时,SAX 显然无法像 DOM 那样快速处理信息。另一方面,仅使用 DOM 确实会杀死您的资源,尤其是在大量小文件上使用时。


SAX 是只读的,而 DOM 允许更改 XML 文件。由于这两个不同的 API 实际上是相互补充的,所以没有理由不能将它们都用于大型项目。


对于我们所有的 XML 代码示例,让我们使用一个简单的 XML 文件movies.xml作为输入 -


<collection shelf="New Arrivals">

<movie title="Enemy Behind">

   <type>War, Thriller</type>

   <format>DVD</format>

   <year>2003</year>

   <rating>PG</rating>

   <stars>10</stars>

   <description>Talk about a US-Japan war</description>

</movie>

<movie title="Transformers">

   <type>Anime, Science Fiction</type>

   <format>DVD</format>

   <year>1989</year>

   <rating>R</rating>

   <stars>8</stars>

   <description>A schientific fiction</description>

</movie>

   <movie title="Trigun">

   <type>Anime, Action</type>

   <format>DVD</format>

   <episodes>4</episodes>

   <rating>PG</rating>

   <stars>10</stars>

   <description>Vash the Stampede!</description>

</movie>

<movie title="Ishtar">

   <type>Comedy</type>

   <format>VHS</format>

   <rating>PG</rating>

   <stars>2</stars>

   <description>Viewable boredom</description>

</movie>

</collection>

使用 SAX API 解析 XML

SAX 是事件驱动的 XML 解析的标准接口。使用 SAX 解析 XML 通常需要您通过子类化 xml.sax.ContentHandler 创建自己的 ContentHandler。


您的ContentHandler处理您的 XML 风格的特定标签和属性。ContentHandler 对象提供了处理各种解析事件的方法。它拥有的解析器在解析 XML 文件时调用 ContentHandler 方法。


在 XML 文件的开头和结尾调用方法startDocument和endDocument 。方法characters(text)通过参数text 传递XML 文件的字符数据。


ContentHandler 在每个元素的开始和结束处被调用。如果解析器不处于命名空间模式,则调用方法startElement(tag, attributes)和endElement(tag);否则,调用相应的方法startElementNS和endElementNS。这里,tag 是元素标签,attributes 是一个 Attributes 对象。


以下是在继续之前要了解的其他重要方法 -


make_parser方法_

以下方法创建一个新的解析器对象并返回它。创建的解析器对象将是系统找到的第一个解析器类型。


xml.sax.make_parser( [parser_list] )

这是参数的详细信息 -


parser_list - 可选参数,由要使用的解析器列表组成,这些解析器必须全部实现 make_parser 方法。


解析方法_

以下方法创建一个 SAX 解析器并使用它来解析文档。


xml.sax.parse( xmlfile, contenthandler[, errorhandler])

这是参数的详细信息 -


xmlfile - 这是要读取的 XML 文件的名称。


contenthandler - 这必须是一个 ContentHandler 对象。


errorhandler - 如果指定,errorhandler 必须是 SAX ErrorHandler 对象。


parseString方法_

还有另一种方法可以创建 SAX 解析器并解析指定的XML 字符串。


xml.sax.parseString(xmlstring, contenthandler[, errorhandler])

这是参数的详细信息 -


xmlstring - 这是要读取的 XML 字符串的名称。


contenthandler - 这必须是一个 ContentHandler 对象。


errorhandler - 如果指定,errorhandler 必须是 SAX ErrorHandler 对象。


例子

#!/usr/bin/python


import xml.sax


class MovieHandler( xml.sax.ContentHandler ):

   def __init__(self):

      self.CurrentData = ""

      self.type = ""

      self.format = ""

      self.year = ""

      self.rating = ""

      self.stars = ""

      self.description = ""


   # Call when an element starts

   def startElement(self, tag, attributes):

      self.CurrentData = tag

      if tag == "movie":

         print "*****Movie*****"

         title = attributes["title"]

         print "Title:", title


   # Call when an elements ends

   def endElement(self, tag):

      if self.CurrentData == "type":

         print "Type:", self.type

      elif self.CurrentData == "format":

         print "Format:", self.format

      elif self.CurrentData == "year":

         print "Year:", self.year

      elif self.CurrentData == "rating":

         print "Rating:", self.rating

      elif self.CurrentData == "stars":

         print "Stars:", self.stars

      elif self.CurrentData == "description":

         print "Description:", self.description

      self.CurrentData = ""


   # Call when a character is read

   def characters(self, content):

      if self.CurrentData == "type":

         self.type = content

      elif self.CurrentData == "format":

         self.format = content

      elif self.CurrentData == "year":

         self.year = content

      elif self.CurrentData == "rating":

         self.rating = content

      elif self.CurrentData == "stars":

         self.stars = content

      elif self.CurrentData == "description":

         self.description = content

  

if ( __name__ == "__main__"):

   

   # create an XMLReader

   parser = xml.sax.make_parser()

   # turn off namepsaces

   parser.setFeature(xml.sax.handler.feature_namespaces, 0)


   # override the default ContextHandler

   Handler = MovieHandler()

   parser.setContentHandler( Handler )

   

   parser.parse("movies.xml")

这将产生以下结果 -


*****Movie*****

Title: Enemy Behind

Type: War, Thriller

Format: DVD

Year: 2003

Rating: PG

Stars: 10

Description: Talk about a US-Japan war

*****Movie*****

Title: Transformers

Type: Anime, Science Fiction

Format: DVD

Year: 1989

Rating: R

Stars: 8

Description: A schientific fiction

*****Movie*****

Title: Trigun

Type: Anime, Action

Format: DVD

Rating: PG

Stars: 10

Description: Vash the Stampede!

*****Movie*****

Title: Ishtar

Type: Comedy

Format: VHS

Rating: PG

Stars: 2

Description: Viewable boredom

有关 SAX API 文档的完整详细信息,请参阅标准Python SAX API。


使用 DOM API 解析 XML

文档对象模型 (“DOM”) 是万维网联盟 (W3C) 的跨语言 API,用于访问和修改 XML 文档。


DOM 对于随机访问应用程序非常有用。SAX 一次只允许您查看文档的一个位。如果您正在查看一个 SAX 元素,则无法访问另一个元素。


这是快速加载 XML 文档和使用 xml.dom 模块创建 minidom 对象的最简单方法。minidom 对象提供了一个简单的解析器方法,可以从 XML 文件快速创建一个 DOM 树。


样例语句调用minidom对象的parse(file[,parser])函数,将file指定的XML文件解析成DOM树对象。


#!/usr/bin/python


from xml.dom.minidom import parse

import xml.dom.minidom


# Open XML document using minidom parser

DOMTree = xml.dom.minidom.parse("movies.xml")

collection = DOMTree.documentElement

if collection.hasAttribute("shelf"):

   print "Root element : %s" % collection.getAttribute("shelf")


# Get all the movies in the collection

movies = collection.getElementsByTagName("movie")


# Print detail of each movie.

for movie in movies:

   print "*****Movie*****"

   if movie.hasAttribute("title"):

      print "Title: %s" % movie.getAttribute("title")


   type = movie.getElementsByTagName('type')[0]

   print "Type: %s" % type.childNodes[0].data

   format = movie.getElementsByTagName('format')[0]

   print "Format: %s" % format.childNodes[0].data

   rating = movie.getElementsByTagName('rating')[0]

   print "Rating: %s" % rating.childNodes[0].data

   description = movie.getElementsByTagName('description')[0]

   print "Description: %s" % description.childNodes[0].data

这将产生以下结果 -


Root element : New Arrivals

*****Movie*****

Title: Enemy Behind

Type: War, Thriller

Format: DVD

Rating: PG

Description: Talk about a US-Japan war

*****Movie*****

Title: Transformers

Type: Anime, Science Fiction

Format: DVD

Rating: R

Description: A schientific fiction

*****Movie*****

Title: Trigun

Type: Anime, Action

Format: DVD

Rating: PG

Description: Vash the Stampede!

*****Movie*****

Title: Ishtar

Type: Comedy

Format: VHS

Rating: PG

Description: Viewable boredom

有关 DOM API 文档的完整详细信息,请参阅标准Python DOM API


Python - 多线程编程

运行多个线程类似于同时运行多个不同的程序,但具有以下好处 -


一个进程中的多个线程与主线程共享相同的数据空间,因此可以比单独的进程更容易地共享信息或相互通信。


线程有时称为轻量级进程,它们不需要太多内存开销;它们比工艺便宜。


一个线程有一个开始、一个执行顺序和一个结束。它有一个指令指针,用于跟踪它当前在其上下文中运行的位置。


它可以被抢占(中断)


它可以在其他线程运行时暂时搁置(也称为休眠) - 这称为屈服。


开始一个新线程

要生成另一个线程,您需要调用线程模块中可用的以下方法 -


thread.start_new_thread ( function, args[, kwargs] )

此方法调用支持在 Linux 和 Windows 中快速有效地创建新线程。


方法调用立即返回,子线程启动并使用传递的args列表调用函数。当函数返回时,线程终止。


这里,args是一个参数元组;使用空元组调用函数而不传递任何参数。kwargs是关键字参数的可选字典。


例子

#!/usr/bin/python


import thread

import time


# Define a function for the thread

def print_time( threadName, delay):

   count = 0

   while count < 5:

      time.sleep(delay)

      count += 1

      print "%s: %s" % ( threadName, time.ctime(time.time()) )


# Create two threads as follows

try:

   thread.start_new_thread( print_time, ("Thread-1", 2, ) )

   thread.start_new_thread( print_time, ("Thread-2", 4, ) )

except:

   print "Error: unable to start thread"


while 1:

   pass

执行上述代码时,会产生以下结果 -


Thread-1: Thu Jan 22 15:42:17 2009

Thread-1: Thu Jan 22 15:42:19 2009

Thread-2: Thu Jan 22 15:42:19 2009

Thread-1: Thu Jan 22 15:42:21 2009

Thread-2: Thu Jan 22 15:42:23 2009

Thread-1: Thu Jan 22 15:42:23 2009

Thread-1: Thu Jan 22 15:42:25 2009

Thread-2: Thu Jan 22 15:42:27 2009

Thread-2: Thu Jan 22 15:42:31 2009

Thread-2: Thu Jan 22 15:42:35 2009

虽然它对于低级线程非常有效,但是与较新的线程模块相比,线程模块非常有限。


线程模块_

Python 2.4 中包含的较新的线程模块为线程提供了比上一节中讨论的线程模块更强大、更高级的支持。


threading模块公开了thread模块的所有方法并提供了一些额外的方法 -


threading.activeCount() - 返回活动线程对象的数量。


threading.currentThread() - 返回调用者线程控制中线程对象的数量。


threading.enumerate() - 返回当前活动的所有线程对象的列表。


除了方法之外,threading 模块还有实现线程的Thread类。Thread类提供的方法如下 -


run() - run() 方法是线程的入口点。


start() - start() 方法通过调用 run 方法启动线程。


join([time]) - join() 等待线程终止。


isAlive() - isAlive() 方法检查线程是否仍在执行。


getName() - getName() 方法返回线程的名称。


setName() - setName() 方法设置线程的名称。


使用线程模块创建线程

要使用 threading 模块实现新线程,您必须执行以下操作 -


定义Thread类的新子类。


覆盖__init__(self [,args])方法以添加其他参数。


然后,重写 run(self [,args]) 方法来实现线程在启动时应该做什么。


一旦你创建了新的Thread子类,你就可以创建它的一个实例,然后通过调用start()来启动一个新线程,然后调用run()方法。


例子

#!/usr/bin/python


import threading

import time


exitFlag = 0


class myThread (threading.Thread):

   def __init__(self, threadID, name, counter):

      threading.Thread.__init__(self)

      self.threadID = threadID

      self.name = name

      self.counter = counter

   def run(self):

      print "Starting " + self.name

      print_time(self.name, 5, self.counter)

      print "Exiting " + self.name


def print_time(threadName, counter, delay):

   while counter:

      if exitFlag:

         threadName.exit()

      time.sleep(delay)

      print "%s: %s" % (threadName, time.ctime(time.time()))

      counter -= 1


# Create new threads

thread1 = myThread(1, "Thread-1", 1)

thread2 = myThread(2, "Thread-2", 2)


# Start new Threads

thread1.start()

thread2.start()


print "Exiting Main Thread"

执行上述代码时,会产生以下结果 -


Starting Thread-1

Starting Thread-2

Exiting Main Thread

Thread-1: Thu Mar 21 09:10:03 2013

Thread-1: Thu Mar 21 09:10:04 2013

Thread-2: Thu Mar 21 09:10:04 2013

Thread-1: Thu Mar 21 09:10:05 2013

Thread-1: Thu Mar 21 09:10:06 2013

Thread-2: Thu Mar 21 09:10:06 2013

Thread-1: Thu Mar 21 09:10:07 2013

Exiting Thread-1

Thread-2: Thu Mar 21 09:10:08 2013

Thread-2: Thu Mar 21 09:10:10 2013

Thread-2: Thu Mar 21 09:10:12 2013

Exiting Thread-2

同步线程

Python 提供的线程模块包括一个易于实现的锁定机制,允许您同步线程。通过调用Lock()方法创建一个新锁,该方法返回新锁。


新锁对象的acquire(blocking)方法用于强制线程同步运行。可选的阻塞参数使您能够控制线程是否等待获取锁。


如果阻塞设置为 0,则如果无法获取锁,则线程立即返回 0 值,如果获取了锁,则返回 1。如果blocking设置为1,线程阻塞并等待锁被释放。


新锁对象的release()方法用于在不再需要锁时释放锁。


例子

#!/usr/bin/python


import threading

import time


class myThread (threading.Thread):

   def __init__(self, threadID, name, counter):

      threading.Thread.__init__(self)

      self.threadID = threadID

      self.name = name

      self.counter = counter

   def run(self):

      print "Starting " + self.name

      # Get lock to synchronize threads

      threadLock.acquire()

      print_time(self.name, self.counter, 3)

      # Free lock to release next thread

      threadLock.release()


def print_time(threadName, delay, counter):

   while counter:

      time.sleep(delay)

      print "%s: %s" % (threadName, time.ctime(time.time()))

      counter -= 1


threadLock = threading.Lock()

threads = []


# Create new threads

thread1 = myThread(1, "Thread-1", 1)

thread2 = myThread(2, "Thread-2", 2)


# Start new Threads

thread1.start()

thread2.start()


# Add threads to thread list

threads.append(thread1)

threads.append(thread2)


# Wait for all threads to complete

for t in threads:

    t.join()

print "Exiting Main Thread"

执行上述代码时,会产生以下结果 -


Starting Thread-1

Starting Thread-2

Thread-1: Thu Mar 21 09:11:28 2013

Thread-1: Thu Mar 21 09:11:29 2013

Thread-1: Thu Mar 21 09:11:30 2013

Thread-2: Thu Mar 21 09:11:32 2013

Thread-2: Thu Mar 21 09:11:34 2013

Thread-2: Thu Mar 21 09:11:36 2013

Exiting Main Thread

多线程优先队列

Queue模块允许您创建一个新的队列对象,该对象可以容纳特定数量的项目。有以下方法来控制队列 -


get() - get() 从队列中删除并返回一个项目。


put() - put 将项目添加到队列中。


qsize() - qsize() 返回当前队列中的项目数。


empty() - 如果队列为空,则 empty() 返回 True;否则为假。


full() - 如果队列已满,则 full() 返回 True;否则为假。


例子

#!/usr/bin/python


import Queue

import threading

import time


exitFlag = 0


class myThread (threading.Thread):

   def __init__(self, threadID, name, q):

      threading.Thread.__init__(self)

      self.threadID = threadID

      self.name = name

      self.q = q

   def run(self):

      print "Starting " + self.name

      process_data(self.name, self.q)

      print "Exiting " + self.name


def process_data(threadName, q):

   while not exitFlag:

      queueLock.acquire()

         if not workQueue.empty():

            data = q.get()

            queueLock.release()

            print "%s processing %s" % (threadName, data)

         else:

            queueLock.release()

         time.sleep(1)


threadList = ["Thread-1", "Thread-2", "Thread-3"]

nameList = ["One", "Two", "Three", "Four", "Five"]

queueLock = threading.Lock()

workQueue = Queue.Queue(10)

threads = []

threadID = 1


# Create new threads

for tName in threadList:

   thread = myThread(threadID, tName, workQueue)

   thread.start()

   threads.append(thread)

   threadID += 1


# Fill the queue

queueLock.acquire()

for word in nameList:

   workQueue.put(word)

queueLock.release()


# Wait for queue to empty

while not workQueue.empty():

   pass


# Notify threads it's time to exit

exitFlag = 1


# Wait for all threads to complete

for t in threads:

   t.join()

print "Exiting Main Thread"

执行上述代码时,会产生以下结果 -


Starting Thread-1

Starting Thread-2

Starting Thread-3

Thread-1 processing One

Thread-2 processing Two

Thread-3 processing Three

Thread-1 processing Four

Thread-2 processing Five

Exiting Thread-3

Exiting Thread-1

Exiting Thread-2

Exiting Main Thread


Python - 使用 SMTP 发送电子邮件

简单邮件传输协议 (SMTP) 是一种协议,用于处理在邮件服务器之间发送电子邮件和路由电子邮件。


Python 提供了smtplib模块,该模块定义了一个 SMTP 客户端会话对象,该对象可用于将邮件发送到具有 SMTP 或 ESMTP 侦听器守护程序的任何 Internet 机器。


这是创建一个 SMTP 对象的简单语法,稍后可用于发送电子邮件 -


import smtplib


smtpObj = smtplib.SMTP( [host [, port [, local_hostname]]] )

这是参数的详细信息 -


host - 这是运行 SMTP 服务器的主机。您可以指定主机的 IP 地址或域名,如 tutorialspoint.com。这是可选参数。


port - 如果您提供主机参数,那么您需要指定一个端口,SMTP 服务器正在侦听该端口。通常这个端口是 25。


local_hostname - 如果您的 SMTP 服务器在本地计算机上运行,那么您可以在此选项中仅指定localhost。


SMTP 对象有一个名为sendmail的实例方法,通常用于完成邮寄消息的工作。它需要三个参数 -


发件人- 带有发件人地址的字符串。


接收者- 字符串列表,每个接收者一个。


消息- 作为字符串的消息,格式为各种 RFC 中指定的格式。


例子

这是使用 Python 脚本发送一封电子邮件的简单方法。尝试一次 -


#!/usr/bin/python


import smtplib


sender = 'from@fromdomain.com'

receivers = ['to@todomain.com']


message = """From: From Person <from@fromdomain.com>

To: To Person <to@todomain.com>

Subject: SMTP e-mail test


This is a test e-mail message.

"""


try:

   smtpObj = smtplib.SMTP('localhost')

   smtpObj.sendmail(sender, receivers, message)         

   print "Successfully sent email"

except SMTPException:

   print "Error: unable to send email"

在这里,您在消息中放置了一个基本的电子邮件,使用三引号,注意正确格式化标题。电子邮件需要From、To和Subject标头,并用空行与电子邮件正文分开。


要发送邮件,您可以使用smtpObj连接到本地计算机上的 SMTP 服务器,然后使用sendmail方法以及消息、发件人地址和目标地址作为参数(即使发件人地址和发件人地址在 e -mail 本身,这些并不总是用于路由邮件)。


如果您没有在本地计算机上运行 SMTP 服务器,则可以使用smtplib客户端与远程 SMTP 服务器进行通信。除非您使用网络邮件服务(例如 Hotmail 或 Yahoo! Mail),否则您的电子邮件提供商必须向您提供您可以提供的外发邮件服务器详细信息,如下所示 -


smtplib.SMTP('mail.your-domain.com', 25)

使用 Python 发送 HTML 电子邮件

当您使用 Python 发送文本消息时,所有内容都被视为简单文本。即使您在文本消息中包含 HTML 标记,它也会显示为简单文本,并且 HTML 标记不会根据 HTML 语法进行格式化。但是 Python 提供了将 HTML 消息作为实际 HTML 消息发送的选项。


发送电子邮件时,您可以指定 Mime 版本、内容类型和字符集以发送 HTML 电子邮件。


例子

以下是将 HTML 内容作为电子邮件发送的示例。尝试一次 -


#!/usr/bin/python


import smtplib


message = """From: From Person <from@fromdomain.com>

To: To Person <to@todomain.com>

MIME-Version: 1.0

Content-type: text/html

Subject: SMTP HTML e-mail test


This is an e-mail message to be sent in HTML format


<b>This is HTML message.</b>

<h1>This is headline.</h1>

"""


try:

   smtpObj = smtplib.SMTP('localhost')

   smtpObj.sendmail(sender, receivers, message)         

   print "Successfully sent email"

except SMTPException:

   print "Error: unable to send email"

以电子邮件形式发送附件

要发送包含混合内容的电子邮件,需要将Content-type标头设置为multipart/mixed。然后,可以在边界内指定文本和附件部分。


边界以两个连字符开头,后跟一个唯一编号,该编号不能出现在电子邮件的消息部分中。表示电子邮件最后部分的最后边界也必须以两个连字符结尾。


附加文件应使用pack("m")函数进行编码,以便在传输前进行 base64 编码。


例子

以下是示例,它将文件/tmp/test.txt作为附件发送。尝试一次 -


#!/usr/bin/python


import smtplib

import base64


filename = "/tmp/test.txt"


# Read a file and encode it into base64 format

fo = open(filename, "rb")

filecontent = fo.read()

encodedcontent = base64.b64encode(filecontent)  # base64


sender = 'webmaster@tutorialpoint.com'

reciever = 'amrood.admin@gmail.com'


marker = "AUNIQUEMARKER"


body ="""

This is a test email to send an attachement.

"""

# Define the main headers.

part1 = """From: From Person <me@fromdomain.net>

To: To Person <amrood.admin@gmail.com>

Subject: Sending Attachement

MIME-Version: 1.0

Content-Type: multipart/mixed; boundary=%s

--%s

""" % (marker, marker)


# Define the message action

part2 = """Content-Type: text/plain

Content-Transfer-Encoding:8bit


%s

--%s

""" % (body,marker)


# Define the attachment section

part3 = """Content-Type: multipart/mixed; name=\"%s\"

Content-Transfer-Encoding:base64

Content-Disposition: attachment; filename=%s


%s

--%s--

""" %(filename, filename, encodedcontent, marker)

message = part1 + part2 + part3


try:

   smtpObj = smtplib.SMTP('localhost')

   smtpObj.sendmail(sender, reciever, message)

   print "Successfully sent email"

except Exception:

   print "Error: unable to send email"


Python - 网络编程

Python 提供了对网络服务的两个级别的访问。在底层,您可以访问底层操作系统中的基本套接字支持,这允许您为面向连接和无连接协议实现客户端和服务器。


Python 也有提供对特定应用程序级网络协议(如 FTP、HTTP 等)的更高级别访问的库。


本章让您了解网络中最著名的概念——套接字编程。


什么是套接字?

套接字是双向通信通道的端点。套接字可以在进程内、同一台机器上的进程之间或不同大陆上的进程之间进行通信。


套接字可以通过多种不同的通道类型实现:Unix 域套接字、TCP、UDP 等等。套接字库提供了用于处理公共传输的特定类以及用于处理其余部分的通用接口。


套接字有自己的词汇 -


编号 术语和说明

1

领域


用作传输机制的协议族。这些值是常量,例如 AF_INET、PF_INET、PF_UNIX、PF_X25 等。


2

类型


两个端点之间的通信类型,通常 SOCK_STREAM 用于面向连接的协议,SOCK_DGRAM 用于无连接协议。


3

协议


通常为零,这可用于识别域和类型内的协议变体。


4

主机名


网络接口的标识符 -


一个字符串,可以是主机名、点分四组地址或冒号(也可能是点)表示法的 IPV6 地址


一个字符串“<broadcast>”,它指定一个 INADDR_BROADCAST 地址。


一个零长度字符串,它指定 INADDR_ANY,或


一个整数,解释为主机字节顺序的二进制地址。


5

港口


每台服务器都侦听调用一个或多个端口的客户端。端口可以是 Fixnum 端口号、包含端口号的字符串或服务名称。


插座模块_

要创建套接字,您必须使用套接字模块中可用的socket.socket()函数,该函数具有一般语法 -


s = socket.socket (socket_family, socket_type, protocol=0)

这是参数的描述 -


socket_family - 如前所述,这是 AF_UNIX 或 AF_INET。


socket_type - 这是 SOCK_STREAM 或 SOCK_DGRAM。


协议- 这通常被忽略,默认为 0。


一旦你有了套接字对象,你就可以使用所需的函数来创建你的客户端或服务器程序。以下是所需的功能列表 -


服务器套接字方法

编号 方法和说明

1

s.bind()


此方法将地址(主机名、端口号对)绑定到套接字。


2

s.listen()


此方法设置并启动 TCP 侦听器。


3

s.accept()


这被动地接受 TCP 客户端连接,等待连接到达(阻塞)。


客户端套接字方法

编号 方法和说明

1

s.connect()


该方法主动发起 TCP 服务器连接。


通用套接字方法

编号 方法和说明

1

s.recv()


此方法接收 TCP 消息


2

s.send()


此方法传输 TCP 消息


3

s.recvfrom()


该方法接收UDP消息


4

s.sendto()


此方法传输 UDP 消息


5

s.close()


此方法关闭套接字


6

socket.gethostname()


返回主机名。


一个简单的服务器

为了编写 Internet 服务器,我们使用 socket 模块中可用的socket函数来创建一个 socket 对象。然后使用套接字对象调用其他函数来设置套接字服务器。


现在调用bind(hostname, port)函数来为给定主机上的服务指定一个端口。


接下来,调用返回对象的accept方法。此方法一直等到客户端连接到您指定的端口,然后返回一个连接对象,该对象表示与该客户端的连接。


#!/usr/bin/python           # This is server.py file


import socket               # Import socket module


s = socket.socket()         # Create a socket object

host = socket.gethostname() # Get local machine name

port = 12345                # Reserve a port for your service.

s.bind((host, port))        # Bind to the port


s.listen(5)                 # Now wait for client connection.

while True:

   c, addr = s.accept()     # Establish connection with client.

   print 'Got connection from', addr

   c.send('Thank you for connecting')

   c.close()                # Close the connection

一个简单的客户端

让我们编写一个非常简单的客户端程序,它打开到给定端口 12345 和给定主机的连接。使用 Python 的socket模块函数创建一个 socket 客户端非常简单。


socket.connect(hosname, port)在port上打开一个到hostname的 TCP 连接。一旦你打开了一个套接字,你就可以像任何 IO 对象一样读取它。完成后,记得关闭它,就像关闭文件一样。


以下代码是一个非常简单的客户端,它连接到给定的主机和端口,从套接字读取任何可用数据,然后退出 -


#!/usr/bin/python           # This is client.py file


import socket               # Import socket module


s = socket.socket()         # Create a socket object

host = socket.gethostname() # Get local machine name

port = 12345                # Reserve a port for your service.


s.connect((host, port))

print s.recv(1024)

s.close()                     # Close the socket when done

现在在后台运行这个 server.py,然后在 client.py 上面运行以查看结果。


# Following would start a server in background.

$ python server.py & 


# Once server is started run client as follows:

$ python client.py

这将产生以下结果 -


Got connection from ('127.0.0.1', 48437)

Thank you for connecting

Python 互联网模块

Python网络/互联网编程中一些重要模块的列表。


协议 常用功能 端口号 Python 模块

HTTP 网页 80 httplib、urllib、xmlrpclib

NNTP 新闻网新闻 119 nntplib

FTP 文件传输 20 ftplib, urllib

SMTP 发送电子邮件 25 smtplib

POP3 获取电子邮件 110 流行音乐库

IMAP4 获取电子邮件 143 imaplib

远程登录 命令行 23 远程登录库

地鼠 文件传输 70 gopherlib, urllib

请检查上述所有库以使用 FTP、SMTP、POP 和 IMAP 协议。


进一步阅读

这是 Socket 编程的快速入门。这是一个广阔的主题。建议通过以下链接查找更多详细信息 -


Unix 套接字编程。


Python 套接字库和模块。


Python - MySQL 数据库访问

数据库接口的 Python 标准是 Python DB-API。大多数 Python 数据库接口都遵循这个标准。


您可以为您的应用程序选择正确的数据库。Python 数据库 API 支持广泛的数据库服务器,例如 -


mSQL

MySQL

PostgreSQL

微软 SQL Server 2000

Informix

基地间

甲骨文

赛贝斯

以下是可用 Python 数据库接口的列表:Python 数据库接口和 API。您必须为需要访问的每个数据库下载单独的 DB API 模块。例如,如果您需要访问 Oracle 数据库和 MySQL 数据库,则必须同时下载 Oracle 和 MySQL 数据库模块。


DB API 为尽可能使用 Python 结构和语法处理数据库提供了最低标准。该 API 包括以下内容 -


导入 API 模块。

获取与数据库的连接。

发出 SQL 语句和存储过程。

关闭连接

我们将使用 MySQL 学习所有概念,所以让我们谈谈 MySQLdb 模块。


什么是 MySQLdb?

MySQLdb 是一个用于从 Python 连接到 MySQL 数据库服务器的接口。它实现了 Python 数据库 API v2.0,并构建在 MySQL C API 之上。


如何安装 MySQLdb?

在继续之前,请确保您的机器上安装了 MySQLdb。只需在您的 Python 脚本中输入以下内容并执行它 -


#!/usr/bin/python


import MySQLdb

如果它产生以下结果,则表示未安装 MySQLdb 模块 -


Traceback (most recent call last):

   File "test.py", line 3, in <module>

      import MySQLdb

ImportError: No module named MySQLdb

要安装 MySQLdb 模块,请使用以下命令 -


For Ubuntu, use the following command -

$ sudo apt-get install python-pip python-dev libmysqlclient-dev

For Fedora, use the following command -

$ sudo dnf install python python-devel mysql-devel redhat-rpm-config gcc

For Python command prompt, use the following command -

pip install MySQL-python

注意- 确保您具有安装上述模块的 root 权限。


数据库连接

在连接到 MySQL 数据库之前,请确保以下内容 -


您已经创建了一个数据库 TESTDB。


您已经在 TESTDB 中创建了一个表 EMPLOYEE。


此表包含字段 FIRST_NAME、LAST_NAME、AGE、SEX 和 INCOME。


用户 ID“testuser”和密码“test123”设置为访问 TESTDB。


Python 模块 MySQLdb 已正确安装在您的机器上。


您已通过 MySQL 教程了解MySQL 基础知识。


例子

以下是连接 MySQL 数据库“TESTDB”的示例


#!/usr/bin/python


import MySQLdb


# Open database connection

db = MySQLdb.connect("localhost","testuser","test123","TESTDB" )


# prepare a cursor object using cursor() method

cursor = db.cursor()


# execute SQL query using execute() method.

cursor.execute("SELECT VERSION()")


# Fetch a single row using fetchone() method.

data = cursor.fetchone()

print "Database version : %s " % data


# disconnect from server

db.close()

运行此脚本时,它会在我的 Linux 机器中产生以下结果。


Database version : 5.0.45

如果与数据源建立了连接,则返回一个连接对象并将其保存到db中以供进一步使用,否则db设置为 None。接下来,db对象用于创建游标对象,该对象又用于执行 SQL 查询。最后,在出来之前,确保关闭数据库连接并释放资源。


创建数据库表

一旦建立了数据库连接,我们就可以使用创建的游标的执行方法在数据库表中创建表或记录。


例子

让我们创建数据库表 EMPLOYEE -


#!/usr/bin/python


import MySQLdb


# Open database connection

db = MySQLdb.connect("localhost","testuser","test123","TESTDB" )


# prepare a cursor object using cursor() method

cursor = db.cursor()


# Drop table if it already exist using execute() method.

cursor.execute("DROP TABLE IF EXISTS EMPLOYEE")


# Create table as per requirement

sql = """CREATE TABLE EMPLOYEE (

         FIRST_NAME  CHAR(20) NOT NULL,

         LAST_NAME  CHAR(20),

         AGE INT,  

         SEX CHAR(1),

         INCOME FLOAT )"""


cursor.execute(sql)


# disconnect from server

db.close()

插入操作

当您要将记录创建到数据库表中时,它是必需的。


例子

以下示例执行 SQL INSERT语句以在 EMPLOYEE 表中创建记录 -


#!/usr/bin/python


import MySQLdb


# Open database connection

db = MySQLdb.connect("localhost","testuser","test123","TESTDB" )


# prepare a cursor object using cursor() method

cursor = db.cursor()


# Prepare SQL query to INSERT a record into the database.

sql = """INSERT INTO EMPLOYEE(FIRST_NAME,

         LAST_NAME, AGE, SEX, INCOME)

         VALUES ('Mac', 'Mohan', 20, 'M', 2000)"""

try:

   # Execute the SQL command

   cursor.execute(sql)

   # Commit your changes in the database

   db.commit()

except:

   # Rollback in case there is any error

   db.rollback()


# disconnect from server

db.close()

上面的例子可以写成如下动态创建 SQL 查询 -


#!/usr/bin/python


import MySQLdb


# Open database connection

db = MySQLdb.connect("localhost","testuser","test123","TESTDB" )


# prepare a cursor object using cursor() method

cursor = db.cursor()


# Prepare SQL query to INSERT a record into the database.

sql = "INSERT INTO EMPLOYEE(FIRST_NAME, \

       LAST_NAME, AGE, SEX, INCOME) \

       VALUES ('%s', '%s', '%d', '%c', '%d' )" % \

       ('Mac', 'Mohan', 20, 'M', 2000)

try:

   # Execute the SQL command

   cursor.execute(sql)

   # Commit your changes in the database

   db.commit()

except:

   # Rollback in case there is any error

   db.rollback()


# disconnect from server

db.close()

例子

以下代码段是另一种执行形式,您可以直接传递参数 -


..................................

user_id = "test123"

password = "password"


con.execute('insert into Login values("%s", "%s")' % \

             (user_id, password))

..................................

读操作

对任何数据库的读取操作意味着从数据库中获取一些有用的信息。


一旦我们的数据库连接建立,您就可以对该数据库进行查询了。您可以使用fetchone()方法获取单个记录,也可以使用 fetchall( )方法从数据库表中获取多个值。


fetchone() - 它获取查询结果集的下一行。结果集是使用游标对象查询表时返回的对象。


fetchall() - 它获取结果集中的所有行。如果已经从结果集中提取了一些行,则它会从结果集中检索剩余的行。


rowcount - 这是一个只读属性,返回受 execute() 方法影响的行数。


例子

以下过程从 EMPLOYEE 表中查询工资超过 1000 的所有记录 -


#!/usr/bin/python


import MySQLdb


# Open database connection

db = MySQLdb.connect("localhost","testuser","test123","TESTDB" )


# prepare a cursor object using cursor() method

cursor = db.cursor()


sql = "SELECT * FROM EMPLOYEE \

       WHERE INCOME > '%d'" % (1000)

try:

   # Execute the SQL command

   cursor.execute(sql)

   # Fetch all the rows in a list of lists.

   results = cursor.fetchall()

   for row in results:

      fname = row[0]

      lname = row[1]

      age = row[2]

      sex = row[3]

      income = row[4]

      # Now print fetched result

      print "fname=%s,lname=%s,age=%d,sex=%s,income=%d" % \

             (fname, lname, age, sex, income )

except:

   print "Error: unable to fecth data"


# disconnect from server

db.close()

这将产生以下结果 -


fname=Mac, lname=Mohan, age=20, sex=M, income=2000

更新操作

UPDATE 对任何数据库的操作意味着更新数据库中已经存在的一条或多条记录。


以下过程更新所有 SEX 为'M'的记录。在这里,我们将所有男性的 AGE 增加一年。


例子

#!/usr/bin/python


import MySQLdb


# Open database connection

db = MySQLdb.connect("localhost","testuser","test123","TESTDB" )


# prepare a cursor object using cursor() method

cursor = db.cursor()


# Prepare SQL query to UPDATE required records

sql = "UPDATE EMPLOYEE SET AGE = AGE + 1

                          WHERE SEX = '%c'" % ('M')

try:

   # Execute the SQL command

   cursor.execute(sql)

   # Commit your changes in the database

   db.commit()

except:

   # Rollback in case there is any error

   db.rollback()


# disconnect from server

db.close()

删除操作

当您想从数据库中删除一些记录时,需要执行 DELETE 操作。以下是从 AGE 超过 20 的 EMPLOYEE 中删除所有记录的过程 -


例子

#!/usr/bin/python


import MySQLdb


# Open database connection

db = MySQLdb.connect("localhost","testuser","test123","TESTDB" )


# prepare a cursor object using cursor() method

cursor = db.cursor()


# Prepare SQL query to DELETE required records

sql = "DELETE FROM EMPLOYEE WHERE AGE > '%d'" % (20)

try:

   # Execute the SQL command

   cursor.execute(sql)

   # Commit your changes in the database

   db.commit()

except:

   # Rollback in case there is any error

   db.rollback()


# disconnect from server

db.close()

执行交易

事务是一种确保数据一致性的机制。交易具有以下四个属性 -


原子性- 交易完成或根本没有发生任何事情。


一致性- 事务必须以一致的状态开始,并使系统处于一致的状态。


隔离- 交易的中间结果在当前交易之外不可见。


持久性 - 一旦提交事务,即使在系统故障之后,效果也是持久的。


Python DB API 2.0 提供了两种提交或回滚事务的方法。


例子

您已经知道如何实现事务。这又是一个类似的例子 -


# Prepare SQL query to DELETE required records

sql = "DELETE FROM EMPLOYEE WHERE AGE > '%d'" % (20)

try:

   # Execute the SQL command

   cursor.execute(sql)

   # Commit your changes in the database

   db.commit()

except:

   # Rollback in case there is any error

   db.rollback()

提交操作

提交是操作,它向数据库发出绿色信号以完成更改,并且在此操作之后,无法恢复任何更改。


这是一个调用提交方法的简单示例。


db.commit()

回滚操作

如果您对一项或多项更改不满意并且想要完全还原这些更改,请使用rollback()方法。


这是一个调用rollback()方法的简单示例。


db.rollback()

断开数据库

要断开数据库连接,请使用 close() 方法。


db.close()

如果用户使用 close() 方法关闭了与数据库的连接,则数据库将回滚任何未完成的事务。但是,您的应用程序最好不要显式调用提交或回滚,而不是依赖于任何 DB 较低级别的实现细节。


处理错误

错误的来源有很多。一些示例是执行的 SQL 语句中的语法错误、连接失败或为已取消或完成的语句句柄调用 fetch 方法。


DB API 定义了每个数据库模块中必须存在的许多错误。下表列出了这些例外情况。


编号 例外与说明

1

警告


用于非致命问题。必须继承 StandardError。


2

错误


错误的基类。必须继承 StandardError。


3

接口错误


用于数据库模块中的错误,而不是数据库本身。必须子类化错误。


4

数据库错误


用于数据库中的错误。必须子类化错误。


5

数据错误


DatabaseError 的子类,指数据中的错误。


6

操作错误


DatabaseError 的子类,它指的是诸如丢失与数据库的连接之类的错误。这些错误通常不受 Python 脚本编写者的控制。


7

完整性错误


DatabaseError 的子类,用于可能破坏关系完整性的情况,例如唯一性约束或外键。


8

内部错误


DatabaseError 的子类,它引用数据库模块内部的错误,例如游标不再处于活动状态。


9

编程错误


DatabaseError 的子类,它指的是错误的表名和其他可以安全归咎于您的错误。


10

不支持错误


DatabaseError 的子类,指尝试调用不受支持的功能。


您的 Python 脚本应该处理这些错误,但在使用上述任何异常之前,请确保您的 MySQLdb 支持该异常。您可以通过阅读 DB API 2.0 规范来获得有关它们的更多信息。


Python - CGI 编程

通用网关接口 (CGI) 是一组标准,用于定义 Web 服务器和自定义脚本之间如何交换信息。CGI 规范目前由 NCSA 维护。


什么是 CGI?

通用网关接口 (CGI) 是外部网关程序与 HTTP 服务器等信息服务器接口的标准。


当前版本是 CGI/1.1,CGI/1.2 正在开发中。


网页浏览

为了理解 CGI 的概念,让我们看看当我们点击一个超链接来浏览一个特定的网页或 URL 时会发生什么。


您的浏览器联系 HTTP Web 服务器并要求提供 URL,即文件名。


Web 服务器解析 URL 并查找文件名。如果它找到该文件,则将其发送回浏览器,否则发送一条错误消息,指示您请求了错误的文件。


Web 浏览器从 Web 服务器获取响应并显示接收到的文件或错误消息。


但是,可以设置 HTTP 服务器,以便无论何时请求某个目录中的文件,该文件都不会被发回;相反,它作为一个程序执行,并且该程序输出的任何内容都会发送回您的浏览器以显示。此功能称为通用网关接口或 CGI,程序称为 CGI 脚本。这些 CGI 程序可以是 Python 脚本、PERL 脚本、Shell 脚本、C 或 C++ 程序等。


CGI 架构图

CGI 架构

Web 服务器支持和配置

在继续进行 CGI 编程之前,请确保您的 Web 服务器支持 CGI 并且已配置为处理 CGI 程序。HTTP 服务器要执行的所有 CGI 程序都保存在预先配置的目录中。这个目录被称为 CGI 目录,按照惯例,它被命名为 /var/www/cgi-bin。按照惯例,CGI 文件的扩展名为。cgi,但您也可以使用 python 扩展名.py保存文件。


默认情况下,Linux 服务器配置为仅运行 /var/www 中 cgi-bin 目录中的脚本。如果要指定任何其他目录来运行 CGI 脚本,请在 httpd.conf 文件中注释以下行 -


<Directory "/var/www/cgi-bin">

   AllowOverride None

   Options ExecCGI

   Order allow,deny

   Allow from all

</Directory>


<Directory "/var/www/cgi-bin">

Options All

</Directory>

在这里,我们假设您已经成功启动并运行了 Web 服务器,并且您能够运行任何其他 CGI 程序,如 Perl 或 Shell 等。


第一个 CGI 程序

这是一个简单的链接,它链接到一个名为hello.py的 CGI 脚本。该文件保存在 /var/www/cgi-bin 目录下,内容如下。在运行 CGI 程序之前,请确保您已使用chmod 755 hello.py UNIX 命令更改文件模式以使文件可执行。


#!/usr/bin/python


print "Content-type:text/html\r\n\r\n"

print '<html>'

print '<head>'

print '<title>Hello World - First CGI Program</title>'

print '</head>'

print '<body>'

print '<h2>Hello World! This is my first CGI program</h2>'

print '</body>'

print '</html>'

如果单击 hello.py,则会产生以下输出 -


你好世界!这是我的第一个 CGI 程序

这个 hello.py 脚本是一个简单的 Python 脚本,它将其输出写入 STDOUT 文件,即屏幕。有一个重要且额外的功能可用,即要打印的第一行Content-type:text/html\r\n\r\n。该行被发送回浏览器,它指定要在浏览器屏幕上显示的内容类型。


至此,您一定已经了解了 CGI 的基本概念,并且可以使用 Python 编写许多复杂的 CGI 程序。该脚本还可以与任何其他外部系统交互以交换信息,例如 RDBMS。


HTTP 标头

行Content-type:text/html\r\n\r\n是 HTTP 标头的一部分,发送到浏览器以了解内容。所有 HTTP 标头都将采用以下形式 -


HTTP Field Name: Field Content


For Example

Content-type: text/html\r\n\r\n

很少有其他重要的 HTTP 标头,您将在 CGI 编程中经常使用它们。


编号 标题和说明

1

内容类型:


定义返回文件格式的 MIME 字符串。示例是 Content-type:text/html


2

过期:日期


信息失效的日期。浏览器使用它来决定何时需要刷新页面。有效日期字符串的格式为 01 Jan 1998 12:00:00 GMT。


3

地点:网址


返回的 URL,而不是请求的 URL。您可以使用此字段将请求重定向到任何文件。


4

最后修改:日期


上次修改资源的日期。


5

内容长度:N


返回的数据的长度(以字节为单位)。浏览器使用此值报告文件的估计下载时间。


6

设置 Cookie:字符串


设置通过字符串传递的cookie


CGI 环境变量

所有 CGI 程序都可以访问以下环境变量。这些变量在编写任何 CGI 程序时都起着重要作用。


编号 变量名称和描述

1

内容类型


内容的数据类型。当客户端向服务器发送附加内容时使用。例如,文件上传。


2

CONTENT_LENGTH


查询信息的长度。它仅适用于 POST 请求。


3

HTTP_COOKIE


以键值对的形式返回设置的 cookie。


4

HTTP_USER_AGENT


User-Agent request-header 字段包含有关发起请求的用户代理的信息。它是 Web 浏览器的名称。


5

PATH_INFO


CGI 脚本的路径。


6

请求参数


使用 GET 方法请求发送的 URL 编码信息。


7

远程地址


发出请求的远程主机的 IP 地址。这对于日志记录或身份验证很有用。


8

远程主机


发出请求的主机的完全限定名称。如果此信息不可用,则可以使用 REMOTE_ADDR 获取 IR 地址。


9

REQUEST_METHOD


用于发出请求的方法。最常用的方法是 GET 和 POST。


10

SCRIPT_FILENAME


CGI 脚本的完整路径。


11

SCRIPT_NAME


CGI 脚本的名称。


12

服务器名称


服务器的主机名或 IP 地址


13

服务器软件


服务器正在运行的软件的名称和版本。


这是列出所有 CGI 变量的小型 CGI 程序。单击此链接查看结果获取环境


#!/usr/bin/python


import os


print "Content-type: text/html\r\n\r\n";

print "<font size=+1>Environment</font><\br>";

for param in os.environ.keys():

   print "<b>%20s</b>: %s<\br>" % (param, os.environ[param])

GET 和 POST 方法

当您需要将一些信息从浏览器传递到 Web 服务器并最终传递到 CGI 程序时,您一定遇到过很多情况。最常见的是,浏览器使用两种方法将这些信息传递给 Web 服务器。这些方法是 GET 方法和 POST 方法。


使用 GET 方法传递信息

GET 方法发送附加到页面请求的编码用户信息。页面和编码信息由 ? 分隔。字符如下 -


http://www.test.com/cgi-bin/hello.py?key1=value1&key2=value2

GET 方法是将信息从浏览器传递到 Web 服务器的默认方法,它会生成一个长字符串,该字符串会出现在浏览器的 Location:box 中。如果您有密码或其他敏感信息要传递给服务器,切勿使用 GET 方法。GET 方法有大小限制:请求字符串中只能发送 1024 个字符。GET 方法使用 QUERY_STRING 标头发送信息,并且可以通过 QUERY_STRING 环境变量在您的 CGI 程序中访问。


您可以通过简单地连接键和值对以及任何 URL 来传递信息,或者您可以使用 HTML <FORM> 标记使用 GET 方法传递信息。


简单的 URL 示例:Get 方法

这是一个简单的 URL,它使用 GET 方法将两个值传递给 hello_get.py 程序。


/cgi-bin/hello_get.py?first_name=ZARA&last_name=ALI

下面是hello_get.py脚本,用于处理 Web 浏览器给出的输入。我们将使用cgi模块,这使得访问传递的信息变得非常容易 -


#!/usr/bin/python


# Import modules for CGI handling 

import cgi, cgitb 


# Create instance of FieldStorage 

form = cgi.FieldStorage() 


# Get data from fields

first_name = form.getvalue('first_name')

last_name  = form.getvalue('last_name')


print "Content-type:text/html\r\n\r\n"

print "<html>"

print "<head>"

print "<title>Hello - Second CGI Program</title>"

print "</head>"

print "<body>"

print "<h2>Hello %s %s</h2>" % (first_name, last_name)

print "</body>"

print "</html>"

这将产生以下结果 -


你好 ZARA 阿里

简单的FORM例子:GET方法

此示例使用 HTML FORM 和提交按钮传递两个值。我们使用相同的 CGI 脚本 hello_get.py 来处理这个输入。


<form action = "/cgi-bin/hello_get.py" method = "get">

First Name: <input type = "text" name = "first_name">  <br />


Last Name: <input type = "text" name = "last_name" />

<input type = "submit" value = "Submit" />

</form>

这是上述表单的实际输出,输入名字和姓氏,然后单击提交按钮以查看结果。


名:


姓:

 

使用 POST 方法传递信息

将信息传递给 CGI 程序的通常更可靠的方法是 POST 方法。这以与 GET 方法完全相同的方式打包信息,但不是在 ? 之后将其作为文本字符串发送。在 URL 中,它作为单独的消息发送。此消息以标准输入的形式进入 CGI 脚本。


下面是处理 GET 和 POST 方法的相同 hello_get.py 脚本。


#!/usr/bin/python


# Import modules for CGI handling 

import cgi, cgitb 


# Create instance of FieldStorage 

form = cgi.FieldStorage() 


# Get data from fields

first_name = form.getvalue('first_name')

last_name  = form.getvalue('last_name')


print "Content-type:text/html\r\n\r\n"

print "<html>"

print "<head>"

print "<title>Hello - Second CGI Program</title>"

print "</head>"

print "<body>"

print "<h2>Hello %s %s</h2>" % (first_name, last_name)

print "</body>"

print "</html>"

让我们再次采用与上面相同的示例,它使用 HTML FORM 和提交按钮传递两个值。我们使用相同的 CGI 脚本 hello_get.py 来处理这个输入。


<form action = "/cgi-bin/hello_get.py" method = "post">

First Name: <input type = "text" name = "first_name"><br />

Last Name: <input type = "text" name = "last_name" />


<input type = "submit" value = "Submit" />

</form>

这是上述表格的实际输出。您输入名字和姓氏,然后单击提交按钮以查看结果。


名:


姓:

 

将复选框数据传递给 CGI 程序

当需要选择多个选项时使用复选框。


这是带有两个复选框的表单的示例 HTML 代码 -


<form action = "/cgi-bin/checkbox.cgi" method = "POST" target = "_blank">

<input type = "checkbox" name = "maths" value = "on" /> Maths

<input type = "checkbox" name = "physics" value = "on" /> Physics

<input type = "submit" value = "Select Subject" />

</form>

此代码的结果如下形式 -


数学 物理 

下面是 checkbox.cgi 脚本,用于处理 Web 浏览器为复选框按钮提供的输入。


#!/usr/bin/python


# Import modules for CGI handling 

import cgi, cgitb 


# Create instance of FieldStorage 

form = cgi.FieldStorage() 


# Get data from fields

if form.getvalue('maths'):

   math_flag = "ON"

else:

   math_flag = "OFF"


if form.getvalue('physics'):

   physics_flag = "ON"

else:

   physics_flag = "OFF"


print "Content-type:text/html\r\n\r\n"

print "<html>"

print "<head>"

print "<title>Checkbox - Third CGI Program</title>"

print "</head>"

print "<body>"

print "<h2> CheckBox Maths is : %s</h2>" % math_flag

print "<h2> CheckBox Physics is : %s</h2>" % physics_flag

print "</body>"

print "</html>"

将单选按钮数据传递给 CGI 程序

当只需要选择一个选项时,使用单选按钮。


这是带有两个单选按钮的表单的示例 HTML 代码 -


<form action = "/cgi-bin/radiobutton.py" method = "post" target = "_blank">

<input type = "radio" name = "subject" value = "maths" /> Maths

<input type = "radio" name = "subject" value = "physics" /> Physics

<input type = "submit" value = "Select Subject" />

</form>

此代码的结果如下形式 -


数学 物理 

下面是 radiobutton.py 脚本,用于处理 Web 浏览器为单选按钮提供的输入 -


#!/usr/bin/python


# Import modules for CGI handling 

import cgi, cgitb 


# Create instance of FieldStorage 

form = cgi.FieldStorage() 


# Get data from fields

if form.getvalue('subject'):

   subject = form.getvalue('subject')

else:

   subject = "Not set"


print "Content-type:text/html\r\n\r\n"

print "<html>"

print "<head>"

print "<title>Radio - Fourth CGI Program</title>"

print "</head>"

print "<body>"

print "<h2> Selected Subject is %s</h2>" % subject

print "</body>"

print "</html>"

将文本区域数据传递给 CGI 程序

当必须将多行文本传递给 CGI 程序时,使用 TEXTAREA 元素。


这是带有 TEXTAREA 框的表单的示例 HTML 代码 -


<form action = "/cgi-bin/textarea.py" method = "post" target = "_blank">

<textarea name = "textcontent" cols = "40" rows = "4">

Type your text here...

</textarea>

<input type = "submit" value = "Submit" />

</form>

此代码的结果如下形式 -


Type your text here...

 

下面是处理网络浏览器输入的 textarea.cgi 脚本 -


#!/usr/bin/python


# Import modules for CGI handling 

import cgi, cgitb 


# Create instance of FieldStorage 

form = cgi.FieldStorage() 


# Get data from fields

if form.getvalue('textcontent'):

   text_content = form.getvalue('textcontent')

else:

   text_content = "Not entered"


print "Content-type:text/html\r\n\r\n"

print "<html>"

print "<head>";

print "<title>Text Area - Fifth CGI Program</title>"

print "</head>"

print "<body>"

print "<h2> Entered Text Content is %s</h2>" % text_content

print "</body>"

将下拉框数据传递给 CGI 程序

当我们有许多可用选项但只选择一两个时使用下拉框。


这是带有一个下拉框的表单的示例 HTML 代码 -


<form action = "/cgi-bin/dropdown.py" method = "post" target = "_blank">

<select name = "dropdown">

<option value = "Maths" selected>Maths</option>

<option value = "Physics">Physics</option>

</select>

<input type = "submit" value = "Submit"/>

</form>

此代码的结果如下形式 -



数学

 

下面是处理 Web 浏览器输入的 dropdown.py 脚本。


#!/usr/bin/python


# Import modules for CGI handling 

import cgi, cgitb 


# Create instance of FieldStorage 

form = cgi.FieldStorage() 


# Get data from fields

if form.getvalue('dropdown'):

   subject = form.getvalue('dropdown')

else:

   subject = "Not entered"


print "Content-type:text/html\r\n\r\n"

print "<html>"

print "<head>"

print "<title>Dropdown Box - Sixth CGI Program</title>"

print "</head>"

print "<body>"

print "<h2> Selected Subject is %s</h2>" % subject

print "</body>"

print "</html>"

在 CGI 中使用 Cookie

HTTP 协议是一种无状态协议。对于商业网站,需要维护不同页面之间的会话信息。例如,一个用户注册在完成许多页面后结束。如何跨所有网页维护用户的会话信息?


在许多情况下,使用 cookie 是记住和跟踪偏好、购买、佣金和其他更好的访问者体验或网站统计所需的信息的最有效方法。


这个怎么运作?

您的服务器以 cookie 的形式向访问者的浏览器发送一些数据。浏览器可以接受 cookie。如果是这样,它将作为纯文本记录存储在访问者的硬盘上。现在,当访问者到达您网站上的另一个页面时,cookie 就可以检索了。检索后,您的服务器知道/记住存储的内容。


Cookie 是 5 个可变长度字段的纯文本数据记录 -


Expires - cookie 过期的日期。如果此项为空,则 cookie 将在访问者退出浏览器时过期。


Domain - 您网站的域名。


Path - 设置 cookie 的目录或网页的路径。如果您想从任何目录或页面检索 cookie,这可能是空白的。


Secure - 如果此字段包含“安全”一词,则只能使用安全服务器检索 cookie。如果此字段为空,则不存在此类限制。


Name=Value - 以键值对的形式设置和检索 Cookie。


设置 Cookie

将 cookie 发送到浏览器非常容易。这些 cookie 与 HTTP Header 一起发送到 Content-type 字段。假设您要将 UserID 和 Password 设置为 cookie。设置 cookie 如下:


#!/usr/bin/python


print "Set-Cookie:UserID = XYZ;\r\n"

print "Set-Cookie:Password = XYZ123;\r\n"

print "Set-Cookie:Expires = Tuesday, 31-Dec-2007 23:12:40 GMT";\r\n"

print "Set-Cookie:Domain = www.tutorialspoint.com;\r\n"

print "Set-Cookie:Path = /perl;\n"

print "Content-type:text/html\r\n\r\n"

...........Rest of the HTML Content....

从这个例子中,您一定已经了解了如何设置 cookie。我们使用Set-Cookie HTTP 标头来设置 cookie。


设置 cookie 属性(如 Expires、Domain 和 Path)是可选的。值得注意的是,cookie 是在发送魔法行"Content-type:text/html\r\n\r\n之前设置的。


检索 Cookie

检索所有设置的 cookie 非常容易。Cookie 存储在 CGI 环境变量 HTTP_COOKIE 中,它们将具有以下形式 -


key1 = value1;key2 = value2;key3 = value3....

以下是如何检索 cookie 的示例。


#!/usr/bin/python


# Import modules for CGI handling 

from os import environ

import cgi, cgitb


if environ.has_key('HTTP_COOKIE'):

   for cookie in map(strip, split(environ['HTTP_COOKIE'], ';')):

      (key, value ) = split(cookie, '=');

      if key == "UserID":

         user_id = value


      if key == "Password":

         password = value


print "User ID  = %s" % user_id

print "Password = %s" % password

这将为上述脚本设置的 cookie 产生以下结果 -


User ID = XYZ

Password = XYZ123

文件上传示例

要上传文件,HTML 表单必须将 enctype 属性设置为multipart/form-data。具有文件类型的输入标签会创建一个“浏览”按钮。


<html>

<body>

   <form enctype = "multipart/form-data" 

                     action = "save_file.py" method = "post">

   <p>File: <input type = "file" name = "filename" /></p>

   <p><input type = "submit" value = "Upload" /></p>

   </form>

</body>

</html>

此代码的结果如下形式 -


文件:未选择任何文件



上面的示例已被故意禁用以保存人们在我们的服务器上上传文件,但您可以在您的服务器上尝试上面的代码。


这是处理文件上传的脚本save_file.py -


#!/usr/bin/python


import cgi, os

import cgitb; cgitb.enable()


form = cgi.FieldStorage()


# Get filename here.

fileitem = form['filename']


# Test if the file was uploaded

if fileitem.filename:

   # strip leading path from file name to avoid 

   # directory traversal attacks

   fn = os.path.basename(fileitem.filename)

   open('/tmp/' + fn, 'wb').write(fileitem.file.read())


   message = 'The file "' + fn + '" was uploaded successfully'

   

else:

   message = 'No file was uploaded'

   

print """\

Content-Type: text/html\n

<html>

<body>

   <p>%s</p>

</body>

</html>

""" % (message,)

如果您在 Unix/Linux 上运行上述脚本,则需要注意替换文件分隔符,如下所示,否则在您的 windows 机器上,上面的 open() 语句应该可以正常工作。


fn = os.path.basename(fileitem.filename.replace("\\", "/" ))

如何弹出“文件下载”对话框?

有时,您希望提供用户可以单击链接的选项,它会向用户弹出“文件下载”对话框,而不是显示实际内容。这很容易,可以通过 HTTP 标头来实现。此 HTTP 标头与上一节中提到的标头不同。


例如,如果您想从给定链接下载FileName文件,则其语法如下 -


#!/usr/bin/python


# HTTP Header

print "Content-Type:application/octet-stream; name = \"FileName\"\r\n";

print "Content-Disposition: attachment; filename = \"FileName\"\r\n\n";


# Actual File Content will go here.

fo = open("foo.txt", "rb")


str = fo.read();

print str


# Close opend file

fo.close()

希望您喜欢本教程。如果是,请将您的反馈发送给我:联系我们


Python - 正则表达式

正则表达式是一个特殊的字符序列,它使用模式中的特殊语法帮助您匹配或查找其他字符串或字符串集。正则表达式在 UNIX 世界中被广泛使用。


Python 模块re完全支持 Python 中的类 Perl 正则表达式。如果在编译或使用正则表达式时发生错误,re 模块会引发异常 re.error。


我们将介绍两个重要的函数,它们将用于处理正则表达式。但首先要说一件小事:有各种各样的字符,当它们用于正则表达式时会有特殊的含义。为避免在处理正则表达式时出现任何混淆,我们将使用原始字符串作为r'expression'。


匹配函数_

此函数尝试将 RE模式匹配到带有可选标志的字符串。


这是此函数的语法 -


re.match(pattern, string, flags=0)

这是参数的描述 -


编号 参数及说明

1

图案


这是要匹配的正则表达式。


2

细绳


这是字符串,它将被搜索以匹配字符串开头的模式。


3

旗帜


您可以使用按位或 (|) 指定不同的标志。这些是修饰符,在下表中列出。


re.match函数在成功时返回匹配对象,在失败时返回None。我们使用match对象的group(num)或groups()函数来获取匹配的表达式。


编号 匹配对象方法和描述

1

组(数量=0)


此方法返回整个匹配(或特定子组 num)


2

组()


此方法返回元组中的所有匹配子组(如果没有则为空)


例子

现场演示

#!/usr/bin/python

import re


line = "Cats are smarter than dogs"


matchObj = re.match( r'(.*) are (.*?) .*', line, re.M|re.I)


if matchObj:

   print "matchObj.group() : ", matchObj.group()

   print "matchObj.group(1) : ", matchObj.group(1)

   print "matchObj.group(2) : ", matchObj.group(2)

else:

   print "No match!!"

执行上述代码时,会产生以下结果 -


matchObj.group() :  Cats are smarter than dogs

matchObj.group(1) :  Cats

matchObj.group(2) :  smarter

搜索功能_

此函数使用可选标志搜索字符串中第一次出现的 RE模式。


这是此函数的语法 -


re.search(pattern, string, flags=0)

这是参数的描述 -


编号 参数及说明

1

图案


这是要匹配的正则表达式。


2

细绳


这是字符串,它将被搜索以匹配字符串中任何位置的模式。


3

旗帜


您可以使用按位或 (|) 指定不同的标志。这些是修饰符,在下表中列出。


re.search函数在成功时返回匹配对象,在失败时返回无。我们使用match对象的group(num)或groups()函数来获取匹配的表达式。


编号 匹配对象方法和描述

1

组(数量=0)


此方法返回整个匹配(或特定子组 num)


2

组()


此方法返回元组中的所有匹配子组(如果没有则为空)


例子

现场演示

#!/usr/bin/python

import re


line = "Cats are smarter than dogs";


searchObj = re.search( r'(.*) are (.*?) .*', line, re.M|re.I)


if searchObj:

   print "searchObj.group() : ", searchObj.group()

   print "searchObj.group(1) : ", searchObj.group(1)

   print "searchObj.group(2) : ", searchObj.group(2)

else:

   print "Nothing found!!"

执行上述代码时,会产生以下结果 -


searchObj.group() :  Cats are smarter than dogs

searchObj.group(1) :  Cats

searchObj.group(2) :  smarter

匹配与搜索

Python 提供了两种不同的基于正则表达式的原始操作:match仅在字符串的开头检查匹配,而search在字符串中的任何位置检查匹配(这是 Perl 默认所做的)。


例子

现场演示

#!/usr/bin/python

import re


line = "Cats are smarter than dogs";


matchObj = re.match( r'dogs', line, re.M|re.I)

if matchObj:

   print "match --> matchObj.group() : ", matchObj.group()

else:

   print "No match!!"


searchObj = re.search( r'dogs', line, re.M|re.I)

if searchObj:

   print "search --> searchObj.group() : ", searchObj.group()

else:

   print "Nothing found!!"

执行上述代码时,会产生以下结果 -


No match!!

search --> searchObj.group() :  dogs

搜索和替换

使用正则表达式的最重要的re方法之一是sub。


句法

re.sub(pattern, repl, string, max=0)

此方法用repl替换字符串中所有出现的 RE模式,除非提供了max ,否则替换所有出现。此方法返回修改后的字符串。


例子

现场演示

#!/usr/bin/python

import re


phone = "2004-959-559 # This is Phone Number"


# Delete Python-style comments

num = re.sub(r'#.*$', "", phone)

print "Phone Num : ", num


# Remove anything other than digits

num = re.sub(r'\D', "", phone)    

print "Phone Num : ", num

执行上述代码时,会产生以下结果 -


Phone Num :  2004-959-559

Phone Num :  2004959559

正则表达式修饰符:选项标志

正则表达式文字可能包括一个可选的修饰符来控制匹配的各个方面。修饰符被指定为可选标志。您可以使用异或 (|) 提供多个修饰符,如前所示,并且可以由以下之一表示 -


编号 修饰符和说明

1

re.I


执行不区分大小写的匹配。


2

重L


根据当前语言环境解释单词。这种解释会影响字母组(\w 和 \W),以及单词边界行为(\b 和 \B)。


3

再M


使 $ 匹配一行的结尾(不仅仅是字符串的结尾)并使 ^ 匹配任何行的开头(不仅仅是字符串的开头)。


4

回复


使句点(点)匹配任何字符,包括换行符。


5

回复


根据 Unicode 字符集解释字母。此标志影响 \w、\W、\b、\B 的行为。


6

re.X


允许“更可爱”的正则表达式语法。它忽略空格(除了在集合 [] 内或被反斜杠转义时)并将未转义的 # 视为注释标记。


正则表达式模式

除了控制字符(+ ? . * ^ $ ( ) [ ] { } | \),所有字符都匹配自己。您可以通过在控制字符前面加上反斜杠来转义它。


下表列出了 Python 中可用的正则表达式语法 -


编号 图案和描述

1

^


匹配行首。


2

$


匹配行尾。


3

.


匹配除换行符以外的任何单个字符。使用 m 选项也可以匹配换行符。


4

[...]


匹配括号中的任何单个字符。


5

[^...]


匹配任何不在括号中的单个字符


6

回覆*


匹配 0 次或多次出现的前面表达式。


7

重新+


匹配 1 次或多次出现的前面表达式。


8

回覆?


匹配 0 或 1 次出现的前面表达式。


9

重新{ n}


精确匹配前面表达式的 n 次出现。


10

再{n,}


匹配 n 次或多次出现的前面表达式。


11

重新{ n,米}


匹配至少 n 次和最多 m 次出现的前面表达式。


12

一个| b


匹配 a 或 b。


13

(回覆)


对正则表达式进行分组并记住匹配的文本。


14

(?imx)


临时切换正则表达式中的 i、m 或 x 选项。如果在括号中,则只有该区域受到影响。


15

(?-imx)


暂时关闭正则表达式中的 i、m 或 x 选项。如果在括号中,则只有该区域受到影响。


16

(?: 回覆)


分组正则表达式而不记住匹配的文本。


17

(?imx:重新)


临时切换括号内的 i、m 或 x 选项。


18

(?-imx:重新)


暂时关闭括号内的 i、m 或 x 选项。


19

(?#...)


评论。


20

(?= 重新)


使用模式指定位置。没有范围。


21

(?! 回覆)


使用模式否定指定位置。没有范围。


22

(?>重新)


匹配独立模式而不回溯。


23

\w


匹配单词字符。


24

\W


匹配非单词字符。


25

\s


匹配空格。等价于 [\t\n\r\f]。


26

\S


匹配非空白。


27

\d


匹配数字。相当于 [0-9]。


28

\D


匹配非数字。


29

\一种


匹配字符串的开头。


30

\Z


匹配字符串的结尾。如果存在换行符,它将在换行符之前匹配。


31

\z


匹配字符串的结尾。


32

\G


匹配上一场比赛结束的地点。


33

\b


在括号外匹配单词边界。在括号内时匹配退格 (0x08)。


34

\B


匹配非单词边界。


35

\n、\t 等


匹配换行符、回车符、制表符等。


36

\1...\9


匹配第 n 个分组的子表达式。


37

\10


如果已经匹配,则匹配第 n 个分组子表达式。否则指字符代码的八进制表示。


正则表达式示例

文字字符

编号 示例和说明

1

Python


匹配“蟒蛇”。


字符类

编号 示例和说明

1

[Pp]ython


匹配“Python”或“python”


2

擦[耶]


匹配“ruby”或“ruby”


3

[爱欧]


匹配任意一个小写元音


4

[0-9]


匹配任何数字;与 [0123456789] 相同


5

[阿兹]


匹配任何小写 ASCII 字母


6

[AZ]


匹配任何大写 ASCII 字母


7

[a-zA-Z0-9]


匹配以上任何一项


8

[^aeiou]


匹配除小写元音以外的任何内容


9

[^0-9]


匹配除数字以外的任何内容


特殊字符类

编号 示例和说明

1

.


匹配除换行符以外的任何字符


2

\d


匹配一个数字:[0-9]


3

\D


匹配非数字:[^0-9]


4

\s


匹配一个空白字符:[ \t\r\n\f]


5

\S


匹配非空白:[^ \t\r\n\f]


6

\w


匹配单个单词字符:[A-Za-z0-9_]


7

\W


匹配一个非单词字符:[^A-Za-z0-9_]


重复案例

编号 示例和说明

1

红宝石?


匹配“rub”或“ruby”:y 是可选的


2

红宝石*


匹配 "rub" 加上 0 个或多个 ys


3

红宝石+


匹配 "rub" 加上 1 个或多个 ys


4

\d{3}


精确匹配 3 位数字


5

\d{3,}


匹配 3 个或更多数字


6

\d{3,5}


匹配 3、4 或 5 位数字


非贪婪重复

这匹配最少的重复次数 -


编号 示例和说明

1

<.*>


贪婪重复:匹配“<python>perl>”


2

<.*?>


Nongreedy:匹配“<python>perl>”中的“<python>”


用括号分组

编号 示例和说明

1

\D\d+


无组:+ 重复 \d


2

(\D\d)+


分组:+ 重复 \D\d 对


3

([Pp]ython(, )?)+


匹配“Python”、“Python、python、python”等。


反向引用

这再次匹配先前匹配的组 -


编号 示例和说明

1

([Pp])ython&\1ails


匹配 python&pails 或 Python&Pails


2

(['"])[^\1]*\1


单引号或双引号字符串。\1 匹配第一组匹配的任何内容。\2 匹配第二组匹配的任何内容,等等。


备择方案

编号 示例和说明

1

蟒蛇|perl


匹配“python”或“perl”


2

擦(y|le))


匹配“红宝石”或“卢布”


3

Python(!+|\?)


“Python”后跟一个或多个!还是一个?


锚点

这需要指定匹配位置。


编号 示例和说明

1

^蟒蛇


在字符串或内部行的开头匹配“Python”


2

蟒蛇$


在字符串或行的末尾匹配“Python”


3

\APython


匹配字符串开头的“Python”


4

蟒蛇\Z


匹配字符串末尾的“Python”


5

\bPython\b


在单词边界匹配“Python”


6

\刷\ B


\B 是非单词边界:匹配“rube”和“ruby”中的“rub”,但不是单独匹配


7

蟒蛇(?=!)


如果后跟感叹号,则匹配“Python”。


8

Python(?!!)


如果后面没有感叹号,则匹配“Python”。


带括号的特殊语法

编号 示例和说明

1

R(?#comment)


匹配“R”。其余的都是评论


2

R(?i)uby


匹配“uby”时不区分大小写


3

R(?i:uby)


和上面一样


4

擦(?:y|le))


仅分组而不创建 \1 反向引用


Python - 面向对象

Python 从出现以来一直是一种面向对象的语言。因此,创建和使用类和对象非常容易。本章帮助您成为使用 Python 面向对象编程支持的专家。


如果您以前没有任何面向对象 (OO) 编程的经验,您可能需要查阅有关它的入门课程或至少某种教程,以便掌握基本概念。


但是,这里是面向对象编程 (OOP) 的小介绍,可让您快速入门 -


OOP 术语概述

类- 对象的用户定义原型,定义了一组表征类的任何对象的属性。属性是通过点符号访问的数据成员(类变量和实例变量)和方法。


类变量- 由类的所有实例共享的变量。类变量在类内定义,但在类的任何方法之外。类变量不像实例变量那样频繁使用。


数据成员- 保存与类及其对象关联的数据的类变量或实例变量。


函数重载- 将多个行为分配给特定函数。执行的操作因所涉及的对象或参数的类型而异。


Instance variable - 在方法内部定义的变量,仅属于类的当前实例。


继承- 将类的特征转移到从它派生的其他类。


Instance - 某个类的单个对象。例如,属于类 Circle 的对象 obj 是类 Circle 的一个实例。


实例化- 创建一个类的实例。


Method - 在类定义中定义的一种特殊函数。


Object - 由其类定义的数据结构的唯一实例。一个对象包括数据成员(类变量和实例变量)和方法。


运算符重载- 将多个函数分配给特定运算符。


创建类

class语句创建一个新的类定义。类的名称紧跟关键字class后跟冒号,如下所示 -


class ClassName:

   'Optional class documentation string'

   class_suite

该类有一个文档字符串,可以通过ClassName.__doc__访问。


class_suite由定义类成员、数据属性和函数的所有组件语句组成。


例子

以下是一个简单的 Python 类的示例 -


class Employee:

   'Common base class for all employees'

   empCount = 0


   def __init__(self, name, salary):

      self.name = name

      self.salary = salary

      Employee.empCount += 1

   

   def displayCount(self):

     print "Total Employee %d" % Employee.empCount


   def displayEmployee(self):

      print "Name : ", self.name,  ", Salary: ", self.salary

变量empCount是一个类变量,其值在此类的所有实例之间共享。这可以作为Employee.empCount从类内部或类外部访问。


第一个方法__init__()是一种特殊的方法,称为类构造函数或初始化方法,Python 在创建此类的新实例时会调用该方法。


您可以像普通函数一样声明其他类方法,但每个方法的第一个参数是self除外。Python 为您将self参数添加到列表中;调用方法时不需要包含它。


创建实例对象

要创建类的实例,您可以使用类名调用该类并传入其__init__方法接受的任何参数。


"This would create first object of Employee class"

emp1 = Employee("Zara", 2000)

"This would create second object of Employee class"

emp2 = Employee("Manni", 5000)

访问属性

您可以使用带有对象的点运算符访问对象的属性。类变量将使用类名访问,如下所示 -


emp1.displayEmployee()

emp2.displayEmployee()

print "Total Employee %d" % Employee.empCount

现在,将所有概念放在一起 -


现场演示

#!/usr/bin/python


class Employee:

   'Common base class for all employees'

   empCount = 0


   def __init__(self, name, salary):

      self.name = name

      self.salary = salary

      Employee.empCount += 1

   

   def displayCount(self):

     print "Total Employee %d" % Employee.empCount


   def displayEmployee(self):

      print "Name : ", self.name,  ", Salary: ", self.salary


"This would create first object of Employee class"

emp1 = Employee("Zara", 2000)

"This would create second object of Employee class"

emp2 = Employee("Manni", 5000)

emp1.displayEmployee()

emp2.displayEmployee()

print "Total Employee %d" % Employee.empCount

执行上述代码时,会产生以下结果 -


Name :  Zara ,Salary:  2000

Name :  Manni ,Salary:  5000

Total Employee 2

您可以随时添加、删除或修改类和对象的属性 -


emp1.age = 7  # Add an 'age' attribute.

emp1.age = 8  # Modify 'age' attribute.

del emp1.age  # Delete 'age' attribute.

您可以使用以下函数,而不是使用普通语句来访问属性 -


getattr(obj, name[, default]) - 访问对象的属性。


hasattr(obj,name) -检查属性是否存在。


setattr (obj,name,value) - 设置属性。如果属性不存在,那么它将被创建。


delattr (obj, name) - 删除一个属性。


hasattr(emp1, 'age')    # Returns true if 'age' attribute exists

getattr(emp1, 'age')    # Returns value of 'age' attribute

setattr(emp1, 'age', 8) # Set attribute 'age' at 8

delattr(empl, 'age')    # Delete attribute 'age'

内置类属性

每个 Python 类都遵循内置属性,并且可以像任何其他属性一样使用点运算符访问它们 -


__dict__ - 包含类名称空间的字典。


__doc__ - 类文档字符串或无,如果未定义。


__name__ - 类名。


__module__ - 定义类的模块名称。此属性在交互模式下为“__main__”。


__bases__ - 包含基类的可能为空的元组,按照它们在基类列表中出现的顺序排列。


对于上面的类,让我们尝试访问所有这些属性 -


现场演示

#!/usr/bin/python


class Employee:

   'Common base class for all employees'

   empCount = 0


   def __init__(self, name, salary):

      self.name = name

      self.salary = salary

      Employee.empCount += 1

   

   def displayCount(self):

     print "Total Employee %d" % Employee.empCount


   def displayEmployee(self):

      print "Name : ", self.name,  ", Salary: ", self.salary


print "Employee.__doc__:", Employee.__doc__

print "Employee.__name__:", Employee.__name__

print "Employee.__module__:", Employee.__module__

print "Employee.__bases__:", Employee.__bases__

print "Employee.__dict__:", Employee.__dict__

执行上述代码时,会产生以下结果 -


Employee.__doc__: Common base class for all employees

Employee.__name__: Employee

Employee.__module__: __main__

Employee.__bases__: ()

Employee.__dict__: {'__module__': '__main__', 'displayCount':

<function displayCount at 0xb7c84994>, 'empCount': 2, 

'displayEmployee': <function displayEmployee at 0xb7c8441c>, 

'__doc__': 'Common base class for all employees', 

'__init__': <function __init__ at 0xb7c846bc>}

销毁对象(垃圾收集)

Python 会自动删除不需要的对象(内置类型或类实例)以释放内存空间。Python 定期回收不再使用的内存块的过程称为垃圾收集。


Python 的垃圾收集器在程序执行期间运行,并在对象的引用计数达到零时触发。对象的引用计数随着指向它的别名数量的变化而变化。


对象的引用计数在被分配新名称或放置在容器(列表、元组或字典)中时会增加。使用del删除对象、重新分配其引用或超出范围时,对象的引用计数会减少。当一个对象的引用计数达到零时,Python 会自动收集它。


a = 40      # Create object <40>

b = a       # Increase ref. count  of <40> 

c = [b]     # Increase ref. count  of <40> 


del a       # Decrease ref. count  of <40>

b = 100     # Decrease ref. count  of <40> 

c[0] = -1   # Decrease ref. count  of <40> 

当垃圾收集器销毁孤立实例并回收其空间时,您通常不会注意到。但是一个类可以实现特殊方法__del__(),称为析构函数,当实例即将被销毁时调用该方法。此方法可用于清理实例使用的任何非内存资源。


例子

这个 __del__() 析构函数打印即将被销毁的实例的类名 -


现场演示

#!/usr/bin/python


class Point:

   def __init__( self, x=0, y=0):

      self.x = x

      self.y = y

   def __del__(self):

      class_name = self.__class__.__name__

      print class_name, "destroyed"


pt1 = Point()

pt2 = pt1

pt3 = pt1

print id(pt1), id(pt2), id(pt3) # prints the ids of the obejcts

del pt1

del pt2

del pt3

执行上述代码时,会产生以下结果 -


3083401324 3083401324 3083401324

Point destroyed

注意- 理想情况下,您应该在单独的文件中定义您的类,然后您应该使用import语句将它们导入您的主程序文件中。


类继承

您可以通过在新类名后面的括号中列出父类,从预先存在的类派生类来创建一个类,而不是从头开始。


子类继承其父类的属性,您可以像在子类中定义这些属性一样使用这些属性。子类也可以覆盖父类的数据成员和方法。


句法

派生类的声明很像它们的父类;但是,在类名之后给出了要继承的基类列表 -


class SubClassName (ParentClass1[, ParentClass2, ...]):

   'Optional class documentation string'

   class_suite

例子

现场演示

#!/usr/bin/python


class Parent:        # define parent class

   parentAttr = 100

   def __init__(self):

      print "Calling parent constructor"


   def parentMethod(self):

      print 'Calling parent method'


   def setAttr(self, attr):

      Parent.parentAttr = attr


   def getAttr(self):

      print "Parent attribute :", Parent.parentAttr


class Child(Parent): # define child class

   def __init__(self):

      print "Calling child constructor"


   def childMethod(self):

      print 'Calling child method'


c = Child()          # instance of child

c.childMethod()      # child calls its method

c.parentMethod()     # calls parent's method

c.setAttr(200)       # again call parent's method

c.getAttr()          # again call parent's method

执行上述代码时,会产生以下结果 -


Calling child constructor

Calling child method

Calling parent method

Parent attribute : 200

类似地,您可以从多个父类中驱动一个类,如下所示 -


class A:        # define your class A

.....


class B:         # define your class B

.....


class C(A, B):   # subclass of A and B

.....

您可以使用 issubclass() 或 isinstance() 函数来检查两个类和实例的关系。


如果给定的子类sub确实是超类sup的子类,则issubclass(sub, sup)布尔函数返回 true 。


isinstance(obj, Class)布尔函数如果obj是Class 的实例或者是 Class的子类的实例,则返回 true


覆盖方法

您始终可以覆盖您的父类方法。重写父类方法的一个原因是您可能希望子类中有特殊或不同的功能。


例子

现场演示

#!/usr/bin/python


class Parent:        # define parent class

   def myMethod(self):

      print 'Calling parent method'


class Child(Parent): # define child class

   def myMethod(self):

      print 'Calling child method'


c = Child()          # instance of child

c.myMethod()         # child calls overridden method

执行上述代码时,会产生以下结果 -


Calling child method

基础重载方法

下表列出了您可以在自己的类中覆盖的一些通用功能 -


编号 方法、描述和样品调用

1

__init__ ( self [,args...] )


构造函数(带有任何可选参数)


示例调用:obj = className(args)


2

__del__(自我)


析构函数,删除一个对象


示例调用:del obj


3

__repr__(自我)


可评估的字符串表示


示例调用:repr(obj)


4

__str__( 自我 )


可打印的字符串表示


示例调用:str(obj)


5

__cmp__ ( 自我, x )


对象比较


示例调用:cmp(obj, x)


重载运算符

假设您创建了一个 Vector 类来表示二维向量,当您使用加号运算符将它们相加时会发生什么?Python 很可能会对你大喊大叫。


但是,您可以在您的类中定义__add__方法来执行向量加法,然后加号运算符将按预期运行 -


例子

现场演示

#!/usr/bin/python


class Vector:

   def __init__(self, a, b):

      self.a = a

      self.b = b


   def __str__(self):

      return 'Vector (%d, %d)' % (self.a, self.b)

   

   def __add__(self,other):

      return Vector(self.a + other.a, self.b + other.b)


v1 = Vector(2,10)

v2 = Vector(5,-2)

print v1 + v2

执行上述代码时,会产生以下结果 -


Vector(7,8)

数据隐藏

对象的属性在类定义之外可能可见,也可能不可见。您需要使用双下划线前缀命名属性,然后这些属性对于外人来说是不直接可见的。


例子

现场演示

#!/usr/bin/python


class JustCounter:

   __secretCount = 0

  

   def count(self):

      self.__secretCount += 1

      print self.__secretCount


counter = JustCounter()

counter.count()

counter.count()

print counter.__secretCount

执行上述代码时,会产生以下结果 -


1

2

Traceback (most recent call last):

   File "test.py", line 12, in <module>

      print counter.__secretCount

AttributeError: JustCounter instance has no attribute '__secretCount'

Python 通过在内部更改名称以包含类名来保护这些成员。您可以访问诸如object._className__attrName 之类的属性。如果您将最后一行替换如下,那么它对您有用 -


.........................

print counter._JustCounter__secretCount

执行上述代码时,会产生以下结果 -


1

2

2


<< 1 2 3 > >>

Copyright www.jennal.cn Rights Reserved葵花宝典教程.鄂icp2022001145号-1

分享:

支付宝

微信