函數

函數

引子

求1-15的和;

求23-36的和;

求55-68的和;

def sum_of_num(x, y):
    sum1 = 0
    for i in range(x, y + 1):
        sum1 += i
        print(i, end=' ')
    return sum1


print(sum_of_num(1, 15))
print(sum_of_num(23, 36))
print(sum_of_num(55, 68))
#1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 120
#23 24 25 26 27 28 29 30 31 32 33 34 35 36 413
#55 56 57 58 59 60 61 62 63 64 65 66 67 68 861

程序而言:函數就是對程序邏輯進行結構化或者過程化的一種編程方法。

built-in function 內置函數—>BIF

函數的定義

聲明函數的一般形式:

def funtion_name(arg1, arg2, ..., argn):
    '''statements'''
    func_statements
    return Value

說明如下:

1.函數代碼塊以 def 關鍵詞開頭,後接函數標識符名稱和小括號 ()。

2.任何傳入參數和自變量必須放在圓括號中間,圓括號之間可以用於定義參數。

3.函數的第一行語句可以選擇性地使用文檔字符串----用於存放函數說明。

4.函數內容以冒號起始,並且縮進。

5.return [表達式] 結束函數,選擇性的返回一個值給調用方。不帶表達式的return相當於返回 None。

其中參數列表和返回值不是必須的,return後也可以不跟返回值,甚至連 return也沒有。

對於return後沒有返回值的和沒有return語句的函數都會返回None值。

有些函數可能既不需要傳遞參數,也沒有返回值。

沒有參數時,包含參數的圓括號也必須寫上,圓括號後也必須有“:”。

函數調用

使用函數名加參數的方式調用函數

def add_sum(x, y):
    return x + y
print(add_sum(1, 2))
#3

函數文檔說明

函數的第一行語句可以選擇性地使用文檔字符串,使用__doc__方法可以返回該字符串

def sum_add():
    '''add'''
    pass
print(sum_add.__doc__)
#add

函數參數

  • 不傳參函數
  • 參數函數
    • 順序(關鍵字參數需在固定參數之後)

函數返回值

return [表達式] 結束函數,選擇性的返回一個值給調用方。不帶表達式的return相當於返回 None。

函數參數種類

  • 形參

    • 只有在調用時才分配內存單元。調用結束後,立即釋放所分配的內存單元。因此,形參只在函數內部有效,函數調用結束返回主調用函數後則不能再使用該形參變量。
  • 實參

    • 實參是一個確定的值,能夠傳遞給形參。
      • 作爲位置參數或者關鍵字參數傳遞。

位置參數

def usr_manage(name, age, job, hobby):
    print("用戶管理系統".center(16, '-'))
    print("\tName:\t", name)
    print("\tAge:\t", age)
    print("\tJob:\t", job)
    print("\tHobbt:\t", hobby)


usr_manage("tom", 20, "IT", "Coding")
usr_manage("Jim", 21, "Student", "Reading")
-----用戶管理系統-----
	Name:	 tom
	Age:	 20
	Job:	 IT
	Hobbt:	 Coding
-----用戶管理系統-----
	Name:	 Jim
	Age:	 21
	Job:	 Student
	Hobbt:	 Reading

只傳遞實參,位置一一對應—>位置參數

使用位置參數時和函數頭定義的形參在順序,個數以及類型上匹配。

默認值參數

def usr_manage(name, age, job, hobby="game"):
    print("用戶管理系統".center(16, '-'))
    print("\tName:\t", name)
    print("\tAge:\t", age)
    print("\tJob:\t", job)
    print("\tHobbt:\t", hobby)


usr_manage("tom", 20, "IT")
usr_manage("Jim", 21, "Student", "Reading")
-----用戶管理系統-----
	Name:	 tom
	Age:	 20
	Job:	 IT
	Hobbt:	 game
-----用戶管理系統-----
	Name:	 Jim
	Age:	 21
	Job:	 Student
	Hobbt:	 Reading

關鍵字參數

def usr_manage(name, age, job, hobby="game"):
    print("用戶管理系統".center(16, '-'))
    print("\tName:\t", name)
    print("\tAge:\t", age)
    print("\tJob:\t", job)
    print("\tHobt:\t", hobby)


usr_manage("tom", job="IT", 20)
usr_manage("Jim", 21, "Student", "Reading")

