關於C語言和Python語言的表示
在學習如何在Python中編寫包和在用C語言編寫包並用Python呼叫的任務時,我發現自己對於函式的一些概念和引數之間的轉換和呼叫不是十分清晰,因此本文主要記錄的是我對於函式的知識在Python和C語言中的表現形式的學習。
1.1 Python中的函式
函式是帶著名字的程式碼塊,用於完成具體的工作。執行函式定義的任務時,只需重複呼叫該函式,就可以完成指定工作。
1.1.1定義一個簡單函式
Python中用關鍵字“def”來表示函式的定義。
def test():
print("hello world!")
1.1.2呼叫該函式
如同C語言中使用函式名即可呼叫,執行結果如下所示。
test()
1.1.3向函式傳遞引數
在上述例子中,假設我們需要輸出的不是“hello world!”,而是“hello Jones!”或者“hello Andy!”呢?這就需要傳遞引數,在函式定義的括號內加入一個變數,在我們呼叫函式時給這個變數指定一個值(Jones或者Andy),就可以輸出不一樣的結果。
def test(name):
print("hello " + name.title() + "!")
test("Jones")
1.1.4實參和形參
在上述的函式定義中,變數“name”是一個形參,它是函式完成其工作所需的一項資訊。而在呼叫函式的“Jones”是一個實參。實參是呼叫函式時傳遞給函式的資訊。簡單來說: 形參是在定義函式的時候給出的 , 實參是在呼叫函式的時候給出的 。
1.1.5位置實參
在呼叫函式時,Python必須將函式呼叫中的每個實參都關聯到函式定義中的一個形參,我將上一個列子稍作改動,在函式定義中加入兩個形參分別為“name”和“home”,在呼叫函式時,讓他指出該人屬於哪個國家。
def test(name,home):
print("hello " + name.title() + ", welcome "+ home.title() + "!")
test("Jones", "China")
test("Andy" , "Japan")
位置實參的順序很重要,務必在程式設計時不能將位置弄反
1.1.6關鍵字實參
關鍵字實參是傳遞給函式的形式為名稱和值。在實參中將名稱和值關聯起來了,因此傳遞引數時順序不會混淆,得到的結果是一樣的。
def test(name,home):
print("hello " + name.title() + ", welcome "+ home.title() + "!")
test(name = "Jones", home = "China")
test(name ="Andy", home = "Japan")
1.1.7返回值
在函式中,可以使用return語句將值返回到呼叫函式的程式碼行,我們修改test函式,使其可以返回該人的姓名和家鄉
def test(name,home):
inf = name + " form " + home
return inf.title()
inf = test(name = "Jones", home = "China")
print(inf)
1.1.8返回字典
函式可返回任何型別的值,包括列表和字典等較為複雜的資料結構。修改上述的函式,讓其可以返回一個人的名字和家鄉。
def test(name,home):
person = {'name':name, 'home':home}
return person
inf = test("Jones", "China")
print(inf)
1.2 Python語言關於包的編寫和編譯
在瞭解包的編寫和編譯之前,要能區分模組和包的概念。
模組:
- 模組就是一組功能的組合;實質上一個模組就是一個包含了python定義和宣告的檔案,檔名就是模組名字加上.py的字尾
- 想要使用模組,必須先要將模組載入進來,可以通過關鍵字 import 或 from進行載入;需要注意的是模組和當前檔案在不同的名稱空間中
- 帶入的模組會重新開闢一塊獨立的名稱空間,定義在這個模組中的函式把這個模組的名稱空間當做全域性名稱空間,這樣的話當前的空間就和模組執行的空間分隔了,誰也不影響誰
包:
- 集合了一些檔案
- 目錄下的第一個檔案是_init__.py
- 匯入包,本質上是匯入了包中的___init__.py檔案
包的結構如下:
|--- Project
|--- main.py
|--- mypackage
|--- __init__.py
|--- module.py
在module.py中輸入如下程式碼,這裡我用的例子和3.1中的例子是一樣的
def test(name,home):
print("hello " + name.title() + ", welcome "+ home.title() + "!")
在main.py中輸入程式碼
import mypackage.module as fun1
fun1.test("Jones", "China")
執行結果如下:從mypackage資料夾中呼叫了module將其命名為fun1,在裡面呼叫了test函式
1.3 C語言中的函式
1.3.1定義一個簡單函式
在C語言中,我們除了要定義主要的main()函式外,還有與之相連的子函式,每個函式只能被定義一次,但一個函式可以根據需要被多次宣告和呼叫。
函式的定義包含一個函式頭和一個函式塊。函式頭指定了函式的名稱、返回值的型別以及引數的型別和名稱(如果有引數的話)。函式塊中的語句明確了該函式要做的事。函式定義的一般格式如下所示:
型別用來定義函式的範圍值型別,可以是void或者任何物件型別,但不能是陣列型別。
名稱就是函式在呼叫時所需輸入的標識。
void test()
{
printf(hello world!);
}
1.3.2形參和實參
形參:在函式定義中出現的引數可以看做是一個佔位符,它沒有資料,只能等到函式被呼叫時接收傳遞進來的資料
實參: 函式被呼叫時給出的引數包含了實實在在的資料,會被函式內部的程式碼使用
形參和實參的區別和聯絡:
- 形參變數只有在函式被呼叫時才會分配記憶體,呼叫結束後,立刻釋放記憶體,所以形參變數只有在函式內部有效,不能在函式外部使用
- 實參可以是常量、變數、表示式、函式等 ,必須有確定的值
- 實參和形參在數量上、型別上、順序上必須嚴格一致
- 只能把實參的值傳遞給形參,而不能把形參的值反向地傳遞給實參
int sum(int m, int n) {
int c;
c = m + n;
return c;
}
int main() {
int a = 1;
int b = 2;
int total;
total = sum(a,b);
printf("total=%d\n", total);
}
在上面這段例子中,m和n是定義的形參,函式調用出的a和b是實參
1.3.3返回值
函式的返回值是指函式被呼叫之後,執行函式體中的程式碼所得到的結果,這個結果通過 return語句返回
他有如下特點:
- 沒有返回值的函式為空型別,用“void”表示
- 一旦函式的返回值型別被定義為 void,就不能再接收它的值了
- return 語句可以有多個,但是每次呼叫函式只能有一個 return 語句被執行,之後的語句都不再執行
1.3.4函式宣告和和函式原型
在編寫程式時,原則上函式定義要出現在函式呼叫之前,但如果在函式定義之前就使用函式的話就需要提前宣告,宣告如下:
dataType functionName( dataType1 param1, dataType2 param2 ... );
函式宣告給出了函式名、返回值型別、引數列表(重點是引數型別)等與該函式有關的資訊,稱為函式原型。函式原型的作用是告訴編譯器與該函式有關的資訊,讓編譯器知道函式的存在,以及存在的形式,即使函式暫時沒有定義,編譯器也知道如何使用它。
int sum(int m, int n)//宣告
int main() {
int a = 1;
int b = 2;
int total;
total = sum(a,b);
printf("total=%d\n", total);
}
int sum(int m, int n) {
int c;
c = m + n;
return c;
}
除了函式,變數也有定義和宣告之分。實際開發過程中,變數定義需要放在原始檔(.c
檔案)中,變數宣告需要放在標頭檔案(.h
檔案)中,在連結程式時會將它們對應起來
1.3.5 區域性變數和全域性變數
-
定義在函式內部的變數稱為區域性變數,它的作用域僅限於函式內部, 離開該函式後就是無效的,再使用就會報錯 。
-
在所有函式外部定義的變數稱為全域性變數,它的作用域預設是整個程式,也就是所有的原始檔,包括
.c
和.h
檔案 -
main函式中定義的變數是區域性變數,可以在不同的函式中使用相同的變數名
1.4 用C語言編寫Python包並呼叫
編寫C語言檔案hello.c
#include <stdio.h>
int test(int b)
{
int a;
a = b +3;
printf("hello world!%d\n",b);
return a;
}
用gcc編譯成dll檔案
編輯Python檔案test.py
from ctypes import *;
h=CDLL('helloc.dll')
c = h.test(1)
print(c)
執行後出現錯誤