1. 程式人生 > >函數部分總結

函數部分總結

結束 我們 編程 改變 for循環 書寫規則 打印 異常 asd

一、自定義函數

  一、函數概念

    1、什麽是函數:函數就是封裝一個功能。(程序中如果沒有函數的引用,會產生重復代碼多,可讀性差的特點。)

    2、函數的定義:def 關鍵詞開頭,空格之後接函數名稱和圓括號()

l1 = [1,2,3,4]
def my_len():
    # def 關鍵字 定義一個函數
    # my_len 函數名書寫規則與變量一樣
    # def與函數名中間一個空格
    # 函數名():加上冒號
    # 函數體
    count = 0
    for j in l1:
        count += 1
    print(count)
my_len()
l1 = [1,2,3,4]
def my_len():
    count = 0
    for j in l1:
        count += 1
    return count
print(my_len())
# 函數的返回值:
# 寫函數,不要在函數中寫print()
# return
# 1、在函數中,遇到return結束函數。
# 2、將返回值給函數的調用者。
#   無 return = return None
#   return 1個值 該值是什麽,就直接返回給函數的調用者,函數名()
#   return 多個值,將多個值放到一個元組中,返回給函數的調用者。

  二、函數的傳參   

    函數分為形參和實參:

    形參:形式參數,不代表實際的變量。

    實參:實際參數,帶入形參中的變量。

    形參傳參:1、位置傳參。按順序,一一對應。

         2、默認參數。傳參則覆蓋,不傳則默認,默認參數永遠在位置參數的後面。

    形參傳參:1、位置傳參。按順序,一一對應。

         2、關鍵字傳參,不按順序,一一對應。

          3、混合傳參,關鍵字參數永遠在位置參數的後面。

    形參傳遞順序:位置參數,*args,默認參數,**kwargs

def test(a, *args, **kwargs):
    print
(a) # 1 print(args) # (2, 3) print(kwargs) # {‘e‘: 5, ‘d‘: ‘4‘} test(1, 2, 3, d=4, e=5) # 1還是參數a的值,args表示剩余的值,kwargs在args之後表示成對鍵值對。
# * 魔法運用
def func(*args):
    print(args)
l1 = [1,2,30]
l2 = [1,2,33,21,45,66]
tu = (1,2,3)
func(1,2,30,1,2,33,21,45,66)    # (1, 2, 30, 1, 2, 33, 21, 45, 66)
func(*qweqrfdsaf) # (‘q‘, ‘w‘, ‘e‘, ‘q‘, ‘r‘, ‘f‘, ‘d‘, ‘s‘, ‘a‘, ‘f‘)
func(*{name:alex,"age":12}) # (‘name‘, ‘age‘)
func(*l1,*l2)   # (1, 2, 30, 1, 2, 33, 21, 45, 66)
def func(*args):
    print(args)
func(1,2,3,10,20,80)    # (1, 2, 3, 10, 20, 80)
def func(**kwargs):
    print(kwargs)
dic1 = {name1:alex,age1:46}
dic2 = {name:老男孩,age:56}
func(**dic1,**dic2) # {‘age1‘: 46, ‘name1‘: ‘alex‘, ‘name‘: ‘老男孩‘, ‘age‘: 56}
# 在函數的調用執行時,
#   *可叠代對象,代表打散(list,tuple,str,dict(鍵))將元素一一添加到args。
#  **字典,代表打散,將所有鍵值對放到一個kwargs字典裏。

# 在函數定義時, *args,**kwargs代表的是聚合。
def func(*args,**kwargs):
    print(args)
    print(kwargs)
dic1 = {name1:alex,age1:46}
dic2 = {name:老男孩,age:56}
func(*[1,2,3,4],*asdfsad,**dic1,**dic2)
# (1, 2, 3, 4, ‘a‘, ‘s‘, ‘d‘, ‘f‘, ‘s‘, ‘a‘, ‘d‘)
# {‘name‘: ‘老男孩‘, ‘name1‘: ‘alex‘, ‘age‘: 56, ‘age1‘: 46}

  三、函數有用信息

