python基礎之函數

Python函數

函數是python爲了代碼最大程度的重用和最小化代碼冗餘而提供的最基本的程序結構。函數也是一種設計工具,使用函數,我們也可以把複雜的系統分解爲可管理的部件

函數的意義

  • 最大化代碼重用和最小化代碼冗餘
  • 流程的分解

函數的相關語句和表達式

語句 例子
Calls my_function('Fir Arg','Sec Arg')
def def myfunction(fir_arg,sec_arg):
return return fir_arg+sec_arg
global global x;x=new_value
nonlocal nonlocal x;x=new_value
yield def my_sqr(x): for i in range(x): yield i **2
lambda funcs=[lambda x: x*2,lambda x:x3]

編寫函數

def是可執行的代碼。在python裏,只有def執行之後,纔會生成相應的函數。要是def沒有執行,相應的函數就不會生成。def語句在if、while語句甚至是其他def語句裏也是合法的。

  • def創建了一個對象,並將其賦值給一個變量。def語句是生成一個函數對象,並將其賦值給函數名變量
  • lambda創建一個函數對象發送給調用者。因此,也可使用lambda表達式創建函數,這一功能允許我們把函數定義內聯到語法上一條def語句不能工作的地方
  • return將一個結果對象返回給調用者。這個返回值成爲函數調用的結果。
  • yield向調用者返回一個結果對象,但是記住他離開的地方
  • global聲明瞭一個模塊級的變量並被賦值。在默認情況下,所有在函數內被賦值的變量,是在這個函數裏的本地變量,並僅在函數運行過程中存在。爲分配一個可以在整個模塊中都可以使用的變量名,函數需要在global語句中列舉出來。
  • nonlocal聲明瞭將要賦值的一個封閉的函數變量。python3.x裏纔有的語句。函數裏嵌套函數時,都是用相同變量名,只想繼承上一個函數裏的相同變量時可以使用。
  • 函數是通過賦值(對象引用)傳遞的。參數是通過賦值傳遞的。但是在python中賦值就是對象引用。因此當參數被傳遞的對象爲可變對象,當對參數進行變更時,會影響到被傳遞進來的變量
  • 參數、返回值以及變量並不需要聲明。這個與其他變量相同,不需要提前聲明。

def語句

def語句將創建一個函數並將其賦值給一個變量名:
def <變量名>([參數1,參數2,...]):
<語句>
def語句的首行定義函數名,並引用函數對象,函數名的本質就是函數的內存地址。
參數個數是0或以上數目。
語句裏,可以包含return語句,在調用函數時,會返回一個值。當沒有return時,默認返回值爲None。
函數裏,也可以使用yield語句來生成返回值。
因爲def是執行語句,因此函數是實時生成的

>>> def hanshu(x,y):
    return x*y

>>> hanshu('abc',2)
'abcabc'
>>> hanshu(2,[1,2,3])
[1, 2, 3, 1, 2, 3]

在這個函數裏,x*y的結果取決於x和y的對象類型,因爲python本身不定義變量,因此傳遞的值的類型與返回的類型都不一定是固定的類型。

python作用域

作用域針對的是變量。在使用同一個變量名時,會出現作用域問題。

  • 一個def內定義的變量名能夠被def內部使用。不能在函數外部引用這個變量名。
  • def內的變量名與def外的變量名並不衝突。在def內賦值的與def外賦值的相同變量名是不同變量。
    變量名有如下三種不同作用域:
    1. 全局:在def外定義的變量名是全局變量
    2. 本地:在def內部定義的叫做本地變量
    3. 其他:嵌套def時,各自的變量也是獨立的。

本地變量與全局變量

>>> x=10        #全局變量
>>> def funx():
    x=20        #本地變量
    print(x)

>>> print(x)    #打印的是全局變量
10
>>> funx()      #打印的是本地變量
20
>>> x=10
>>> def funx():
    print(x)
    #本地變量沒有定義的話會引用全局的變量
>>> print(x)
10
>>> funx()
10

