天天看點

python學習筆記——函數和子產品函數子產品python中的包結構

函數

這麼重要的東西自然少不了。

那麼在python中是怎麼定義的呢?

def cgg(name):
	print("haha %s"%name)
           

def是定義的意思,而cgg是函數名,name是參數。

函數的參數傳遞問題

傳遞方式

我們知道,參數傳遞分為值傳遞和引用傳遞,那麼在python中函數的參數是怎麼傳遞的呢?

在說參數的傳遞方式之前我們需要先說一下可更改(mutable)與不可更改(immutable)對象。

在python中,變量是沒有類型的,隻有對象才有類型,這也就是為什麼我們可以對一個已經複賦10的變量指派一個字元串。

但是對象的确是有類型的,而對象因為類型的關系分為可更改不不可更改。

比如這個例子:

a=10
b=[1,2,3]
a=20
b[0]=4
           

我們先來看a,指派給a的10就是一個不可更改的對象,因為實際上我們再次指派20的時候,我們是建立了一個20的整型對象,而原來的10已經不複存在,是以說它不可更改。

而對于b,是一個清單,我們調用b[0]=4時,它本身依然存在,隻是其中一個元素發生了改變,是以清單是一個可更改對象。

那麼,我們在進行函數參數傳遞時,這兩類對象也是有差别的。

對于不可更改的對象,python會采用值傳遞;而對于可更改的對象,python采用引用傳遞。

我們就不舉例了。

參數類型

python中有四類參數:必備參數、關鍵字參數、預設參數、不定長參數

下面我們依次講解

必備參數

這就是我們正常的函數聲明,比如上面的那個例子cgg函數就需要一個參數name,如果我們調用函數卻不傳遞對應的參數,編譯器會報錯。

關鍵字參數

關鍵字參數和必備參數的差別主要是在調用上,關鍵字參數可以顯式的給出參數的傳遞,是以不需要遵循函數定義時,參數清單裡參數的順序,我們舉個例子:

def cgg(name,age):
    print("My name is %s,and I'm %s years old."%(name,age))
cgg(age="18",name="cgg")
           

在這個例子中,我們可以看出name和age的順序并沒有遵循所給的順序,而是颠倒了一下,但是并不影響程式的運作結果。

預設參數

像我們之前說的一些庫函數一樣,有些函數,如果我們不傳入對應的參數,則會有一個預設值,同樣,我們也可以在定義函數時實作這個功能:

def cgg(name,gender="男"):
    print("我的名字是%s,我的性别是:%s"%(name,gender))
cgg("cgg")
cgg("xhy","女")
           

在cgg聲明的時候,我們可以看到,在性别這個參數,我們設定了一個預設值:男性

也就是說,在沒有填寫這個參數時,就會預設為男性。

不定長參數

有的時候,我們的函數可能不知道對方到底要傳入多少個參數,比如C語言裡的printf就是一個例子。那麼我們就需要一個能接受不定長參數的函數,我們可以如下定義:

def cgg(*b):
    for i in b:
        print(i)
cgg(10)
cgg(10,20,30)
           

輸出結果:10 10 20 30 (換行我就略去了)

也就說,我們可以在一個參數前面加上星号,表示它是一個不定長參數,可以接收多個參數。

同時注意,像下面這個定義是被允許的:

def cgg(a,*b):
    for i in b:
        print(i)
        
cgg(10)
cgg(10,20,30)
           

輸出結果:20 30(換行略去)

此時會把第一個參數給a,剩下的全部由b接收

但是如果我們這麼做,則會有些問題:

def cgg(*b,a):
    for i in b:
        print(i)
        
cgg(10)
cgg(10,20,30)
           

編譯了以後,會報錯,而錯誤的原因不是不能定義a這個參數,而是說我們調用時,漏了一個參數a。

也就是說,如果不做處理,我們的參數将全部給b,而a一個也撈不到。

那麼我們應該怎麼辦呢?

def cgg(*b,a):
    for i in b:
        print(i)
        
cgg(10,a=10)
cgg(10,20,30,a=10)
           

關鍵字參數就可以解決了。

匿名函數

這裡要用到一個新的關鍵字,lambda。