默認值參數,關鍵字參數需放在位置參數之後。

不定參數

在Python中不定參數主要是指*args**kwargs兩個魔法變量。

他們倆主要是用於函數定義,我們可以將不定數量的參數傳遞給一個函數。

  • *args用來接收任意非鍵值對的任意數量的參數列表給函數。傳遞一個元組。

  • **kwargs用來接收任意不定長度的鍵值對列表給函數。傳遞一個字典。

def ave(*args):
    sum1 = 0
    for i in args:
        sum1 += i
    return sum1/len(args)
print(ave(1, 5, 11, 21, 23))
print(ave(2, 2, 2, 2, 2, 2))
#12.2
#2.0
def un_para_key(**kwargs):
    print(kwargs)
    print(type(kwargs))
un_para_key(a=1, b=2)
#{'a': 1, 'b': 2}
<class 'dict'>

函數引用

函數被調用前只要被加到到緩存中,就無所謂順序

def foo():
    print("in foo()")
    bar()
def bar():
    print("in bar()")
foo()

函數屬性

函數屬性是Python中另外一個使用了句點屬性標識並擁有命名空間的領域。

你可以獲得每個 pyhon 模塊,類,和函數中任意的名字空間。你可以在模塊 foo 和 bar 裏都有名爲 x 的一個變量,但是在將這兩個模塊導入你的程序後,仍然可以使用這兩個變量。所以,即使在兩個模塊中使用了相同的變量名字,這也是安全的,因爲句點屬性標識對於兩個模塊意味了不同的命名空間,比如說,在這段代碼中沒有名字衝突:print(foo.x + bar.x)

內嵌函數

作用域

bar()整個函數都處於外部foo()函數的作用域裏(foo()是我們可以從外部訪問的一個對象區域)。除了在foo()內部,其他地方無法對bar()進行調用的。

def foo():
    def bar():
        print("bar() called.")
    print("foo() called.")
foo()
bar()
#foo() called.
#bar() called.
Traceback (most recent call last):
  File "D:/python/test1/day06.py", line 152, in <module>
    bar()
NameError: name 'bar' is not defined

變量作用域

作用域的產生

就作用域而言,python和C有很大差別,只有當變量在module,class,函數中定義的時候纔會有作用域的概念。

def foo():
    a = "foo"
    print(a)
foo()
print(a)
foo
Traceback (most recent call last):
  File "D:/python/test1/day06.py", line 157, in <module>
    print(a)
NameError: name 'a' is not defined

在作用域中定義的變量,一般只在作用域內有效。需要注意的是,在if-elif-else,for-else,while-else,try-except(else-finally)等關鍵字的語句塊中不會產生作用域。

if True:
    a = 100
    print(a)
print(a)
#100
#100

作用域的類型

Python中,使用一個變量時並不要求預先聲明。但在真正使用的時候,他必須綁定到某個內存對象。(被定義,賦值)。這種變量名的綁定,將在當前作用域引入我們新的變量,同時屏蔽外層作用域中的同名變量。

  • 局部作用域(locale — L)

    局部變量:包含在def關鍵字定義的語句塊中,即在函數中定義的變量。每當函數被調用時都會創建一個新的局部作用域。Python中也有遞歸,即自己調用自己,每次調用都會創建一個新的局部命名空間。在函數內部的變量聲明,除非特別的聲明爲全局變量,否則均默認爲局部變量。有些情況需要在函數內部定義全局變量,這時可以使用global關鍵字來聲明變量的作用域爲全局。局部變量域就像一個棧,僅僅是暫時的存在,依賴創建該局部作用域的函數是否處於活動的狀態。所以,一般建議儘量少定義全局變量,因爲全局變量在模塊文件運行的過程中會一直存在,佔用內存空間。
    注意:如果需要在函數內部對全局變量賦值,需要在函數內部通過global語句聲明該變量爲全局變量。

  • 嵌套作用域(enclosing — E)

    • E也包含在def關鍵字中,E和L是相對的,E相對於跟上層的函數而言也是L。與L的區別在於,對於一個函數而言,L是定義在此函數內部的局部作用域。
    • 主要爲了實現Python的閉包,而增加的實現。
  • 全局作用域(global — G)

    即在模塊層次中定義的變量。模塊頂層聲明的變量具有全局作用域。從外部來看,模塊的全局變量就是一個模塊對象的屬性。

  • 內置作用域(bulit-in — B)

    • 系統固定模塊中定義的變量。