作用域法則

  • 內嵌的模塊是全局作用域
  • 全局作用域的作用範圍僅限於單個文件
  • 每次的函數的調用都創建了一個新的本地作用域
  • 賦值的變量名除非聲明全局變量或非本地變量,否則均爲本地變量
  • 所有其他的變量名都可以歸納爲本地全局或者內置。

變量名使用時,查找順序:

  • 本地變量名——在本地是否使用此變量名賦值過
  • 上一層結構中def或lambda的本地變量名——上一層是否使用此變量名賦值過
  • 全局變量名——在整個文件裏是否對變量名賦值過
  • 內置變量名——python內部是否存在此變量名
    如果找不到以上變量名則會報錯
>>> def newdef():
    x=20
    def newdef2():
        print(x)
    newdef2()

>>> newdef()
20

>>> x=10
>>> def newdef():
    def newdef2():
        print(x)
    newdef2()

>>> newdef()
10

global語句

在函數內,想改變全局變量,可以使用global語句來定義此變量爲全局變量。

>>> g='global'
>>> l='global'
>>> def glo():
    global g
    g='local'
    l='local'

>>> g
'global'
>>> l
'global'
>>> glo()
>>> g
'local'
>>> l
'global'

在glo函數裏,都重新賦值了g與l,但在函數執行後只有g改變了,當使用global之後,當前函數裏所使用的所有對變量g的更改都會對全局變量g進行更改。
除了這個方法,還有引用自己的方法(交互模式裏,可以import main)與sys.modules的方法(可以使用引用過的所有模塊,交互模式裏本身可用main方式)。

>>> x=10
>>> import __main__
>>> __main__.x
10
>>> def glo():
    __main__.x+=1

>>> glo()
>>> x
11

>>> s=10
>>> import sys
>>> sys.modules['__main__'].s
10
>>> def glo():
    sys.modules['__main__'].s+=1

>>> glo()
>>> s
11

作用域與嵌套函數

被嵌套函數的作用域就是上級函數,在這裏,想調用inner函數,必須是在函數outer裏面,不能直接使用。可以使用返回內部函數的方法來提取內部函數:

>>> def outer():
    def inner():
        print('inner')
    inner()

>>> func1=outer()
inner
工廠函數

工廠函數:根據要求的對象,一個能夠記住嵌套作用域的變量值的函數。

>>> def printx(x):  
    def printy(y):  #嵌套函數
        return x*y  #返回x*y的值
    return printy   #返回嵌套的函數

>>> a=printx(3)    #定義x值爲3後的嵌套函數賦值
>>> a(2)
6
>>> a(3)
9

nonlocal語句

nonlocal讓內部函數中的變量在上一層及以下層函數中生效(父級級父級以下)

x=1
>>> def func1():
    x=2
    def func2():
        nonlocal x
        x=3
        return x
    func2()
    print(x)

>>> func1()
3
>>> x
1

因爲x並不是全局變量,所以只有在調用函數時nonlocal語句纔會生效,這裏x=3,當直接輸出x而不調用函數時那麼x=1

參數

參數簡介

參數:argement或parameter,對象作爲輸入值傳遞給函數的方式。
參數傳遞時的簡要關鍵點:

  • 參數的傳遞是通過自動將對象賦值給本地變量名來實現
  • 在函數內部的參數名的賦值不會影響調用者
  • 改變函數的可變對象參數的值也許會對調用者有影響

傳遞參數爲可變對象與不可變對象時:
不可變對象通過值進行傳遞——數值、字符串等
可變對象是通過指針進行傳遞——列表、字典等

>>> a=3
>>> def printa(a):
    a=a+1
    print(a)

>>> a
3
>>> printa(a)
4
>>> a
3

參數傳遞

在這裏,b[:]方式會新生成一個列表對象,因此函數裏的y與setlist(b[:])是兩個不同的對象。這種方法可以避免可變參數的修改。

>>> def setlist(y):
    y.append(3)