匿名函數,顧名思義,沒有名字的函數,其實與其說它是函數,不如說它是一個表達式。我們來看一個例子:

sum3=lambda a,b,c:a+b+c
print(sum3(10,20,30))
           

答案是60

的确很像一個加了名字的表達式,有點像……宏定義?

但是要注意一點,匿名函數是允許通路其他變量的,即使聲明這個變量時還沒有定義:

sum3=lambda a,b,c:a+b+c+d
d=30
print(sum3(10,20,30))
           

在這個示例中,匿名函數sum3定義時,我們并沒有定義d這個變量,但是隻要我們在調用sum3之前定義了d,這個語句就可以正常執行功能。

傳回值

當然了,有了函數嗎,自然少不了函數的傳回值。那麼這裡用的依然是return。

def cgg(a,b):
	return a+b
           

子產品

簡介

什麼是子產品?

其實我們寫的那些.py檔案,都是子產品。

我們之前用過很多庫函數自帶的子產品,比如time、calendar等等。

這裡我們自己寫一個子產品:

def cgg(data):
	print(data)
def cgg2(data):
	print("other")
	print(data)
           

這段代碼儲存在xhy.py這個子產品裡。

是以我們在寫自己的程式時。可以如下調用:

import xhy
xhy.cgg("cgg")
           

運作結果:cgg

我們接下來舉例會圍繞這個xhy子產品展開。

導入子產品的方式

import

我們在開頭的示例中就是一種直接import的方法,包括我們之前的學習過程中也用這種方法,我就不再舉例了。

from …… import ……

字面意思很好了解,從哪裡導入什麼,也就說并不是整個導入子產品,而是導入其中的某個部分。

比如:

from xhy import cgg
cgg("cgg")
           

不會出任何問題。

但是如果我們這麼寫:

from xhy import cgg
xhy.cgg("cgg")
cgg2("cgg")
           

這兩個語句都是有問題的。

因為我們隻導入了一個函數,是以xhy和cgg2都是未定義的。無法使用

我們還可以在import後加上星号表示導入這個子產品的所有東西:

from xhy import *
cgg("cgg")
cgg2("cgg")
           

這樣是沒有任何問題的。

但是,如果我們這樣寫:

from xhy import *
xhy.cgg("cgg")
           

依然是有問題的,xhy任然未定義。

我們的子產品放在哪

相信大家在建立一個子產品時候都會有一個疑問,我的子產品應該放在哪?

這個顯然是由python會去哪裡尋找子產品決定的。

當我們導入一個子產品時,python會去依次三個地方去找:

  1. 目前目錄
  2. 如果不在目前目錄,python會搜尋shell變量PYTHONPATH下的每個目錄
  3. 如果都找不到,python會選擇搜尋預設路徑、

我們怎麼知道子產品裡有什麼?

打開py看?

未免太麻煩了。

python提供了一個函數dir():

import xhy
dir(xhy)
           

這樣就會顯示子產品裡會有哪些東西啦

當然了,看自己的子產品恐怕沒什麼意思,我們也可以看官方的庫:

import math
dir(math)
           

補充兩個例子:

一個小例子:

import time
print(time.asctime())
           

這個可以顯示現在的時間。

而這個time就是一個子產品,包括之前的turtle也是一個子產品。

我們能再看一個例子:

import sys
print(sys.stdin.readline())
           

這個一看就明白,是輸出輸入的東西

這裡的sys也是一個子產品

TIPS:readline()傳回字元串

locals()和globals()

這兩個函數可以在函數裡調用來檢視可以在目前這個函數裡調用的變量和全局變量。

傳回值均是字典。

reload()

對于import的語句,隻會執行一次,不會因為運作而反複執行。

一般情況下的确沒問題,但是如果,你中途修改了子產品的内容,再執行新添加的内容,你就會發現問題了。

是以我們需要用reload函數來執行重新加載:

這樣就OK了。

python中的包結構

包可以看成一個檔案夾,但并不完全是檔案夾的功能。

比如在python中,包就會由自己特定的結構。

python規定包必須包含一個檔案,那就是__init__.py,它可以是空的,但一定要有,它用來辨別這是一個包。

但是如果裡面有内容,那麼當這個包中有程式運作時,會先調用這個檔案(從名字init也可以看出來了)