def func1():
    """
    此函數是完成登陸的功能,參數分別是...作用。
    :return: 返回值是登陸成功與否(True,False)
    """
    print(666)
    return True
func1() # 666
print(func1.__name__)   # func1
print(func1.__doc__)    # 顯示註釋內容

二、命名空間和作用域

  一、命名空間

    命名空間的本質:存放名字與值的綁定關系   

    命名空間一共分為三種:

      全局命名空間:代碼在運行伊始,創建的存儲“變量名與值的關系”的空間

      局部命名空間:在函數的運行中開辟的臨時的空間

      內置命名空間:存放了python解釋器

    三種命名空間之間的加載與取值順序:

    加載順序:內置命名空間(程序運行前加載)->全局命名空間(程序運行中:從上到下加載)->局部命名空間(程序運行中:調用時才加載)

    取值:在局部調用:局部命名空間->全局命名空間->內置命名空間

    在全局調用:全局命名空間->內置命名空間

  二、作用域

    作用域就是作用範圍,按照生效範圍可以分為全局作用域和局部作用域。

    全局作用域(globals):包含內置名稱空間、全局名稱空間,在整個文件的任意位置都能被引用、全局有效

    局部作用域(locals):局部名稱空間,只能在局部範圍內生效

    global關鍵字

#global
# 1,在局部空間內,聲明一個全局變量
def func1():
    global name
    name = 老男孩
    print(name) # 老男孩
func1()
print(name) # 老男孩
# 2,在局部空間內改變一個全局變量
a = 4
def func1():
    global a    # 5
    a = 5
func1()
print(a)

    nolocal關鍵字

#nonlocal
# 1,不能修改全局變量。
#在局部作用域中,對父級作用域(或者更外層作用域非全局作用域)的變量進行引用和修改,
# 並且引用的哪層,從那層及以下此變量全部發生改變。
a = 4
def func1():
    b = 6
    def func2():
        b = 666
        print(b) # 666
    func2()
    print(b) # 6
func1()

b = 4
def func1():
    b = 6
    def func2():
        nonlocal b
        b = 666
        print(b) # 666
    func2()
    print(b) # 666
print(b)    # 4
func1()

  三、函數名的應用

# 函數名是函數的名字,本質:變量,特殊的變量。
# 1,單獨打印函數名  <function func1 at 0x0000000000872378>
def func1():
    print(666)
print(func1)  # <function func1 at 0x0000000000872378>
a = 6
print(a)    # 6
# 2、函數名的賦值
def func2():
    print(666)

f = func2
f() # 666
# 3、函數名可以作為容器類數據的元素
def f1():
    print(1211)
def f2():
    print(1222)
def f3():
    print(1233)
def f4():
    print(1233)
l1 = [f1, f2, f3, f4]
for i in l1:
    i()
# 4、函數名可以作為參數
a = 1
def f1(x):
    print(x)    # 1
f1(a)
def f1():
    print(666)
def f2(x):  # x = f1
    x()  # f1()
f2(f1)
# 5、函數名可以作為函數的返回值
def wraaper():
    def inner():
        print(666)
    return inner
ret = wraaper()  # inner
ret()  # inner()

三、閉包和裝飾器

  一、閉包

    閉包:就是內層函數對外層函數(非全局)變量的引用。

    閉包:當函數開始執行時,如果遇到閉包,他又一個機制,他會永遠開辟一個內存空間,將閉包中的額變量等值放入其中,不會隨著函數的執行完畢而消失。

    判斷是不是閉包:內層函數名.__closure__ 結果是:cell...就是閉包

name = 老男孩
def wraaper2(n):
    #  n = ‘老男孩‘
    def inner():
        print(n)    # 老男孩
    inner()
    print(inner.__closure__)    # (<cell at 0x000001E3F9123B28: str object at 0x000001E3F9010F30>,)