搜索變量名的優先級:局部作用域>嵌套作用域>全局作用域>內置作用域

全局變量和局部變量

gbl_str = "foo"
def foo():
    loc_str = "bar"
    return gbl_str + loc_str
print(foo())
#foobar
print(gbl_str)
#foo
print(loc_str)  # 僅能訪問全局變量,訪問局部變量報錯
Traceback (most recent call last):
  File "D:/python/test1/day06.py", line 168, in <module>
    print(loc_str)
NameError: name 'loc_str' is not defined
a = 6688
def foo():
    # a = 666
    print('foo,a:\t', a)  # 局部變量與全局變量重名,全局變量被屏蔽,局部變量還未被定義,報錯
    a = 888
    print(a)
def bar():
    print('bar,a:\t', a)
foo()
bar()
Traceback (most recent call last):
  File "D:/python/test1/day06.py", line 182, in <module>
    foo()
  File "D:/python/test1/day06.py", line 177, in foo
    print('foo,a:\t', a)
UnboundLocalError: local variable 'a' referenced before assignment

global

可變類型的全局變量

a = 6688
def foo():
    global a  # 聲明爲全局變量
    print("foo(),a:\t", a)
    a = 666
    print("foo(),a:\t", a)
def bar():
    print("bar(),a:\t", a)
foo()
bar()
#foo(),a:	 6688
#foo(),a:	 666
#bar(),a:	 666
a = 6688
def foo():
    a = 666  # 仍爲局部變量
    def inner_foo():
        global a  # 聲明inner_foo()中的a爲全局變量
        print(a)
        a = 888
        print(a)
    inner_foo()
    print(a)
print(a)
foo()
print(a)
#6688
#6688
#888
#666
#888

遞歸

函數不斷調用自身

def fib(n):
    if n == 1 or n ==2:
        return 1
    else:
        return fib(n-2) + fib(n-1)
print(fib(10))
#55

匿名函數(lambda)

python 使用 lambda 來創建匿名函數。

所謂匿名,意即不再使用 def 語句這樣標準的形式定義一個函數。

  • lambda 只是一個表達式,函數體比 def 簡單很多。

  • lambda的主體是一個表達式,而不是一個代碼塊。僅僅能在lambda表達式中封裝有限的邏輯進去。

  • lambda 函數擁有自己的命名空間,且不能訪問自己參數列表之外或全局命名空間裏的參數。

  • 雖然lambda函數看起來只能寫一行,卻不等同於C或C++的內聯函數,後者的目的是調用小函數時不佔用棧內存從而增加運行效率。

  • 格式:

    lambda para1, para2, para3, ..., paraN : expression using paras
    
def add(x, y, z):
    return x + y + z
f = lambda x, y, z: x + y + z
print(add(1, 2, 3))
print(f(1, 2, 3))
#6
#6

高階函數

高階函數:把一個函數名,以實參的形式,傳遞給這個函數的形參,這個函數就成爲高階函數。

def pow_2(x):
    return x**2
def add(a, b, c):
    return c(a) + c(b)
a_value = add(-9, 1, pow_2)
print(a_value)
#82

filter函數

通過函數實現過濾:

li = ['Zhejiang', 'University', 'City', 'College']
s = lambda sr:sr.startswith('C')
e = lambda sr:sr.endswith('ty')
def filter_test_2(para, n):
    ret = []
    for i in para:
        if not n(i):
            ret.append(i)
    return ret
print(filter_test_2(li, s))
print(filter_test_2(li, e))
#['Zhejiang', 'University']
#['Zhejiang', 'College']

filter:

功能:

  • 過濾掉序列中不符合函數條件的元素。當序列中需要保留的元素可以用某些函數描述時,就應該想到filter函數。

調用格式:

  • filter(function, sequence)
    • function —> 可以是自定義的函數,也可以是匿名函數
    • sequence —> 列表、元組、字符串
li = ['Zhejiang', 'University', 'City', 'College']
fl = filter(lambda sr: sr.endswith('ty'), li)
print(list(fl))
#['University', 'City']

map 映射

功能

  • 求一個序列或者多個序列進行函數映射後的值。(用list()強轉)

格式

  • map(function, iterable1, iterable2)
    • function的參數可以不止一個
    • iterable1,iterable2就是傳入的參數
