文章目錄
函數
引子
求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 —> 列表/元組
- reduce(function, iterable, [initial])
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]