wraaper2(name)

  二、裝飾器

    開放封閉原則:

    1、對擴展是開放的

    2、對修改是封閉的

    裝飾器主要功能和裝飾器固定結構:在不改變函數調用方式的基礎上在函數的前、後添加功能。

    裝飾器固定格式

def timer(func):
    def inner(*args,**kwargs):
        ‘‘‘執行函數之前要做的‘‘‘
        re = func(*args,**kwargs)
        ‘‘‘執行函數之後要做的‘‘‘
        return re
    return inner

    帶參數的裝飾器

def outer(flag):
    def timer(func):
        def inner(*args,**kwargs):
            if flag:
                print(‘‘‘執行函數之前要做的‘‘‘)
            re = func(*args,**kwargs)
            if flag:
                print(‘‘‘執行函數之後要做的‘‘‘)
            return re
        return inner
    return timer
@outer(False)

def func():
    print(111)

func()

    多個裝飾器裝飾同一個函數

def wrapper1(func):
    def inner():
        print(wrapper1 ,before func)  # 第二步
        func()
        print(wrapper1 ,after func)   # 第四步
    return inner

def wrapper2(func):
    def inner():
        print(wrapper2 ,before func)  # 第一步
        func()
        print(wrapper2 ,after func)   # 第五步
    return inner

@wrapper2
@wrapper1
def f():
    print(in f)   # 第三步
f()

四、叠代器和生成器

  一、叠代器

    可叠代協議:可以被叠代要滿足的要求,可以將某個數據集內的數據“一個挨著一個的取出來”,就叫做叠代,內部實現了__iter__方法

    叠代協議:必須擁有__iter__方法和__next__方法

    叠代器的好處:

      1、節省內存空間。

      2、滿足惰性機制。

      3、不能反復取值,不可逆。

    可叠代計算過程:

      1、將可叠代對象轉化成叠代器

      2、內部使用__next__方法取值

      3、運用了異常處理去處理報錯。    

l2 = [1, 2, 3, 4, 5, 6, 7, 8]
l2_obj = l2.__iter__()
while True:
    try:
        i = l2_obj.__next__()
        print(i)
    except Exception:
        break

  二、生成器

    生成器:生成器本質上是叠代器。

    初始生成器:常規函數定義,但是,使用yield語句而不是return語句返回結果。yield語句一次返回一個結果,在每個結果中間,掛起函數的狀態,以便下次重它離開的地方繼續執行

    生成器函數定義:

      1、一個包含yield關鍵字的函數就是一個生成器函數

      2、next 和send 功能一樣,都是執行一次,send獲取下一個值可以給上一個yield賦值。

      使用send的註意事項:第一次使用生成器的時候,使用next獲取下一個值,最後一個yield不能接受外部的值

def generator():
    print(123)  # 123
    content = yield 1
    print(content)  # hello
    print(456)  #456
    yield 2
g = generator()
g.__next__()
g.send(hello)

  三、列表推導式和生成器表達式

    1、列表推導式:用列表推導式能夠構建的任何列表,用別的都可以構建,一目了然,占內存。

l2 = [i*i for i in range(1,11)]
print(l2)   # [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

    2、生成器表達式:類似於列表推導,但是,生成器返回按需產生結果的一個對象,而不是一次構建一個結果列表,不易看出,節省內存。

l_obj = (python%s期 % i for i in range(1,12))
print(l_obj)    # <generator object <genexpr> at 0x000001AAF0AEBDB0>
print(l_obj.__next__()) # python1期
print(l_obj.__next__()) # python2期
print(l_obj.__next__()) # python3期

    總結:

      1.把列表解析的[]換成()得到的就是生成器表達式

      2.列表解析與生成器表達式都是一種便利的編程方式,只不過生成器表達式更節省內存

      3.Python不但使用叠代器協議,讓for循環變得更加通用。大部分內置函數,也是使用叠代器協議訪問對象的。例如, sum函數是Python的內置函數,該函數使用叠代器協議訪問對象,而生成器實現了叠代器協議,所以,我們可 以直接這樣計算一系列值的和:

五、內置函數

六、匿名函數

七、遞歸函數

函數部分總結