qpython3l中的androidpython helper模块块中有什么函数,怎么用

502 Bad Gateway
502 Bad Gateway
nginx/1.12.1& &&&&Python模块和C/C++的动态库间相互调用在实际的应用中会有所涉及,在此作一总结。
二、Python调用C/C++
1、Python调用C动态链接库
&&&&&&& Python调用C库比较简单,不经过任何封装打包成so,再使用python的ctypes调用即可。(1)C语言文件:pycall.c
/***gcc -o libpycall.so -shared -fPIC pycall.c*/
#include &stdio.h&
#include &stdlib.h&
int foo(int a, int b)
printf("you input %d and %d\n", a, b);
return a+b;
(2)gcc编译生成动态库libpycall.so:gcc -o libpycall.so -shared -fPIC pycall.c。使用g++编译生成C动态库的代码中的函数或者方法时,需要使用extern "C"来进行编译。
(3)Python调用动态库的文件:pycall.py
import ctypes
ll = ctypes.cdll.LoadLibrary
lib = ll("./libpycall.so")
lib.foo(1, 3)
print '***finish***'
(4)运行结果:
2、Python调用C++(类)动态链接库&
&&&&&& 需要extern "C"来辅助,也就是说还是只能调用C函数,不能直接调用方法,但是能解析C++方法。不是用extern "C",构建后的动态链接库没有这些函数的符号表。(1)C++类文件:pycallclass.cpp
#include &iostream&
using namespace
class TestLib
void display();
void display(int a);
void TestLib::display() {
cout&&"First display"&&
void TestLib::display(int a) {
cout&&"Second display:"&&a&&
extern "C" {
void display() {
obj.display();
void display_int() {
obj.display(2);
(2)g++编译生成动态库libpycall.so:g++ -o libpycallclass.so -shared -fPIC pycallclass.cpp。
(3)Python调用动态库的文件:pycallclass.py
import ctypes
so = ctypes.cdll.LoadLibrary
lib = so("./libpycallclass.so")
print 'display()'
lib.display()
print 'display(100)'
lib.display_int(100)
(4)运行结果:
3、Python调用C/C++可执行程序
(1)C/C++程序:main.cpp
#include &iostream&
using namespace
int test()
int a = 10, b = 5;
return a+b;
int main()
cout&&"---begin---"&&
int num = test();
cout&&"num="&&num&&
cout&&"---end---"&&
(2)编译成二进制可执行文件:g++ -o testmain main.cpp。
(3)Python调用程序:main.py
import commands
main = "./testmain"
if os.path.exists(main):
rc, out = commands.getstatusoutput(main)
print 'rc = %d, \nout = %s' % (rc, out)
print '*'*10
f = os.popen(main)
data = f.readlines()
print data
print '*'*10
os.system(main)
(4)运行结果:
4、扩展Python(C++为Python编写扩展模块)
&&&&&& 所有能被整合或导入到其它python脚本的代码,都可以被称为扩展。可以用Python来写扩展,也可以用C和C++之类的编译型的语言来写扩展。Python在设计之初就考虑到要让模块的导入机制足够抽象。抽象到让使用模块的代码无法了解到模块的具体实现细节。Python的可扩展性具有的优点:方便为语言增加新功能、具有可定制性、代码可以实现复用等。&&&&&& 为 Python 创建扩展需要三个主要的步骤:创建应用程序代码、利用样板来包装代码和编译与测试。(1)创建应用程序代码
#include &stdio.h&
#include &stdlib.h&
#include &string.h&
int fac(int n)
if (n & 2) return(1); /* 0! == 1! == 1 */
return (n)*fac(n-1); /* n! == n*(n-1)! */
char *reverse(char *s)
register char t,
*q = (s + (strlen(s) - 1)); /* bwd */
while (p & q)
/* if p & q */
/* swap & move ptrs */
*p++ = *q;
return(s);
int main()
char s[BUFSIZ];
printf("4! == %d\n", fac(4));
printf("8! == %d\n", fac(8));
printf("12! == %d\n", fac(12));
strcpy(s, "abcdef");
printf("reversing 'abcdef', we get '%s'\n", \
reverse(s));
strcpy(s, "madam");
printf("reversing 'madam', we get '%s'\n", \
reverse(s));
& & & &上述代码中有两个函数,一个是递归求阶乘的函数fac();另一个reverse()函数实现了一个简单的字符串反转算法,其主要目的是修改传入的字符串,使其内容完全反转,但不需要申请内存后反着复制的方法。
(2)用样板来包装代码&&&&&&& 接口的代码被称为&样板&代码,它是应用程序代码与Python解释器之间进行交互所必不可少的一部分。样板主要分为4步:a、包含Python的头文件;b、为每个模块的每一个函数增加一个型如PyObject* Module_func()的包装函数;c、为每个模块增加一个型如PyMethodDef ModuleMethods[]的数组;d、增加模块初始化函数void initModule()。
#include &stdio.h&
#include &stdlib.h&
#include &string.h&
int fac(int n)
if (n & 2) return(1);
return (n)*fac(n-1);
char *reverse(char *s)
register char t,
*q = (s + (strlen(s) - 1));
while (s && (p & q))
*p++ = *q;
return(s);
int test()
char s[BUFSIZ];
printf("4! == %d\n", fac(4));
printf("8! == %d\n", fac(8));
printf("12! == %d\n", fac(12));
strcpy(s, "abcdef");
printf("reversing 'abcdef', we get '%s'\n", \
reverse(s));
strcpy(s, "madam");
printf("reversing 'madam', we get '%s'\n", \
reverse(s));
#include "Python.h"
static PyObject *
Extest_fac(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "i", &num))
return NULL;
return (PyObject*)Py_BuildValue("i", fac(num));
static PyObject *
Extest_doppel(PyObject *self, PyObject *args)
char *orig_
char *dupe_
if (!PyArg_ParseTuple(args, "s", &orig_str))
return NULL;
retval = (PyObject*)Py_BuildValue("ss", orig_str,
dupe_str=reverse(strdup(orig_str)));
free(dupe_str);
#防止内存泄漏
static PyObject *
Extest_test(PyObject *self, PyObject *args)
return (PyObject*)Py_BuildValue("");
static PyMethodDef
ExtestMethods[] =
{ "fac", Extest_fac, METH_VARARGS },
{ "doppel", Extest_doppel, METH_VARARGS },
{ "test", Extest_test, METH_VARARGS },
{ NULL, NULL },
void initExtest()
Py_InitModule("Extest", ExtestMethods);
& & & & Python.h头文件在大多数类Unix系统中会在/usr/local/include/python2.x或/usr/include/python2.x目录中,系统一般都会知道文件安装的路径。
&&&&&&& 增加包装函数,所在模块名为Extest,那么创建一个包装函数叫Extest_fac(),在Python脚本中使用是先import Extest,然后调用Extest.fac(),当Extest.fac()被调用时,包装函数Extest_fac()会被调用,包装函数接受一个 Python的整数参数,把它转为C的整数,然后调用C的fac()函数,得到一个整型的返回值,最后把这个返回值转为Python的整型数做为整个函数调用的结果返回回去。其他两个包装函数Extest_doppel()和Extest_test()类似。&&&&&&&& 从Python到C的转换用PyArg_Parse*系列函数,int PyArg_ParseTuple():把Python传过来的参数转为C;int PyArg_ParseTupleAndKeywords()与PyArg_ParseTuple()作用相同,但是同时解析关键字参数;它们的用法跟C的sscanf函数很像,都接受一个字符串流,并根据一个指定的格式字符串进行解析,把结果放入到相应的指针所指的变量中去,它们的返回值为1表示解析成功,返回值为0表示失败。从C到Python的转换函数是PyObject* Py_BuildValue():把C的数据转为Python的一个对象或一组对象,然后返回之;Py_BuildValue的用法跟sprintf很像,把所有的参数按格式字符串所指定的格式转换成一个Python的对象。&&&&&&& C与Python之间数据转换的转换代码:&&&&&&& 为每个模块增加一个型如PyMethodDef ModuleMethods[]的数组,以便于Python解释器能够导入并调用它们,每一个数组都包含了函数在Python中的名字,相应的包装函数的名字以及一个METH_VARARGS常量,METH_VARARGS表示参数以tuple形式传入。 若需要使用PyArg_ParseTupleAndKeywords()函数来分析命名参数的话,还需要让这个标志常量与METH_KEYWORDS常量进行逻辑与运算常量 。数组最后用两个NULL来表示函数信息列表的结束。&&&&&&&& 所有工作的最后一部分就是模块的初始化函数,调用Py_InitModule()函数,并把模块名和ModuleMethods[]数组的名字传递进去,以便于解释器能正确的调用模块中的函数。(3)编译&&&&&&& 为了让新Python的扩展能被创建,需要把它们与Python库放在一起编译,distutils包被用来编译、安装和分发这些模块、扩展和包。&&&&&&& 创建一个setup.py 文件,编译最主要的工作由setup()函数来完成:
#!/usr/bin/env python
from distutils.core import setup, Extension
MOD = 'Extest'
setup(name=MOD, ext_modules=[Extension(MOD, sources=['Extest2.c'])])
& & & & Extension()第一个参数是(完整的)扩展的名字,如果模块是包的一部分的话,还要加上用'.'分隔的完整的包的名字。上述的扩展是独立的,所以名字只要写"Extest"就行;sources参数是所有源代码的文件列表,只有一个文件Extest2.c。setup需要两个参数:一个名字参数表示要编译哪个内容;另一个列表参数列出要编译的对象,上述要编译的是一个扩展,故把ext_modules参数的值设为扩展模块的列表。
&&&&&&& 运行setup.py build命令就可以开始编译我们的扩展了,提示部分信息:
creating build/lib.linux-x86_64-2.6
gcc -pthread -shared build/temp.linux-x86_64-2.6/Extest2.o -L/usr/lib64 -lpython2.6 -o build/lib.linux-x86_64-2.6/Extest.so
(4)导入和测试
&&&&&&&& 你的扩展会被创建在运行setup.py脚本所在目录下的build/lib.*目录中,可以切换到那个目录中来测试模块,或者也可以用命令把它安装到Python中:python setup.py install,会提示相应信息。&&&&&&&& 测试模块:(5)引用计数和线程安全&&&& Python对象引用计数的宏:Py_INCREF(obj)增加对象obj的引用计数,Py_DECREF(obj)减少对象obj的引用计数。Py_INCREF()和Py_DECREF()两个函数也有一个先检查对象是否为空的版本,分别为Py_XINCREF()和Py_XDECREF()。&&&&& 编译扩展的程序员必须要注意,代码有可能会被运行在一个多线程的Python环境中。这些线程使用了两个C宏Py_BEGIN_ALLOW_THREADS和Py_END_ALLOW_THREADS,通过将代码和线程隔离,保证了运行和非运行时的安全性,由这些宏包裹的代码将会允许其他线程的运行。
三、C/C++调用Python
&&&&&& C++可以调用Python脚本,那么就可以写一些Python的脚本接口供C++调用了,至少可以把Python当成文本形式的动态链接库,&需要的时候还可以改一改,只要不改变接口。缺点是C++的程序一旦编译好了,再改就没那么方便了。(1)Python脚本:pytest.py
#test function
def add(a,b):
print "in python function add"
print "a = " + str(a)
print "b = " + str(b)
print "ret = " + str(a+b)
def foo(a):
print "in python function foo"
print "a = " + str(a)
print "ret = " + str(a * a)
class guestlist:
def __init__(self):
print "aaaa"
print "bbbbb"
def __getitem__(self, id):
return "ccccc"
def update():
guest = guestlist()
print guest['aa']
(2)C++代码:
/**g++ -o callpy callpy.cpp -I/usr/include/python2.6 -L/usr/lib64/python2.6/config -lpython2.6**/
#include &Python.h&
int main(int argc, char** argv)
// 初始化Python
//在使用Python系统前,必须使用Py_Initialize对其
//进行初始化。它会载入Python的内建模块并添加系统路
//径到模块搜索路径中。这个函数没有返回值,检查系统
//是否初始化成功需要使用Py_IsInitialized。
Py_Initialize();
// 检查初始化是否成功
if ( !Py_IsInitialized() ) {
return -1;
// 添加当前路径
//把输入的字符串作为Python代码直接运行,返回0
//表示成功,-1表示有错。大多时候错误都是因为字符串
//中有语法错误。
PyRun_SimpleString("import sys");
PyRun_SimpleString("print '---import sys---'");
PyRun_SimpleString("sys.path.append('./')");
PyObject *pName,*pModule,*pDict,*pFunc,*pA
// 载入名为pytest的脚本
pName = PyString_FromString("pytest");
pModule = PyImport_Import(pName);
if ( !pModule ) {
printf("can't find pytest.py");
getchar();
return -1;
pDict = PyModule_GetDict(pModule);
if ( !pDict ) {
return -1;
// 找出函数名为add的函数
printf("----------------------\n");
pFunc = PyDict_GetItemString(pDict, "add");
if ( !pFunc || !PyCallable_Check(pFunc) ) {
printf("can't find function [add]");
getchar();
return -1;
// 参数进栈
pArgs = PyTuple_New(2);
PyObject* Py_BuildValue(char *format, ...)
把C++的变量转换成一个Python对象。当需要从
C++传递变量到Python时,就会使用这个函数。此函数
有点类似C的printf,但格式不同。常用的格式有
s 表示字符串,
i 表示整型变量,
f 表示浮点数,
O 表示一个Python对象。
PyTuple_SetItem(pArgs, 0, Py_BuildValue("l",3));
PyTuple_SetItem(pArgs, 1, Py_BuildValue("l",4));
// 调用Python函数
PyObject_CallObject(pFunc, pArgs);
//下面这段是查找函数foo 并执行foo
printf("----------------------\n");
pFunc = PyDict_GetItemString(pDict, "foo");
if ( !pFunc || !PyCallable_Check(pFunc) ) {
printf("can't find function [foo]");
getchar();
return -1;
pArgs = PyTuple_New(1);
PyTuple_SetItem(pArgs, 0, Py_BuildValue("l",2));
PyObject_CallObject(pFunc, pArgs);
printf("----------------------\n");
pFunc = PyDict_GetItemString(pDict, "update");
if ( !pFunc || !PyCallable_Check(pFunc) ) {
printf("can't find function [update]");
getchar();
return -1;
pArgs = PyTuple_New(0);
PyTuple_SetItem(pArgs, 0, Py_BuildValue(""));
PyObject_CallObject(pFunc, pArgs);
Py_DECREF(pName);
Py_DECREF(pArgs);
Py_DECREF(pModule);
// 关闭Python
Py_Finalize();
(3)C++编译成二进制可执行文件:g++ -o callpy callpy.cpp -I/usr/include/python2.6 -L/usr/lib64/python2.6/config -lpython2.6,编译选项需要手动指定Python的include路径和链接接路径(Python版本号根据具体情况而定)。
(4)运行结果:
(1)Python和C/C++的相互调用仅是测试代码,具体的项目开发还得参考Python的API文档。(2)两者交互,C++可为Python编写扩展模块,Python也可为C++提供脚本接口,更加方便于实际应用。(3)若有不足,请留言,在此先感谢!
阅读(...) 评论()Python中struct.pack()函数和struct.unpack()函数_Linux编程_Linux公社-Linux系统门户网站
你好,游客
Python中struct.pack()函数和struct.unpack()函数
来源:Linux社区&
作者:litaozijin
  Python中的struct主要是用来处理C结构数据的,读入时先转换为Python的字符串类型,然后再转换为Python的结构化类型,比如元组(tuple)啥的~。一般输入的渠道来源于文件或者网络的二进制流。
  1.struct.pack()和struct.unpack()
  在转化过程中,主要用到了一个格式化字符串(format strings),用来规定转化的方法和格式。
  下面来谈谈主要的方法:
  1.1 struct.pack(fmt,v1,v2,.....)
  将v1,v2等参数的值进行一层包装,包装的方法由fmt指定。被包装的参数必须严格符合fmt。最后返回一个包装后的字符串。
  1.2 struct.unpack(fmt,string)
  顾 名思义,解包。比如pack打包,然后就可以用unpack解包了。返回一个由解包数据(string)得到的一个元组(tuple), 即使仅有一个数据也会被解包成元组。其中len(string) 必须等于 calcsize(fmt),这里面涉及到了一个calcsize函数。struct.calcsize(fmt):这个就是用来计算fmt格式所描述的结构的大小。
 & 格式字符串(format string)由一个或多个格式字符(format characters)组成,对于这些格式字符的描述参照Python manual如下
Formatc TypePythonNote
string of length 1
signedchar
unsignedchar
unsignedshort
unsignedint
integer or long
unsignedlong
unsignedlonglong
2.代码示例
import struct
# native byteorder buffer = struct.pack("ihb", 1, 2, 3) print repr(buffer) print struct.unpack("ihb", buffer)
# data from a sequence, network byteorder data = [1, 2, 3] buffer = struct.pack("!ihb", *data)print repr(buffer) print struct.unpack("!ihb", buffer)
'\x01\x00\x00\x00\x02\x00\x03'(1, 2, 3)'\x00\x00\x00\x01\x00\x02\x03'(1, 2, 3)
首 先将参数1,2,3打包,打包前1,2,3明显属于python数据类型中的integer,pack后就变成了C结构的二进制串,转成 python的string类型来显示就是  '\x01\x00\x00\x00\x02\x00\x03'。由于本机是小端('little- endian',关于大端和小端的区别请参照这里, 故而高位放在低地址段。i 代表C struct中的int类型,故而本机占4位,1则表示为;h 代表C struct中的short类型,占2位,故表示为0200;同理b 代表C struct中的signed char类型,占1位,故而表示为03。
其他结构的转换也类似,有些特别的可以参考官方文档的Manual。
在Format string 的首位,有一个可选字符来决定大端和小端,列表如下:
little-endian
big-endian
network (= big-endian)
如果没有附加,默认为@,即使用本机的字符顺序(大端or小端),对于C结构的大小和内存中的对齐方式也是与本机相一致的(native),比如有的机器integer为2位而有的机器则为四位;有的机器内存对其位四位对齐,有的则是n位对齐(n未知,我也不知道多少)。
还有一个标准的选项,被描述为:如果使用标准的,则任何类型都无内存对齐。
比如刚才的小程序的后半部分,使用的format string中首位为!,即为大端模式标准对齐方式,故而输出的为'\x00\x00\x00\x01\x00\x02\x03',其中高位自己就被放在内存的高地址位了。
下面关于Python的文章您也可能喜欢,不妨参考下:
《Python核心编程 第二版》.(Wesley J. Chun ).[高清PDF中文版] 下载见
零基础如何入门Python
14.04安装Python 3.3.5&
6.5 脚本自动化装 Python2.6升级2.7&
CentOS上源码安装Python3.4&
Ubuntu 14.04下Python数据处理环境搭建&
Python Paramiko模块安装和使用&
《Python开发技术详解》.( 周伟,宗杰).[高清PDF扫描版+随书视频+代码]
在CentOS 6.5上安装Python2.7&
Ubuntu 14.04 LTS下编译安装Open Babel和Python语言绑定
Python常见数据结构整理&
本文永久更新链接地址:
相关资讯 & & &
& (04月06日)
& (02月18日)
& (04月14日)
& (04月06日)
& (02月01日)
   同意评论声明
   发表
尊重网上道德,遵守中华人民共和国的各项有关法律法规
承担一切因您的行为而直接或间接导致的民事或刑事法律责任
本站管理人员有权保留或删除其管辖留言中的任意内容
本站有权在网站内转载或引用您的评论
参与本评论即表明您已经阅读并接受上述条款Python 为什么要使用函数嵌套函数 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
已注册用户请 &
推荐学习书目
Python Sites
值得关注的项目
Python 编程
Python 为什么要使用函数嵌套函数
17:47:47 +08:00 · 3533 次点击
看一些代码会写成函数中嵌套函数,例如:
def func():
def new_func():
a = new_func()
这种写法和 lambda 和单独创建一个 function 有什么区别或优势吗?
21 回复 &| &直到
22:02:19 +08:00
& & 17:52:17 +08:00
& & 17:54:57 +08:00
对啊,要写闭包的时候很好用的
& & 18:03:54 +08:00
查看一下柯里化的定义,这样写返回的新函数能够保持当时的状态,而且能够达到惰性求值的效果(用到这个函数的时候再处理传入的参数)
& & 18:07:03 +08:00
例如装饰器传参,就是多层嵌套的函数,
& & 18:18:23 +08:00
因为 lambda 的限制
& & 21:07:01 +08:00
你的例子确实 lambda 也可以做到。但是下面的呢?
def func(x):
def new_func(y):
return x+y
return new_func
&&& a = func(10)
&&& a(3)
13
&&& a(5)
15
& & 22:27:16 +08:00 via Android
也许是为了方便吧。脚本嘛
& & 22:48:30 +08:00
额,其实我也不是很了解这两种用法的差异的,不过一不小心就写了出来 @
In [1]: def func(x):
return lambda y:y+x
In [2]: a = func(10)
In [3]: a(3)
Out[3]: 13
In [4]: a(5)
Out[4]: 15
& & 22:57:23 +08:00
@ 你的例子不合适啊。
&&& a = lambda x: lambda y: x + y
&&& b = a(10)
&&& b(3)
13
&&& b(5)
15
& & 23:08:38 +08:00
因为 lambda 是匿名的,我想区别应该是名字是否有意义,比如递归吧。
&&& def func(x, sum):
...
if(x==0):
...
return sum
...
return func(x-1, sum + x)
...
&&& func(10, 0)
55
lambda 大概写不出上面这个递归?
& & 23:35:47 +08:00 via Android
能省几个参数,函数的作用域小了
& & 00:08:01 +08:00 via Android
一般是返回一个函数指针时用。一般外部固定了函数指针的参数,但是自己又需要传递给函数指针一些数据,这样嵌套函数可以使得内部函数可以访问外部函数的变量。关键字:闭包,需求的例子:装饰器。
不用 lambda 的原因是 lambda 限制太大,不方便。
& & 08:29:38 +08:00
这就是 meta 编程啊
& & 09:14:42 +08:00
lambda 你能多写几行么
& & 09:44:52 +08:00 via Android
Python 里 lambda 只能写一行啊
& & 10:14:32 +08:00
需要做到这个的话直接用指针不行吗?
& & 10:30:52 +08:00
@ 无法实现,像下面的装饰器例子:
&显示 Gist 代码&
需要将 @(123) 的 123 传递给 fffff 函数,但是 fffff 函数是会被当作 hello3 参数给用户调用的,用户不会帮你把 123 传递进去,只能通过闭包的方式传递进去 123 .
& & 10:35:18 +08:00
lambda 写复杂的函数很麻烦啊
& & 13:55:52 +08:00
这是一种嵌套函数的写法,有时候它和 lambda 没什么区别,但有些情况下它会实现一个闭包,所以我姑且认为楼主是想知道闭包的特性.
那么这里首先强烈建议楼主了解一下 namespace 与变量作用域的相关知识.
如果只要了解闭包的概念,请参考这篇文章.
如果想知道闭包的实现原理.那么你必须得明白函数调用过程.因为闭包本身就是调用一个函数反回另一个函数.
这里推荐 UCSB 的教程,提供了一个交互式的函数调用演示程序.共6个课程,每个课程都很短,但看完这些你大概能对函数调用帧栈有初步了解.
到现在你已经可以开始探究 python 在函数调用中如何精妙地完成参数传递.
如果能坚持到这里,那么你已经停不下来了...函数调用过程中所有涉及到的源码作者都给出了分析,看完之后应该什么都明白了
以下链接可以看看,也许能帮助你理解源码.
& & 14:16:47 +08:00
一种劣习,让函数变成有状态的,或者叫不完全依赖于字面输入,还依赖一个隐藏输入的东西
& &147 天前
我用这个是因为 有时候要用递归,把 helper 放函数里面可以把外面函数的变量当全局变量。
另外就是 helper 只用这里会用,写外面不清晰。
& · & 893 人在线 & 最高记录 3541 & · &
创意工作者们的社区
World is powered by solitude
VERSION: 3.9.8.1 · 18ms · UTC 23:41 · PVG 07:41 · LAX 16:41 · JFK 19:41? Do have faith in what you're doing.Python中的函数详解 - Python - 伯乐在线
& Python中的函数详解
Python中的函数,无论是命名函数,还是匿名函数,都是语句和表达式的集合。在Python中,函数是第一个类对象,这意味着函数的用法并没有限制。Python函数的使用方式就像Python中其他值一样,例如字符串和数字等。Python函数拥有一些属性,通过使用Python内置函数dir就能查看这些属性,如下代码所示:
def square(x):
return x**2
&&& square
&function square at 0x031AA230&
&&& dir(square)
['__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__doc__', '__format__', '__get__', '__getattribute__', '__globals__', '__hash__', '__init__', '__module__', '__name__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'func_closure', 'func_code', 'func_defaults', 'func_dict', 'func_doc', 'func_globals', 'func_name']
def square(x):&&&&return x**2&&&& square&function square at 0x031AA230&&&& dir(square)['__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__doc__', '__format__', '__get__', '__getattribute__', '__globals__', '__hash__', '__init__', '__module__', '__name__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'func_closure', 'func_code', 'func_defaults', 'func_dict', 'func_doc', 'func_globals', 'func_name']&&&
其中,一些重要的函数属性包括以下几个:
1. __doc__返回指定函数的文档字符串。
def square(x):
"""return square of given number"""
return x**2
&&& square.__doc__
'return square of given number'
def square(x):&&&&"""return square of given number"""&&&&return x**2&&&& square.__doc__'return square of given number'
2. __name__返回函数名字。
def square(x):
"""return square of given number"""
return x**2
&&& square.func_name
def square(x):&&&&"""return square of given number"""&&&&return x**2&&&& square.func_name'square'
3. __module__返回函数定义所在模块的名字。
def square(x):
"""return square of given number"""
return x**2
&&& square.__module__
'__main__'
def square(x):&&&&"""return square of given number"""&&&&return x**2&&&& square.__module__'__main__'
4. func_defaults返回一个包含默认参数值的元组,默认参数将在后文进行讨论。
5. func_globals返回一个包含函数全局变量的字典引用。
def square(x):
"""return square of given number"""
return x**2
&&& square.func_globals
{'__builtins__': &module '__builtin__' (built-in)&, '__name__': '__main__', 'square': &function square at 0x10f099c08&, '__doc__': None, '__package__': None}
def square(x):&&&&"""return square of given number"""&&&&return x**2&&&& square.func_globals{'__builtins__': &module '__builtin__' (built-in)&, '__name__': '__main__', 'square': &function square at 0x10f099c08&, '__doc__': None, '__package__': None}
6. func_dict返回支持任意函数属性的命名空间。
def square(x):
"""return square of given number"""
return x**2
&&& square.func_dict
def square(x):&&&&"""return square of given number"""&&&&return x**2&&&& square.func_dict{}
7. func_closure返回一个胞体元组,其中胞体包含了函数自由变量的绑定,闭包将在后文讨论。
函数可以作为参数传递给其他函数。这些以其他函数作为参数的函数通常称为更高阶函数,这就构成了函数式编程中一个非常重要的部分。高阶函数一个很好的例子就是map函数,该函数接受一个函数和一个迭代器作为参数,并将函数应用于迭代器中的每一项,最后返回一个新的列表。我们将在下面的例子中演示这一点,例子中将前面定义的square函数和一个数字迭代器传递给map函数。
&&& map(square, range(10))
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
&&& map(square, range(10))[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
此外,函数也可以在其他函数代码块内部定义,同时也能从其他函数调用中返回。
def outer():
outer_var = "outer variable"
def inner():
return outer_var
return inner
def outer():&&&&outer_var = "outer variable"&&&&def inner():&&&&&&&&return outer_var&&&&return inner
在上面的例子中,我们在函数outer中定义了另一个函数inner,并且当函数outer执行时将返回inner函数。此外,像任何其他Python对象一样,函数也可以赋值给变量,如下所示:
def outer():
outer_var = "outer variable"
def inner():
return outer_var
return inner
&&& func = outer()
&function inner at 0x031AA270&
12345678910
def outer():&&&&outer_var = "outer variable"&&&&def inner():&&&&&&&&return outer_var&&&&return inner&&&& func = outer()&&& func&function inner at 0x031AA270&&&&
在上面的例子中,outer函数被调用时将会返回一个函数,并将返回的函数赋值给变量func。最后,该变量就可以像被返回的函数一样被调用:
&&& func()
'outer variable'
&&& func()'outer variable'
关键字def用于创建用户自定义函数,函数定义就是一些可执行的语句。
def square(x):
return x**2
def square(x):&&&&return x**2
在上面的square函数中,当包含该函数的模块加载到Python解释器中时,或者如果该函数在Python REPL中定义,那么将会执行函数定义语句def square(x)。然而,这对以可变数据结构作为值的默认参数有一些影响,这一点我们将会在后文讲述。函数定义的执行会绑定当前本地命名空间中的函数名(可以将命名空间当作名字到值的一种映射,并且这种映射还可以嵌套,命名空间和范围会在另一个教程中详细介绍)到一个函数对象,该对象是一个对函数中可执行代码的包装器。这个函数对象包含了一个对当前全局命名空间的引用,而当前命名空间指该函数调用时所使用的全局命名空间。此外,函数定义不会执行函数体,只有在函数被调用时才会执行函数体。
函数调用参数
除了正常的参数之外,Python函数还支持数量可变的参数。这些参数有主要有下面描述的三种类别:
1. 默认参数值:这允许用户为函数的参数定义一些默认值。这种情况下,可以以更少的参数来调用该函数,而函数调用时未提供的参数,Python会使用默认提供的值作为这些参数值。下面的例子展示了这种用法:
def show_args(arg, def_arg=1, def_arg2=2):
return "arg={}, def_arg={}, def_arg2={}".format(arg, def_arg, def_arg2)
def show_args(arg, def_arg=1, def_arg2=2):&&&&&&return "arg={}, def_arg={}, def_arg2={}".format(arg, def_arg, def_arg2)
上面例子函数的定义中,包含一个正常位置的参数arg和两个默认参数def_arg和def_arg2。该函数可以以下面中的任何一种方式进行调用:
(1)只提供非缺省位置参数值。在本例中,缺省参数取默认值:
def show_args(arg, def_arg=1, def_arg2=2):
return "arg={}, def_arg={}, def_arg2={}".format(arg, def_arg, def_arg2)
&&& show_args("tranquility")
'arg=tranquility, def_arg=1, def_arg2=2'
def show_args(arg, def_arg=1, def_arg2=2):&&&&&&return "arg={}, def_arg={}, def_arg2={}".format(arg, def_arg, def_arg2)&&&&&& show_args("tranquility")&&'arg=tranquility, def_arg=1, def_arg2=2'
(2)用提供的值覆盖一些默认的参数值,包括非缺省位置参数:
def show_args(arg, def_arg=1, def_arg2=2):
return "arg={}, def_arg={}, def_arg2={}".format(arg, def_arg, def_arg2)
&&& show_args("tranquility", "to Houston")
'arg=tranquility, def_arg=to Houston, def_arg2=2'
def show_args(arg, def_arg=1, def_arg2=2):&&&&&&return "arg={}, def_arg={}, def_arg2={}".format(arg, def_arg, def_arg2)&&&&&& show_args("tranquility", "to Houston")&&'arg=tranquility, def_arg=to Houston, def_arg2=2'
(3)为所有参数提供值,可以用这些值覆盖默认参数值:
def show_args(arg, def_arg=1, def_arg2=2):
return "arg={}, def_arg={}, def_arg2={}".format(arg, def_arg, def_arg2)
&&& show_args("tranquility", "to Houston", "the eagle has landed")
'arg=tranquility, def_arg=to Houston, def_arg2=the eagle has landed'
def show_args(arg, def_arg=1, def_arg2=2):&&&&&&return "arg={}, def_arg={}, def_arg2={}".format(arg, def_arg, def_arg2)&&& &&& show_args("tranquility", "to Houston", "the eagle has landed")'arg=tranquility, def_arg=to Houston, def_arg2=the eagle has landed'
当使用可变的默认数据结构作为默认参数时,需要特别小心。因为函数定义只执行一次,所以这些可变的数据结构(引用值)只在函数定义时创建一次。这就意味着,相同的可变数据结构将用于所有函数调用,如下面例子所示:
def show_args_using_mutable_defaults(arg, def_arg=[]):
def_arg.append("Hello World")
return "arg={}, def_arg={}".format(arg, def_arg)
&&& show_args_using_mutable_defaults("test")
"arg=test, def_arg=['Hello World']"
&&& show_args_using_mutable_defaults("test 2")
"arg=test 2, def_arg=['Hello World', 'Hello World']"
def show_args_using_mutable_defaults(arg, def_arg=[]):&&&&&&def_arg.append("Hello World")&&&&&&return "arg={}, def_arg={}".format(arg, def_arg)&&&&&& show_args_using_mutable_defaults("test")&&"arg=test, def_arg=['Hello World']" &&&&& show_args_using_mutable_defaults("test 2")&&"arg=test 2, def_arg=['Hello World', 'Hello World']"
在每个函数调用中,“Hello World”都被添加到了def_arg列表中,在调用两次函数之后,默认参数中将有两个“Hello World”字符串。当使用可变默认参数作为默认值时,注意到这一点非常重要。当我们讨论Python数据模型时,将会清楚理解其原因。
2. 关键字参数:以“kwarg=value”的形式使用关键字参数也可以调用函数。其中,kwarg指函数定义中使用的参数名称。以下面定义的含有默认和非默认参数的函数为例:
def show_args(arg, def_arg=1):
return "arg={}, def_arg={}".format(arg, def_arg)
def show_args(arg, def_arg=1):&&&&&& return "arg={}, def_arg={}".format(arg, def_arg)
为了演示使用关键字参数调用函数,下面的函数可以以后面的任何一种方式调用:
show_args(arg="test", def_arg=3)
show_args(arg="test", def_arg=3)
show_args(test)
show_args(test)
show_args(arg="test")
show_args(arg="test")
show_args("test", 3)
show_args("test", 3)
在函数调用中,关键字参数不得早于非关键字参数,所以以下调用会失败:
show_args(def_arg=4)
show_args(def_arg=4)
函数不能为一个参数提供重复值,所以下面的调用方法是非法的:
show_args("test", arg="testing")
show_args("test", arg="testing")
在上面的例子中,参数arg是位置参数,所以值“test”会分配给它。而试图将其再次分配给关键字arg,意味着在尝试多重赋值,而这是非法的。
传递的所有关键字参数必须匹配一个函数接受的参数,而包含非可选参数的关键字顺序并不重要,所以下面调换了参数顺序的写法是合法的:
show_args(def_arg="testing", arg="test")
show_args(def_arg="testing", arg="test")
3. 任意的参数列表:Python还支持定义这样的函数,该函数可以接受以元组形式传递的任意数量的参数,Python教程中的一个例子如下所示:
def write_multiple_items(file, separator, *args):
file.write(separator.join(args))
def write_multiple_items(file, separator, *args): &&&&file.write(separator.join(args))
任意数量的参数必须在正常参数之后。在本例中,任意数量参数存在于参数file和separator之后。下面是一个调用上述定义函数的示例:
f = open("test.txt", "wb")
write_multiple_items(f, " ", "one", "two", "three", "four", "five")
f = open("test.txt", "wb")write_multiple_items(f, " ", "one", "two", "three", "four", "five")
上面的参数one、two、three、four、five捆绑在一起共同组成了一个元组,通过参数args就能访问该元组。
解包函数参数
有时候,函数调用的参数可能是以元组、列表或字典的形式存在。可以通过使用“*”或“**”操作符将这些参数解包到函数内部以供调用。以下面的函数为例,该函数接受两个位置参数,并打印出两个参数的值。
def print_args(a, b):
def print_args(a, b):&&&&print a&&&&print b
如果提供给函数的参数值是以列表形式存在,那么我们可以直接将这些值解包到函数中,如下所示:
&&& args = [1, 2]
&&& print_args(*args)
&&& args = [1, 2]&&& print_args(*args)12
类似的,当我们有关键词时,可以使用字典来存储kwarg到值的映射关系,并利用“**”操作符将关键字参数解包到函数,如下所示:
&&& def parrot(voltage, state=’a stiff’, action=’voom’):
print "-- This parrot wouldn’t", action,
print "if you put", voltage, "volts through it.",
print "E’s", state, "!"
&&& d = {"voltage": "four million", "state": "bleedin’ demised", "action": "VOOM"}
&&& parrot(**d)
&&& This parrot wouldn’t VOOM if you put four million volts through it. E’s bleedin’ demised
&&& def parrot(voltage, state=’a stiff’, action=’voom’):&&&&&&&&&& print "-- This parrot wouldn’t", action,&&&&&&&&&& print "if you put", voltage, "volts through it.",&&&&&&&&&& print "E’s", state, "!"&&&& d = {"voltage": "four million", "state": "bleedin’ demised", "action": "VOOM"}&&& parrot(**d)&&& This parrot wouldn’t VOOM if you put four million volts through it. E’s bleedin’ demised
利用“*”和“**”定义函数
有时候,当定义一个函数时,我们之前可能不知道参数的数量。这就导致了下面签名的函数定义:
show_args(arg, *args, **kwargs)
show_args(arg, *args, **kwargs)
“*args”参数表示未知的位置参数序列长度,而“**kwargs”代表包含关键字和值映射关系的字典,它可以包含任意数量的关键字和值映射,并且在函数定义中“*args”必须位于“**kwargs”前面。下面的代码演示了这种情况:
def show_args(arg, *args, **kwargs):
for item in args:
print args
for key, value in kwargs:
print key, value
&&& args = [1, 2, 3, 4]
&&& kwargs = dict(name='testing', age=24, year=2014)
&&& show_args("hey", *args, **kwargs)
name testing
123456789101112131415161718
def show_args(arg, *args, **kwargs):&&&&print arg&&&&for item in args:&&&&&&&&print args&&&&for key, value in kwargs:&&&&&&&&print key, value&&&& args = [1, 2, 3, 4]&&& kwargs = dict(name='testing', age=24, year=2014)&&& show_args("hey", *args, **kwargs)hey1234age 24name testingyear 2014
必须向函数提供正常的参数,但“*args”和“**kwargs”却是可选的,如下所示:
&&& show_args("hey", *args, **kwargs)
&&& show_args("hey", *args, **kwargs)hey
在函数调用中,普通参数以正常方式提供,而可选参数则可以通过解包的形式到达函数调用中。
Python也支持匿名函数,这些函数使用lambda关键字创建。Python中Lambda表达式的形式如下所示:
lambda_expr ::=
"lambda" [parameter_list]: expression
lambda_expr ::=&&"lambda" [parameter_list]: expression
Lambda表达式返回评估后的函数对象,并且具有与命名函数相同的属性。在Python中,Lambda表达式通常只用于非常简单的函数,如下所示:
&&& square = lambda x: x**2
&&& for i in range(10):
1234567891011121314
&&& square = lambda x: x**2&&& for i in range(10):&&&&square(i)0149162536496481&&&
上面的lambda表达式的功能与下面命名函数的功能相同:
def square(x):
return x**2
def square(x):&&&&return x**2
嵌套函数和闭包
在一个函数内部定义函数就创建了嵌套函数,如下所示:
def outer():
outer_var = "outer variable"
def inner():
return outer_var
return inner
```python&& def outer():&&&&&& outer_var = "outer variable"&&&&&& def inner():&&&&&&&&&& return outer_var&&&&&&&&return inner```
在这种类型的函数定义中,函数inner只在函数outer内部有效,所以当内部函数需要被返回(移动到外部作用范围)或被传递给另一个函数时,使用嵌套函数通常比较方便。在如在上面的嵌套函数中,每次调用外部函数时都会创建一个新的嵌套函数实例,这是因为,在每次执行外部函数时,都会执行一次内部函数定义,而其函数体则不会被执行。
嵌套函数可以访问创建它的环境,这是python函数定义语义的直接结果。一个结果是,外部函数中定义的变量可以在内部函数中引用,即使外部函数已经执行结束。
def outer():
outer_var = "outer variable"
def inner():
return outer_var
return inner
&&& x = outer()
&function inner at 0x0273BCF0&
'outer variable'
1234567891011
def outer():&&&&outer_var = "outer variable"&&&&def inner():&&&&&&&&return outer_var&&&&return inner&&&& x = outer()&&& x&function inner at 0x0273BCF0&&&& x()'outer variable'
当内部嵌套的函数引用外部函数中的变量时,我们说嵌套函数相对于引用变量是封闭的。我们可以使用函数对象的一个特殊属性“__closure__”来访问这个封闭的变量,如下所示:
&&& cl = x.__closure__
(&cell at 0x029E4470: str object at 0x02A0FD90&,)
&&& cl[0].cell_contents
'outer variable'
&&& cl = x.__closure__&&& cl(&cell at 0x029E4470: str object at 0x02A0FD90&,)&&&& cl[0].cell_contents'outer variable'
Python中的闭包有一个古怪的行为。在Python 2.x及更低版本中,指向不可变类型(例如字符串和数字)的变量不能在闭包内反弹。下面的例子说明了这一点:
def counter():
count += 1
return count
&&& c = counter()
Traceback (most recent call last):
File "&stdin&", line 1, in &module&
File "&stdin&", line 4, in c
UnboundLocalError: local variable 'count' referenced before assignment
12345678910111213
def counter():&&&&count = 0&&&&def c():&&&&&&&&count += 1&&&&&&&&return count&&&&return c&&&& c = counter()&&& c()Traceback (most recent call last):&&File "&stdin&", line 1, in &module&&&File "&stdin&", line 4, in cUnboundLocalError: local variable 'count' referenced before assignment
一个相当不可靠的解决方案是,使用一个可变类型来捕获闭包,如下所示:
def counter():
count = [0]
count[0] += 1
return count[0]
&&& c = counter()
1234567891011121314
def counter():&&&&count = [0]&&&&def c():&&&&&&&&count[0] += 1&&&&&&&&return count[0]&&&&return c&&&& c = counter()&&& c()1&&& c()2&&& c()3
Python 3引入了“nonlocal”关键字用来解决下面所示的闭包范围问题。在本教程命名空间一节中,我们更加详细地描述了这些古怪用法。
def counter():
nonlocal count
count += 1
return count
def counter():&&&&&& count = 0&&&&&& def c():&&&&&&&&&& nonlocal count&&&&&&&&&& count += 1&&&&&&&&&& return count&&&&&&&&return c
闭包可以用来维持状态(与类作用不同),在一些简单的情况下,还可以提供一种简洁性与可读性比类更强的解决方案,我们使用中的一个日志例子来说明这一点。假设一个非常简单的日志API,它使用基于类的面向对象思想,并可以在不同级别上打印日志:
class Log:
def __init__(self, level):
self._level = level
def __call__(self, message):
print("{}: {}".format(self._level, message))
log_info = Log("info")
log_warning = Log("warning")
log_error = Log("error")
12345678910
class Log:&&&&def __init__(self, level):&&&&&&&&self._level = level&&&&&def __call__(self, message):&&&&&&&&print("{}: {}".format(self._level, message))&log_info = Log("info")log_warning = Log("warning")log_error = Log("error")
相同的功能也可以使用闭包来实现,如下所示:
def make_log(level):
def _(message):
print("{}: {}".format(level, message))
log_info = make_log("info")
log_warning = make_log("warning")
log_error = make_log("error")
def make_log(level):&&&&def _(message):&&&&&&&&print("{}: {}".format(level, message))&&&&return _&log_info = make_log("info")log_warning = make_log("warning")log_error = make_log("error")
可以看出,即使两个版本都实现了相同的功能,但基于闭包的版本更简洁、可读性更好。闭包在一个主要的Python函数“函数修饰符”中也扮演着很重要的角色,这是使用非常广泛的功能,我们将在接下来的教程讲解。
如果文中你发现了任何错误、问题或者你有更好的话题想让我写出来,可以在Twitter上联系我(@obi_inc)。
关于作者:
可能感兴趣的话题
关于闭包,结论片面,http://blog.csdn.net/marty_fu/article/details/7679297/正解。
关于 Python 频道
Python频道分享 Python 开发技术、相关的行业动态。
新浪微博:
推荐微信号
(加好友请注明来意)
– 好的话题、有启发的回复、值得信赖的圈子
– 分享和发现有价值的内容与观点
– 为IT单身男女服务的征婚传播平台
– 优秀的工具资源导航
– 翻译传播优秀的外文文章
– 国内外的精选文章
– UI,网页,交互和用户体验
– 专注iOS技术分享
– 专注Android技术分享
– JavaScript, HTML5, CSS
– 专注Java技术分享
– 专注Python技术分享
& 2018 伯乐在线

我要回帖

更多关于 simulink传递函数模块 的文章

 

随机推荐