>>> a=[1,2]
>>> setlist(a[:])
>>> a
[1, 2]
>>> setlist(a)
>>> a
[1, 2, 3]

參數傳遞是由特定匹配規則的:

  • 位置:從左到右
  • 關鍵字參數:通過參數名進行匹配
  • 默認參數:爲沒有傳入值得參數定義參數值
  • 可變參數:收集任意多基於位置或關鍵字的參數——參數以* 或**開頭
  • 可變參數解包:傳遞任意多的基於位置或關鍵字的參數——傳遞值以* 或**開頭
  • Keyword-only參數:參數必須按照名稱傳遞

傳遞參數時,要注意順序:非關鍵字參數->關鍵字參數->字典參數

>>> def myfunc(a,b):
    print(a,b)

>>> myfunc(1,2)
1 2
>>> myfunc(b=1,a=2)
2 1

匹配語法

語法 位置
func(value) 調用者 常規參數:通過位置進行匹配
func(name=value) 調用者 關鍵字參數:通過變量名匹配
func(*sequence) 調用者 迭代傳遞所有元素
func(**dict) 調用者 以‘鍵’爲關鍵字,‘值’爲相應值的方式傳遞字典所有元素
def func(name) 函數 常規參數:通過位置或變量名進行匹配
def func(name=value) 函數 默認參數值:如果沒有在調用中傳遞的話
def func(*name) 函數 匹配並收集(在元組中)所有包含位置的參數
def func(**name) 函數 匹配並收集(在字典中)所有包含關鍵字的參數
def func(*arg,name) 函數 參數必須在調用中按照關鍵字傳遞

常規參數函數用法:

>>> def myfunc(a,b):
    result=a+b
    print(result)

>>> myfunc(1,2)
3

關鍵字參數函數:

>>> def myfunc(a,b):
    result=a+b
    print(result)

>>> myfunc(b=1,a=3)
4

迭代傳遞參數用法:

>>> def myfunc(a,b,c):
    result=a+b+c
    print(result)

>>> myfunc(*[1,2,3])
6

在字典中匹配所有參數用法:

>>> def myfunc(a,b,c):
    result=a+b+c
    print(result)

>>> myfunc(**{'a':1,'b':2,'c':3})
6
>>> myfunc(1,**{'b':2,'c':3})
6

默認參數函數用法:

>>> def myfunc(a,b=3):
    print(a+b)
 #當有默認參數存在時,可以只傳入其他的參數
>>> myfunc(3)
6
>>> myfunc(3,2)
5

可變參數函數用法:
可變參數,可以傳遞任意個參數
*args方式是把所有常規參數調用與迭代調用放進一個元組裏:

>>> def myfunc(*a):
    result=''.join(a)
    print (result)

>>> myfunc('1,','2,','3')
1,2,3
>>> myfunc('first,',*['second,','third'])
first,second,third

**args方法是把任意個關鍵字參數與字典調用方式存放在變量名爲args的字典裏

>>> def myfunc(**a):
    print(a)

>>> myfunc(a='1',b='2')
{'a': '1', 'b': '2'}
>>> myfunc(a='1',b='2',**{'c':'3'})
{'a': '1', 'b': '2', 'c': '3'}

必須使用關鍵字傳遞的方法:
函數裏的參數:
常規——有/無默認值
*args——存放在列表
*args——存放在字典
在python3開始,在
args與args中間可以加入一個“必須使用關鍵字傳遞的參數”
使用方法爲是0個或多個常規參數+args+“必須使用關鍵字傳遞的參數”+0個或1個
args。

>>> def myfunc(*,b,**c):
    print(b,c)

>>> myfunc(**{'b':4})
4 {}
>>> def myfun(*a,b,**c):
    print(a,b,c)

>>> myfun(2,**{'b':4,'c':5})
(2,) 4 {'c': 5}

特殊參數的傳遞:
在python裏,函數也是對象,函數名也是變量名,因此函數本身也可以傳遞。
計算最大、最小值的函數時,一般用法:

