扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
Python函数参数传递机制问题在本质上是调用函数(过程)和被调用函数(过程)在调用发生时进行通信的方法问题。基本的参数传递
成都创新互联专业为企业提供新抚网站建设、新抚做网站、新抚网站设计、新抚网站制作等企业网站建设、网页设计与制作、新抚企业网站模板建站服务,10多年新抚做网站经验,不只是建网站,更提供有价值的思路和整体网络服务。
机制有两种:值传递和引用传递。值传递(passl-by-value)过程中,被调函数的形式参数作为被调函数的局部变量处理,即在堆栈中开
辟了内存空间以存放由主调函数放进来的实参的值,从而成为了实参的一个副本。值传递的特点是被调函数对形式参数的任何操作都是作
为局部变量进行,不会影响主调函数的实参变量的值。(推荐学习:Python视频教程)
引用传递(pass-by-reference)过程中,被调函数的形式参数虽然也作为局部变量在堆栈中开辟了内存空间,但是这时存放的是由主调函
数放进来的实参变量的地址。被调函数对形参的任何操作都被处理成间接寻址,即通过堆栈中存放的地址访问主调函数中的实参变量。正
因为如此,被调函数对形参做的任何操作都影响了主调函数中的实参变量。
//test1.c# include stdio.h# include stdlib.hstruct Student
{ char name[30]; float fScore[3];
};void Display(struct Student su){ printf("-----Information------\n"); printf("Name:%s",su.name); printf("Chinese:%.2f\n",su.fScore[0]); printf("Math:%.2f\n",su.fScore[1]); printf("English:%.2f",su.fScore[2]); printf("平均分数为:%.2f\n",(su.fScore[0]+su.fScore[1],su.fScore[2])/3);
}
#先上代码再解释
static PyObject *keywdarg_parrot(PyObject *self, PyObject *args, PyObject *keywds)
{
int voltage;
char *state = "a stiff";
char *action = "voom";
char *type = "Norwegian Blue";
static char *kwlist[] = {"voltage", "state", "action", "type", NULL};
if (!PyArg_ParseTupleAndKeywords(args, keywds, "i|sss", kwlist,
voltage, state, action, type))
return NULL;
printf("-- This parrot wouldn't %s if you put %i Volts through it.\n",
action, voltage);
printf("-- Lovely plumage, the %s -- It's %s!\n", type, state);
Py_INCREF(Py_None);
return Py_None;
}
static PyMethodDef keywdarg_methods[] = {
/* The cast of the function is necessary since PyCFunction values
* only take two PyObject* parameters, and keywdarg_parrot() takes
* three.
*/
{"parrot", (PyCFunction)keywdarg_parrot, METH_VARARGS | METH_KEYWORDS,
"Print a lovely skit to standard output."},
{NULL, NULL, 0, NULL} /* sentinel */
};
PyObject * initkeywdarg(void)
{
/* Create the module and add the functions */
return Py_InitModule("keywdarg", keywdarg_methods);
}
这是一个函数(keywdarg_parrot)即使用了元组参数,也使用了字典参数的例子。例子出自Python2.7.2的文档。具体在:
Python v2.7.2 documentation #187;Extending and Embedding the Python
Interpreter
这个页面下。文档里面有一些关于C/C++与Python交互的介绍和例子,还是比较详细的。传递字典参量要注意,
{"parrot", (PyCFunction)keywdarg_parrot, METH_VARARGS | METH_KEYWORDS,
"Print a lovely skit to standard output."},
这里的METH_VARARGS | METH_KEYWORDS,与普通的不同。解析用:
PyArg_ParseTupleAndKeywords(args, keywds, "i|sss", kwlist,
voltage, state, action, type)
其中的四个变量要提前声明好,这里分别是int,str,str,str类型的。int对应的是args接受到的值。string的都是keywds里面的,它们都是有初始值的。kwlist是变量的名字,就是在python里调用的时候使用的keyword名称。照着例子的模式可以改成其它的,能用的。具体是怎么工作的,其实我也太明白。
Python代码是这样的调用的时候:
print keywdarg.parrot(10,"LHJ",'HKJ','ER')
print keywdarg.parrot(10,"LHJ",'HKJ')
print keywdarg.parrot(10,"LHJ",type='KJ')
输出分别是:
-- This parrot wouldn't HKJ if you put 10 Volts through it.
-- Lovely plumage, the ER -- It's LHJ!
None
-- This parrot wouldn't HKJ if you put 10 Volts through it.
-- Lovely plumage, the Norwegian Blue -- It's LHJ!
None
-- This parrot wouldn't voom if you put 10 Volts through it.
-- Lovely plumage, the KJ -- It's LHJ!
None
第二次调用省略掉了变量,也能正常执行。第三次调用,变量type本来是第四位的,现在变成了keyword并写在了第三位,是python代码里调用的常见形式:keyword不讲顺序,省略掉的keyword使用了默认值。
就这些了,其它的你再看一下Python的文档吧。
python的函数参数传递是"引用传递(地址传递)"。
python中赋值语句的过程(x = 1):先申请一段内存分配给一个整型对象来存储数据1,然后让变量x去指向这个对象,实际上就是指向这段内存(这里有点和C语言中的指针类似)。
在Python中,会为每个层次生成一个符号表,里层能调用外层中的变量,而外层不能调用里层中的变量,并且当外层和里层有同名变量时,外层变量会被里层变量屏蔽掉。函数 调用 会为函数局部变量生成一个新的符号表。
局部变量:作用于该函数内部,一旦函数执行完成,该变量就被回收。
全局变量:它是在函数外部定义的,作用域是整个文件。全局变量可以直接在函数里面应用,但是如果要在函数内部改变全局变量,必须使用global关键字进行声明。
注意 :默认值在函数 定义 作用域被解析
在定义函数时,就已经执行力它的局部变量
python中不可变类型是共享内存地址的:把相同的两个不可变类型数据赋给两个不同变量a,b,a,b在内存中的地址是一样的。
Python是解释性语言, 底层就是用c实现的, 所以用python调用C是很容易的, 下面就总结一下各种调用的方法, 给出例子, 所有例子都在ubuntu9.10, python2.6下试过
1. Python 调用 C (base)
想在python中调用c函数, 如这儿的fact
#include Python.h
int fact(int n)
{
if (n = 1)
return 1;
else
return n * fact(n - 1);
}
PyObject* wrap_fact(PyObject* self, PyObject* args)
{
int n, result;
if (! PyArg_ParseTuple(args, "i:fact", n))
return NULL;
result = fact(n);
return Py_BuildValue("i", result);
}
static PyMethodDef exampleMethods[] =
{
{"fact", wrap_fact, METH_VARARGS, "Caculate N!"},
{NULL, NULL}
};
void initexample()
{
PyObject* m;
m = Py_InitModule("example", exampleMethods);
}
把这段代码存为wrapper.c, 编成so库,
gcc -fPIC wrapper.c -o example.so -shared -I/usr/include/python2.6 -I/usr/lib/python2.6/config
然后在有此so库的目录, 进入python, 可以如下使用
import example
example.fact(4)
2. Python 调用 C++ (base)
在python中调用C++类成员函数, 如下调用TestFact类中的fact函数,
#include Python.h
class TestFact{
public:
TestFact(){};
~TestFact(){};
int fact(int n);
};
int TestFact::fact(int n)
{
if (n = 1)
return 1;
else
return n * (n - 1);
}
int fact(int n)
{
TestFact t;
return t.fact(n);
}
PyObject* wrap_fact(PyObject* self, PyObject* args)
{
int n, result;
if (! PyArg_ParseTuple(args, "i:fact", n))
return NULL;
result = fact(n);
return Py_BuildValue("i", result);
}
static PyMethodDef exampleMethods[] =
{
{"fact", wrap_fact, METH_VARARGS, "Caculate N!"},
{NULL, NULL}
};
extern "C" //不加会导致找不到initexample
void initexample()
{
PyObject* m;
m = Py_InitModule("example", exampleMethods);
}
把这段代码存为wrapper.cpp, 编成so库,
g++ -fPIC wrapper.cpp -o example.so -shared -I/usr/include/python2.6 -I/usr/lib/python2.6/config
然后在有此so库的目录, 进入python, 可以如下使用
import example
example.fact(4)
3. Python 调用 C++ (Boost.Python)
Boost库是非常强大的库, 其中的python库可以用来封装c++被python调用, 功能比较强大, 不但可以封装函数还能封装类, 类成员.
首先在ubuntu下安装boost.python, apt-get install libboost-python-dev
#include boost/python.hpp
char const* greet()
{
return "hello, world";
}
BOOST_PYTHON_MODULE(hello)
{
using namespace boost::python;
def("greet", greet);
}
把代码存为hello.cpp, 编译成so库
g++ hello.cpp -o hello.so -shared -I/usr/include/python2.5 -I/usr/lib/python2.5/config -lboost_python-gcc42-mt-1_34_1
此处python路径设为你的python路径, 并且必须加-lboost_python-gcc42-mt-1_34_1, 这个库名不一定是这个, 去/user/lib查
然后在有此so库的目录, 进入python, 可以如下使用
import hello
hello.greet()
'hello, world'
4. python 调用 c++ (ctypes)
ctypes is an advanced ffi (Foreign Function Interface) package for Python 2.3 and higher. In Python 2.5 it is already included.
ctypes allows to call functions in dlls/shared libraries and has extensive facilities to create, access and manipulate simple and complicated C data types in Python - in other words: wrap libraries in pure Python. It is even possible to implement C callback functions in pure Python.
#include Python.h
class TestFact{
public:
TestFact(){};
~TestFact(){};
int fact(int n);
};
int TestFact::fact(int n)
{
if (n = 1)
return 1;
else
return n * (n - 1);
}
extern "C"
int fact(int n)
{
TestFact t;
return t.fact(n);
}
将代码存为wrapper.cpp不用写python接口封装, 直接编译成so库,
g++ -fPIC wrapper.cpp -o example.so -shared -I/usr/include/python2.6 -I/usr/lib/python2.6/config
进入python, 可以如下使用
import ctypes
pdll = ctypes.CDLL('/home/ubuntu/tmp/example.so')
pdll.fact(4)
12
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流