li = [1, 2, 3, 4, 5]
li2 = [3, 4, 5, 6, 7, 8]
res = map(lambda x, y: x*y+2, li, li2)
print(list(res))
#[5, 10, 17, 26, 37]

使用其他方法實現類似功能:

def func_test(oj):
    return oj+1
def func_test2(oj):
    return oj-1
def add_1(a, b):
    for i in range(0, len(b)):
        b[i] = a(b[i])
    return b
print(add_1(func_test, [1, 2, 3, 4]))
print(add_1(func_test2, [1, 2, 3, 4]))

reduce 函數

  • 功能:
    • 對一個序列進行壓縮運算,得到一個值value。
    • python2中,reduce()是內置函數,而現在,python3中,他被移植到一個模塊中,functools。
    • from functools import reduce
  • 格式
    • reduce(function, iterable, [initial])
      • function必須要傳入兩個參數
      • iterable —> 列表/元組
from functools import reduce
k = [2, 3, 4, 5, 6]
z = reduce(lambda x, y: x+y, k,1)
print(z)
#21

apply 函數

功能

  • pandas中,應用對象是pandas中的DataFrame或者Series
  • 直接對DataFrame或者Series應用函數
  • 對pandas中的groupby之後的聚合對象應用apply
import numpy as np
import pandas as pd

a = np.random.randint(low=0, high=4, size=(2, 4))
data = pd.DataFrame(a)
print(data)
print(data.apply(lambda x: x*10))
#   0  1  2  3
#0  3  3  3  1
#1  1  1  2  3
#    0   1   2   3
#0  30  30  30  10
#1  10  10  20  30

zip

功能

  • 將可迭代對象作爲參數,將對象中對應的元素打包成一個個元組,返回由這些元組組成的對象。
  • 長度不一樣的時候,以長度短的爲準

注:

利用*號操作符,與zip相反,進行解壓。

格式:

zip(iterable1, iterable2, …, iterableN)

  • iterable —> 兩個或者多個可迭代序列(字符串,列表,元組,字典)
    • py2,由元組組成的列表
    • py3,返回的是一個對象,如果要得到一個列表,需要list()強轉,也可以通過迭代訪問
a = [1, 2, 3]
b = [4, 5, 6]
c = [4, 5, 6, 7, 8]
ziptest1 = zip(a, b)
print(list(ziptest1))

練習

#寫一個函數,計算傳入字符中的數字,字母,空格以及其他字符的個數
import string
def count_str(*args):
    digit, alpha, block, other = 0, 0, 0, 0
    for i in args:
        if i in string.ascii_letter:
            alpha += 1
        elif str(i) in string.digits:
            digit += 1
        elif i == ' ':
            block += 1
        else:
            other += 1
    print("字母的數量爲:\t", alpha, "\n數字的數量爲:\t", digit, "\n空格的數量爲:\t", block, "\n其他字符的數量爲:\t", other)
count_str(1, '2', '3', 4, 'a', 'b', ' ', '@', "#")
#字母的數量爲:	 2 
#數字的數量爲:	 4 
#空格的數量爲:	 1 
#其他字符的數量爲:	 2

#利用filter函數篩選1-1000的迴文
#方法一:
def palindrome(num1):
    a = str(num1)
    for i in range(0, len(a)):
        if a[i] != a[-i-1]:
            return False
    return True
#方法二:
def palindrome_2(num1):
    return str(num1) == str(num1)[::-1]
#方法三:
palindrome_3 = lambda x:str(x) == str(x)[::-1]
a = filter(palindrome_3, range(1, 1000))
print(list(a))
#[1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 22, 33, 44, 55, 66, 77, 88, 99, 101, 111, 121, 131, 141, 151, 161, 171, 181, 191, 202, 212, 222, 232, 242, 252, 262, 272, 282, 292, 303, 313, 323, 333, 343, 353, 363, 373, 383, 393, 404, 414, 424, 434, 444, 454, 464, 474, 484, 494, 505, 515, 525, 535, 545, 555, 565, 575, 585, 595, 606, 616, 626, 636, 646, 656, 666, 676, 686, 696, 707, 717, 727, 737, 747, 757, 767, 777, 787, 797, 808, 818, 828, 838, 848, 858, 868, 878, 888, 898, 909, 919, 929, 939, 949, 959, 969, 979, 989, 999] 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章