python函数间通信 python不同程序间通信
如何实现 C/C++ 与 Python 的通信
用C/C++对脚本语言的功能扩展是非常常见的事情,Python也不例外。除了SWIG,市面上还有若干用于Python扩展的工具包,比较知名的还有Boost.Python、SIP等,此外,Cython由于可以直接集成C/C++代码,并方便的生成Python模块,故也可以完成扩展Python的任务。
公司主营业务:网站设计制作、成都网站建设、移动网站开发等业务。帮助企业客户真正实现互联网宣传,提高企业的竞争能力。创新互联是一支青春激扬、勤奋敬业、活力青春激扬、勤奋敬业、活力澎湃、和谐高效的团队。公司秉承以“开放、自由、严谨、自律”为核心的企业文化,感谢他们对我们的高要求,感谢他们从不同领域给我们带来的挑战,让我们激情的团队有机会用头脑与智慧不断的给客户带来惊喜。创新互联推出建宁免费做网站回馈大家。
答主在这里选用SWIG的一个重要原因是,它不仅可以用于Python,也可以用于其他语言。如今SWIG已经支持C/C++的好基友Java,主流脚本语言Python、Perl、Ruby、PHP、JavaScript、tcl、Lua,还有Go、C#,以及R。SWIG是基于配置的,也就是说,原则上一套配置改变不同的编译方法就能适用各种语言(当然,这是理想情况了……)
SWIG的安装方便,有Windows的预编译包,解压即用,绿色健康。主流Linux通常集成swig的包,也可以下载源代码自己编译,SWIG非常小巧,通常安装不会出什么问题。
用SWIG扩展Python,你需要有一个待扩展的C/C++库。这个库有可能是你自己写的,也有可能是某个项目提供的。这里举一个不浮夸的例子:希望在Python中用到SSE4指令集的CRC32指令。
首先打开指令集的文档
可以看到有6个函数。分析6个函数的原型,其参数和返回值都是简单的整数。于是书写SWIG的配置文件(为了简化起见,未包含2个64位函数):
/* File: mymodule.i */
%module mymodule
%{
#include "nmmintrin.h"
%}
int _mm_popcnt_u32(unsigned int v);
unsigned int _mm_crc32_u8 (unsigned int crc, unsigned char v);
unsigned int _mm_crc32_u16(unsigned int crc, unsigned short v);
unsigned int _mm_crc32_u32(unsigned int crc, unsigned int v);
接下来使用SWIG将这个配置文件编译为所谓Python Module Wrapper
swig -python mymodule.i
得到一个 mymodule_wrap.c和一个mymodule.py。把它编译为Python扩展:
Windows:
cl /LD mymodule_wrap.c /o _mymodule.pyd -IC:\Python27\include C:\Python27\libs\python27.lib
Linux:
gcc -fPIC -shared mymodule_wrap.c -o _mymodule.so -I/usr/include/python2.7/ -lpython2.7
注意输出文件名前面要加一个下划线。
现在可以立即在Python下使用这个module了:
import mymodule
mymodule._mm_popcnt_u32(10)
2
回顾这个配置文件分为3个部分:
定义module名称mymodule,通常,module名称要和文件名保持一致。
%{ %} 包裹的部分是C语言的代码,这段代码会原封不动的复制到mymodule_wrap.c
欲导出的函数签名列表。直接从头文件里复制过来即可。
还记得本文第2节的那个great_function吗?有了SWIG,事情就会变得如此简单:
/* great_module.i */
%module great_module
%{
int great_function(int a) {
return a + 1;
}
%}
int great_function(int a);
换句话说,SWIG自动完成了诸如Python类型转换、module初始化、导出代码表生成的诸多工作。
对于C++,SWIG也可以应对。例如以下代码有C++类的定义:
//great_class.h
#ifndef GREAT_CLASS
#define GREAT_CLASS
class Great {
private:
int s;
public:
void setWall (int _s) {s = _s;};
int getWall () {return s;};
};
#endif // GREAT_CLASS
对应的SWIG配置文件
/* great_class.i */
%module great_class
%{
#include "great_class.h"
%}
%include "great_class.h"
这里不再重新敲一遍class的定义了,直接使用SWIG的%include指令
SWIG编译时要加-c++这个选项,生成的扩展名为cxx
swig -c++ -python great_class.i
Windows下编译:
cl /LD great_class_wrap.cxx /o _great_class.pyd -IC:\Python27\include C:\Python27\libs\python27.lib
Linux,使用C++的编译器
g++ -fPIC -shared great_class_wrap.cxx -o _great_class.so -I/usr/include/python2.7/ -lpython2.7
在Python交互模式下测试:
import great_class
c = great_class.Great()
c.setWall(5)
c.getWall()
5
也就是说C++的class会直接映射到Python class
SWIG非常强大,对于Python接口而言,简单类型,甚至指针,都无需人工干涉即可自动转换,而复杂类型,尤其是自定义类型,SWIG提供了typemap供转换。而一旦使用了typemap,配置文件将不再在各个语言当中通用。
参考资料:
SWIG的官方文档,质量比较高。SWIG Users Manual
有个对应的中文版官网,很多年没有更新了。
写在最后:
由于CPython自身的结构设计合理,使得Python的C/C++扩展非常容易。如果打算快速完成任务,Cython(C/C++调用Python)和SWIG(Python调用C/C++)是很不错的选择。但是,一旦涉及到比较复杂的转换任务,无论是继续使用Cython还是SWIG,仍然需要学习Python源代码。
本文使用的开发环境:
Python 2.7.10
Cython 0.22
SWIG 3.0.6
Windows 10 x64 RTM
CentOS 7.1 AMD 64
Mac OSX 10.10.4
Python 的函数是怎么传递参数的
Python 的函数传递参数:
Python 传参数可以理解为 C 的 const 指针(your_type* const your_variable),它所指向的对象可以被修改产生副作用,但变量本身不能修改指向其他对象。这个和 C++ 的 reference 差不多。
所以如果一定要产生 C 的修改指针指向其他对象的效果,用 list、dict 或其他自定义的 mutable 对象包装是一个办法,但我认为这样是一种不良实践。在 C 语言中用参数输出结果有非常多的理由:
C 语言没有 tuple,不能返回多值,除非声明一个 struct 类型。这种情况下划分 in 参数和 out 参数成为一种惯例
C 语言没有异常机制,返回值一般要保留给 errno
但这些情况在 Python 中都是不存在的
python线程间通信的问题,回答有加分!300
pyqt的线程之间的通信是通过信号to槽来实现的,首先你在线程类里面声明一个全局槽比如:
class imThread(QtCore.QThread):
imslot = QtCore.pyqtSignal()
这里是要重点注意,上面的是没有任何参数的一个信号,如果你需要参数的话,你可以在里面添加参数类型,例如:
imslot1 = QtCore.pyqtSignal(str) #这是一个带字符串参数的信号
imslot2 = QtCore.pyqtSignal(int) #这是一个带整型参数的信号
imslot3 = QtCore.pyqtSignal(bool) #这是一个带布尔参数的信号
当然了,如果你需要多个参数的话,同样地往里面加就是了,qt也没有要求参数必须是同类型的,所以可以这样:
imslot1 = QtCore.pyqtSignal(str, int) #这是一个带整型和字符串的参数信号
imslot2 = QtCore.pyqtSignal(int, str, str) #这是一个带整型和两个字符串的参数信号
imslot3 = QtCore.pyqtSignal(bool, str) #这是一个带布尔和字符串的参数信号
在线程的run方法里面来定义执行信号:
self.imslot.emit()
这里也是需要重点注意的是,上面这个接口是没有参数的,如果你是要参数的话,是需要这样写:
self.imslot1[str].emit('hello')
self.imslot2[int].emit(1)
self.imslot3[bool].emit(False)
多参数的是这样
self.imslot1[str, int].emit('hello', 1)
self.imslot2[int, str, str].emit(1, "hello", "world")
self.imslot3[bool, str].emit(False, 'hello')
以上就是在线程类里面完成信号定义了,接下来就是逻辑层成定义一个函数槽来连接线程类里面的信号,这个也很简单,比如我在主线程类里面定义一个方法:
def imSlot():
print 'ok'
以上这个是槽函数,接下来是实现信号槽的连接
imThread.imslot.connect('imSlot')
这个就是信号槽的连接方式,当然了,这个是没有参数的一个信号槽,那么带参数的怎么写呢?也很简单!首先定义一个槽函数:
def imSlot(para):
print para
这个是带参数的槽函数,下面是:
imThread.imslot[str].connect('imSlot')
以上就是线程之间的方法了,子线程在执行的通行经过执行信号的话,子线程可以安全地执行而不会出现GUI主线程卡死的情况了。
python怎么向类中的函数传递参数
Python中函数参数的传递是通过“赋值”来传递的。但这条规则只回答了函数参数传递的“战略问题”,并没有回答“战术问题”,也就说没有回答怎么赋值的问题。函数参数的使用可以分为两个方面,一是函数参数如何定义,二是函数在调用时的参数如何解析的。而后者又是由前者决定的。函数参数的定义有四种形式:
1. F(arg1,arg2,...)
2. F(arg2=value,arg3=value...)
3. F(*arg1)
4. F(**arg1)
第1 种方式是最“传统”的方式:一个函数可以定义不限个数参数,参数(形式参数)放在跟在函数名后面的小括号中,各个参数之间以逗号隔开。用这种方式定义的函数在调用的时候也必须在函数名后的小括号中提供相等个数的值(实际参数),不能多也不能少,而且顺序还必须相同。也就是说形参和实参的个数必须一致,而且想给形参1的值必须是实参中的第一位,形参与实参之间是一一对应的关系,即“形参1=实参1 形参2=实参2...”。很明显这是一种非常不灵活的形式。比如:"def addOn(x,y): return x + y",这里定义的函数addOn,可以用addOn(1,2)的形式调用,意味着形参x将取值1,主将取值2。addOn(1,2,3)和addOn (1)都是错误的形式。
第2种方式比第1种方式,在定义的时候已经给各个形参定义了默认值。因此,在调用这种函数时,如果没有给对应的形式参数传递实参,那么这个形参就将使用默认值。比如:“def addOn(x=3,y=5): return x + y”,那么addOn(6,5)的调用形式表示形参x取值6,y取值5。此外,addOn(7)这个形式也是可以的,表示形参x取值7,y取默认值5。这时候会出现一个问题,如果想让x取默认值,用实参给y赋值怎么办?前面两种调用形式明显就不行了,这时就要用到Python中函数调用方法的另一大绝招 ──关健字赋值法。可以用addOn(y=6),这时表示x取默认值3,而y取值6。这种方式通过指定形式参数可以实现可以对形式参数进行“精确攻击”,一个副带的功能是可以不必遵守形式参数的前后顺序,比如:addOn(y=4,x=6),这也是可以的。这种通过形式参数进行定点赋值的方式对于用第1种方式定义的函数也是适用的。
上面两种方式定义的形式参数的个数都是固定的,比如定义函数的时候如果定义了5个形参,那么在调用的时候最多也只能给它传递5个实参。但是在实际编程中并不能总是确定一个函数会有多少个参数。第3种方式就是用来应对这种情况的。它以一个*加上形参名的方式表示,这个函数实际参数是不一定的,可以是零个,也可以是N个。不管是多少个,在函数内部都被存放在以形参名为标识符的tuple中。比如:
对这个函数的调用addOn() addOn(2) addOn(3,4,5,6)等等都是可以的。
与第3种方式类似,形参名前面加了两个*表示,参数在函数内部将被存放在以形式名为标识符的dictionary中。这时候调用函数必须采用key1=value1、key2=value2...的形式。比如:
1. def addOn(**arg):
2. sum = 0
3. if len(arg) == 0: return 0
4. else:
5. for x in arg.itervalues():
6. sum += x
7. return sum
那么对这个函数的调用可以用addOn()或诸如addOn(x=4,y=5,k=6)等的方式调用。
上面说了四种函数形式定义的方式以及他们的调用方式,是分开说的,其实这四种方式可以组合在一起形成复杂多样的形参定义形式。在定义或调用这种函数时,要遵循以下规则:
1. arg=value必须在arg后
2. *arg必须在arg=value后
3. **arg必须在*arg后
在函数调用过程中,形参赋值的过程是这样的:
首先按顺序把“arg”这种形式的实参给对应的形参
第二,把“arg=value”这种形式的实参赋值给形式
第三,把多出来的“arg”这种形式的实参组成一个tuple给带一个星号的形参
第四,把多出来的“key=value”这种形式的实参转为一个dictionary给带两个星号的形参。
例子:
1. def test(x,y=5,*a,**b):
2. print x,y,a,b
就这么一个简单函数,来看看下面对这个函数调用会产生什么结果:
test(1) === 1 5 () {}
test(1,2) === 1 2 () {}
test(1,2,3) === 1 2 (3,) {}
test(1,2,3,4) === 1 2 (3,4)
test(x=1) === 1 5 () {}
test(x=1,y=1) === 1 1 () {}
test(x=1,y=1,a=1) === 1 1 () {'a':1}
test(x=1,y=1,a=1,b=1) === 1 1 () {'a':1,'b':1}
test(1,y=1) === 1 1 () {}
test(1,2,y=1) === 出错,说y给赋了多个值
test(1,2,3,4,a=1) === 1 2 (3,4) {'a':1}
test(1,2,3,4,k=1,t=2,o=3) === 1 2 (3,4) {'k':1,'t':2,'o':3}
python中两个函数间参数传递问题
def plus(a,b):
z = a + 1
c = b + 5
return (z,c)
(q,w) = plus(1,2)
plud(q,w)
##我这里假设a=1,b=2
##首先plus(1,2),得到z=2,c=7,通过return 让(q,w)=(z,c)的值,然后plud(q,w)即可实现将z,c的值传递给下一个函数
Python 的函数是怎么传递参数的?
首先你要明白,Python的函数传递方式是赋值,而赋值是通过建立变量与对象的关联实现的。
对于你的代码:
执行 d = 2时,你在__main__里创建了d,并让它指向2这个整型对象。
执行函数add(d)过程中:
d被传递给add()函数后,在函数内部,num也指向了__main__中的2
但执行num = num + 10之后,新建了对象12,并让num指向了这个新对象——12。
如果你明白函数中的局部变量与__main__中变量的区别,那么很显然,在__main__中,d仍在指着2这个对象,它没有改变。因此,你打印d时得到了2。
如果你想让输出为12,最简洁的办法是:
在函数add()里增加return num
调用函数时使用d = add(d)
代码如下:
def add(num):
num += 10
return num
d = 2
d = add(d)
print d
标题名称:python函数间通信 python不同程序间通信
链接地址:http://scyanting.com/article/dooicog.html