在封裝的代碼間傳遞指針你要確保他們運(yùn)行在相同的地址空間里,還要保證指針指向的內(nèi)存的生存期是安全的,否則這種思路就是錯(cuò)誤的。實(shí)現(xiàn)方法舉例如下:
網(wǎng)站建設(shè)哪家好,找成都創(chuàng)新互聯(lián)!專注于網(wǎng)頁(yè)設(shè)計(jì)、網(wǎng)站建設(shè)、微信開(kāi)發(fā)、小程序開(kāi)發(fā)、集團(tuán)企業(yè)網(wǎng)站建設(shè)等服務(wù)項(xiàng)目。為回饋新老客戶創(chuàng)新互聯(lián)還提供了湘東免費(fèi)建站歡迎大家使用!
1、定義了C 結(jié)構(gòu)體和函數(shù)如下
typedef struct NameAge
{
char name[20];
int age;
}NameAge , *NameAgePointer;
void test(NameAgePointer p) // 接收結(jié)構(gòu)體指針
{
// do something with p...
}
2、python定義結(jié)構(gòu)體如下
#python中結(jié)構(gòu)體定義
class PyStruct():
def __init__(self, name, age):
self.name = name
self.age = age
fred = PyStruct("fred", 5)
3、假設(shè)把第1步里的test封裝成example模塊,python導(dǎo)入example(既然你都會(huì)swig了,這個(gè)過(guò)程就不啰嗦了)
import example
example.test(pointer(fred))
以上是基本思路,因?yàn)榇罱ㄩ_(kāi)發(fā)環(huán)境和過(guò)程比較繁雜,沒(méi)有驗(yàn)證過(guò),但是應(yīng)該沒(méi)有大問(wèn)題
python的函數(shù)參數(shù)傳遞是"引用傳遞(地址傳遞)"。
python中賦值語(yǔ)句的過(guò)程(x = 1):先申請(qǐng)一段內(nèi)存分配給一個(gè)整型對(duì)象來(lái)存儲(chǔ)數(shù)據(jù)1,然后讓變量x去指向這個(gè)對(duì)象,實(shí)際上就是指向這段內(nèi)存(這里有點(diǎn)和C語(yǔ)言中的指針類似)。
在Python中,會(huì)為每個(gè)層次生成一個(gè)符號(hào)表,里層能調(diào)用外層中的變量,而外層不能調(diào)用里層中的變量,并且當(dāng)外層和里層有同名變量時(shí),外層變量會(huì)被里層變量屏蔽掉。函數(shù)? 調(diào)用 ?會(huì)為函數(shù)局部變量生成一個(gè)新的符號(hào)表。
局部變量:作用于該函數(shù)內(nèi)部,一旦函數(shù)執(zhí)行完成,該變量就被回收。
全局變量:它是在函數(shù)外部定義的,作用域是整個(gè)文件。全局變量可以直接在函數(shù)里面應(yīng)用,但是如果要在函數(shù)內(nèi)部改變?nèi)肿兞浚仨毷褂胓lobal關(guān)鍵字進(jìn)行聲明。
注意 :默認(rèn)值在函數(shù)? 定義 ?作用域被解析
在定義函數(shù)時(shí),就已經(jīng)執(zhí)行力它的局部變量
python中不可變類型是共享內(nèi)存地址的:把相同的兩個(gè)不可變類型數(shù)據(jù)賦給兩個(gè)不同變量a,b,a,b在內(nèi)存中的地址是一樣的。
在封裝的代碼間傳遞指針你要確保他們運(yùn)行在相同的地址空間里,還要保證指針指向的內(nèi)存的生存期是安全的,否則這種思路就是錯(cuò)誤的。實(shí)現(xiàn)方法舉例如下:
1、定義了C
結(jié)構(gòu)體和函數(shù)如下
typedef
struct
NameAge
{
char
name[20];
int
age;
}NameAge
,
*NameAgePointer;
void
test(NameAgePointer
p)
//
接收結(jié)構(gòu)體指針
{
//
do
something
with
p...
}
2、python定義結(jié)構(gòu)體如下
#python中結(jié)構(gòu)體定義
class
PyStruct():
def
__init__(self,
name,
age):
self.name
=
name
self.age
=
age
fred
=
PyStruct("fred",
5)
3、假設(shè)把第1步里的test封裝成example模塊,python導(dǎo)入example(既然你都會(huì)swig了,這個(gè)過(guò)程就不啰嗦了)
import
example
example.test(pointer(fred))
以上是基本思路,因?yàn)榇罱ㄩ_(kāi)發(fā)環(huán)境和過(guò)程比較繁雜,沒(méi)有驗(yàn)證過(guò),但是應(yīng)該沒(méi)有大問(wèn)題
如果你用C給Matlab寫過(guò)MEX程序,那么這個(gè)問(wèn)題是很容易理解的(好像每次討論P(yáng)ython問(wèn)題時(shí)我總是把Matlab搬了出來(lái)…… 《在Matlab中把struct當(dāng)成Python中的Dictionary使用》《Matlab和Python的幾種數(shù)據(jù)類型的比較》)。
既然提到了MEX,就簡(jiǎn)單說(shuō)一下:
一個(gè)Matlab可能形如
function ret=add3(a,b,c)
如果在C的層面實(shí)現(xiàn)這個(gè)函數(shù),就會(huì)看到另一種景象:
void mexFunction(int nlhs,mxArray * plhs[],int nrhs,const mxArray * prhs[])
a,b,c三個(gè)參數(shù)的地址放在一個(gè)指針數(shù)組里,然后把這個(gè)指針數(shù)組的首地址作為參數(shù)prhs傳遞給函數(shù),這說(shuō)明Matlab函數(shù)的參數(shù)是傳遞指針的,而不是值傳遞。
縱然是傳遞的指針,但是卻不能在函數(shù)里改變實(shí)參的值,因?yàn)闃?biāo)記為“const”了。
Python是開(kāi)放源碼的,我沒(méi)有看。所以下面很多東西是猜的。
Python在函數(shù)的參數(shù)傳遞時(shí)用的什么手法?實(shí)驗(yàn)一下(使用ActivePython2.5):
首先介紹一個(gè)重要的函數(shù):
help(id)
Help on built-in function id in module __builtin__:
id(...)
id(object) - integer
Return the identity of an object. This is guaranteed to be unique among
simultaneously existing objects. (Hint: it's the object's memory address.)
看最后括號(hào)里那句:Hint:it's the object's address.(它是對(duì)象的地址)
有了這個(gè)函數(shù),下面的事情就方便多了。
a=0
id(a)
3630228
a=1
id(a)
3630216
可以看出,給a賦一次值,a的address就改變了。在C的層面看,(也許真實(shí)情況不是下面的樣子,但作為一個(gè)類比應(yīng)該還是可以的):
void * pa;
pa=malloc(sizeof(int));
*(int *)pa=0;
free(pa);
pa=malloc(sizeof(int));
*(int *)pa=1;
Python中每次賦值會(huì)改變變量的address,分配新的內(nèi)存空間,所以Python中對(duì)于類型不像C那樣嚴(yán)格要求。
下面看看Python函數(shù)參數(shù)傳遞時(shí)到底傳的什么:
有一個(gè)函數(shù):
def changeA(a):
... print id(a)
... a=100
... print id(a)
設(shè)定一個(gè)變量var1:
var1=10
id(var1)
3630108
changeA(var1)
3630108
3631012
var1
10
調(diào)用函數(shù)后,從兩次print的結(jié)果可以看出,傳遞確實(shí)是地址。但是即便如此,在函數(shù)內(nèi)對(duì)形參的修改不會(huì)對(duì)實(shí)參造成任何實(shí)質(zhì)的影響,因?yàn)閷?duì)形參的重新賦值,只是改變了形參所指向的內(nèi)存單元(changeA里兩次調(diào)用print id(a)得到不同的結(jié)果),卻沒(méi)有改變實(shí)參的指向。在C的層面看也許類似下面的情節(jié):
void changeA(void * pa)
{
pa=malloc(sizeof(int));
*(int *)pa=100;
free(pa);
}
精通C的你一眼就看出這個(gè)函數(shù)永遠(yuǎn)也改變不了它外面的世界。
也就是說(shuō)雖然傳遞的是地址,但像changeA這樣的函數(shù)改變不了實(shí)參的值。
也許會(huì)感到困擾?不,我已經(jīng)在Matlab中習(xí)慣了。
一個(gè)最典型的例子就是Matlab中刪除結(jié)構(gòu)體成員的rmfield函數(shù)(參見(jiàn)《Matlab筆記三則》),
(Matlab版本7.0.1)
如果想刪除結(jié)構(gòu)體patient的name成員,用
rmfield(patient, 'name');
是永遠(yuǎn)達(dá)不到目的的(就像試圖用雙手抓住自己的領(lǐng)子,把自己提到空中);
迷途知返的做法是:
patient = rmfield(patient, 'name');