#這是一個求最小值的函數
>>> def min1(*a):
    reg=a[0]
    for i in a[1:]:
        if i <reg:
            reg=i
    print(reg)

>>> min1(2,3,5,1,6,8)
1
#這裏將最大和最小值的函數作爲參數傳入到求最大和最小值的函數裏
>>> def lessthan(x,y):
    return x<y

>>> def morethan(x,y):
    return x>y

>>> def minmax(test,*args):
    res=args[0]
    for i in args[1:]:
        if test(i,res):
            res=i
    print(res)

>>> minmax(lessthan,2,3,5,1,6)
1
>>> minmax(morethan,2,3,5,1,6)
6

函數的高級用法

遞歸函數

>>> def mysum(s):
    if not s:
        return 0
    else:
        return s[0]+mysum(s[1:])
#或
>>> def mysum(s):
    return 0 if not s else s[0]+mysum(s[1:])

>>> mysum([1,2,3,4])
10

嵌套列表裏面的值相加

>>> li=[1,2,[3,4,5],6,[7,[8,9],10]]
>>> def sumlist(a):
    sum=0
    for i in a:
        if not isinstance(i,list):  #判斷遍歷的i是否是列表
            sum += i
        else:
            sum += sumlist(i)
    return sum

>>> sumlist(li)
55

函數對象:屬性和註解

在python裏函數也是以對象的形態出現。函數名也是以變量名形式存放。因此函數也可以跨模塊,以參數傳遞等形式。函數對象也能調用根本無關的操作:屬性存儲與註釋。
間接函數調用:

>>> def func(x):
    print(x)

>>> func2=func
>>> func2(2)
2

把函數放進列表或元組裏:

>>> def myfunc(func_name,arg1):
    func_name(arg1)

>>> def func_name(arg1):
    print (arg1)

>>> li=[(func_name,1),(func_name,2),(func_name,3)]
>>> for i in li:
    myfunc(i[0],i[1])

1
2
3

匿名函數:lambda

lambda會生成函數對象,但不賦值給任何變量。
lambda表達式:
lambda [&lt;arg1&gt;][,&lt;arg2&gt;][,&lt;arg3&gt;]....:expression using args
參數不是必須的,但沒有參數就沒有相對意義。
lambda簡單說明:
lambda是一個表達式,而不是一個語句,也不是一個的代碼塊。——生成一個對象。

>>> myfunc=lambda a:a*2
>>> myfunc(4)
8
>>> (lambda a,b:a*b)(5,4)
20

當我們把函數對象放進列表裏等操作的時候,使用def感覺很臃腫,這時可以使用lambda來簡化過程。

>>> funclist=[lambda x: x**2,
          lambda x: x**3,
          lambda x: x**4]
>>> funclist[0](2)
4
>>> funclist[1](3)
27

在序列中映射函數:map

使列表中的每個值都加10

>>> l=[1,2,3,4]
>>> list(map(lambda x: x+10,l))
[11, 12, 13, 14]

函數式編程工具:filter

filter與map相似,但是針對返回的bool結果判斷,結果爲真,保留元素;結果爲假,棄用元素。結果也是保存在可迭代對象裏:

>>> list(filter(lambda x: x>1,[-1,0,1,2,3,4,5]))
[2, 3, 4, 5]

函數式編程工具:reduce

reduce函數是在functools模塊裏的,因此我們需要導入這個函數。
這個方法是第一次從可迭代對象裏提取兩個元素當作函數的參數傳入,按前面的函數進行運算,保存返回值,當可迭代對象裏還有元素的時候,之前的返回值爲第一個參數,可迭代對象裏取下一個繼續運算,知道可迭代對象空。最後返回函數的返回值。

>>> from functools import reduce
>>> reduce(lambda x,y: x+y,[1,2,3,4])
10
>>> reduce(lambda x,y:x if x>y else y,[3,5,2,6,7,4,1,9])
9

歡迎各位關注我的微信公衆號“沒有故事的陳師傅”
python基礎之函數

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章