一、函數(shù)定義
函數(shù)是組織好的,可重復(fù)使用的,用來實(shí)現(xiàn)單一,或相關(guān)聯(lián)功能的代碼段;比如常用的print(),就是內(nèi)建函數(shù);通俗來講,函數(shù)就是把代碼打包成不通形狀的樂高積木,以便可以根據(jù)需求調(diào)用拼裝;當(dāng)然這種函數(shù)叫做自定義函數(shù)。
定義: 函數(shù)是指將一組語句的集合通過一個(gè)名字(函數(shù)名)封裝起來,要想執(zhí)行這個(gè)函數(shù),只需調(diào)用其函數(shù)名即可.
特性: 減少重復(fù)代碼;使程序變的可擴(kuò)展;使程序變得易維護(hù).
- 語法
def 函數(shù)名(參數(shù)列表):
函數(shù)體
- 事例
def hello():
print('Hello World')
#上面是函數(shù)主體,下面是調(diào)用hello這個(gè)函數(shù);
hello()
- 返回值
要想獲取函數(shù)的執(zhí)行結(jié)果,就可以用return語句把結(jié)果返回
注意:
一旦函數(shù)經(jīng)過調(diào)用并開始執(zhí)行,那函數(shù)外部的程序,就無法再控制函數(shù)的執(zhí)行過程,只能等待函數(shù)執(zhí)行結(jié)果;所以return語句代表著函數(shù)的結(jié)束;
如果未在函數(shù)中指定return,那這個(gè)函數(shù)的返回值為None;
def count(numb1, numb2):
numb3 = numb1 * numb2
return numb3
print(count(3, 4))
二、函數(shù)參數(shù)
參數(shù)從調(diào)用的意義上來講,分為形式參數(shù)和實(shí)際參數(shù),簡(jiǎn)稱"形參"和"實(shí)參";形參指的是函數(shù)創(chuàng)建和定義過程中小括號(hào)內(nèi)的參數(shù);實(shí)參是指函數(shù)被調(diào)用的過程中傳遞進(jìn)來的參數(shù);
- 形參:變量只有在被調(diào)用時(shí)才分配內(nèi)存單元,在調(diào)用結(jié)束時(shí),即刻釋放所分配的內(nèi)存單元。因此,形參只在函數(shù)內(nèi)部有效。函數(shù)調(diào)用結(jié)束返回主調(diào)用函數(shù)后則不能再使用該形參變量;
-
實(shí)參:可以是常量、變量、表達(dá)式、函數(shù)等,無論實(shí)參是何種類型的量,在進(jìn)行函數(shù)調(diào)用時(shí),它們都必須有確定的值,以便把這些值傳送給形參。因此應(yīng)預(yù)先用賦值,輸入等辦法使參數(shù)獲得確定值;
形參和實(shí)參 - 普通參數(shù)
普通參數(shù)又位置參數(shù),需要按照形參的順序,進(jìn)行實(shí)參的賦值
def data(name, age):
'''
:param name:
:param age:
:return:
'''
print('姓名:{0}\n年齡:{1}'.format(name, age))
data('lain', 23)
- 關(guān)鍵字參數(shù)
關(guān)鍵字參數(shù)在傳入實(shí)際參數(shù)時(shí)指定形參的變量名,不用考慮具體位置
def data(name, age, pro):
'''
:param name:
:param age:
:param pro:
:return:
'''
print('姓名:' + name + '\n年齡:' + age + '\n職業(yè):' + pro)
data(pro='CA', name='LAIN', age='28') #不用考慮先后順序
- 默認(rèn)參數(shù)
使用默認(rèn)參數(shù)時(shí),可以不帶實(shí)參去調(diào)用函數(shù);默認(rèn)參數(shù)是在參數(shù)定義的過程中,為形參賦值,當(dāng)函數(shù)調(diào)用的時(shí)候不傳遞實(shí)參,則默認(rèn)使用形參的賦值參數(shù)代替
def data(pro='CA', name='LAIN', age='28'):
'''
:param name:
:param age:
:param pro:
:return:
'''
print('姓名:' + name + '\n年齡:' + age + '\n職業(yè):' + pro)
data() #實(shí)參不傳參則按照形參賦值的參數(shù)進(jìn)行打??;
data(name='LIMING', age='30', pro='DBA') #實(shí)參傳參則按照實(shí)參傳遞的參數(shù)進(jìn)行打??;
- 收集參數(shù)
一個(gè)函數(shù)能處理比當(dāng)初聲明時(shí)更多的參數(shù)是收集參數(shù)又叫可變參數(shù)或者不定長(zhǎng)參數(shù);聲明時(shí)不會(huì)命名;
命名規(guī)范:*args **kwargs
- 元組形式:加一個(gè)星號(hào)(*)的變量名會(huì)存放所有未命名的變量參數(shù)。如果在函數(shù)調(diào)用時(shí)沒有指定參數(shù),它就是一個(gè)空元組;
def data(name, age, pro, *hobby):
'''
:param name:
:param age:
:param pro:
:return:
'''
print('姓名:' + name + '\n年齡:' + age + '\n職業(yè):' + pro)
print('興趣愛好:', *hobby)
data('LIMING', '30', 'DBA', '足球', '跑步', '爬山')
#上面的事例可以理解為打包,既然可以打包那么肯定可以解包
def data(name, age, pro, *hobby):
'''
:param name:
:param age:
:param pro:
:return:
'''
print('姓名:' + name + '\n年齡:' + age + '\n職業(yè):' + pro)
print('興趣愛好:', *hobby)
a = ['足球', '跑步', '爬山']
data('LIMING', '30', 'DBA', *a)
- 字典形式:加兩個(gè)星號(hào)(**)的變量名會(huì)存放所有未命名的變量參數(shù)。
def data(name, age, pro, *hobby, **mes):
'''
:param name:
:param age:
:param pro:
:return:
'''
print('姓名:' + name + '\n年齡:' + age + '\n職業(yè):' + pro)
print('興趣愛好:', *hobby)
print('其他信息:', mes)
data('LIMING', '30', 'DBA', '足球', '跑步', '爬山', phone='13452123453', studID='20183511')
如果在函數(shù)調(diào)用時(shí)沒有指定參數(shù),它就是一個(gè)空字典;
def data(name, age, pro, *hobby, **mes):
'''
:param name:
:param age:
:param pro:
:return:
'''
print('姓名:' + name + '\n年齡:' + age + '\n職業(yè):' + pro)
print('興趣愛好:', *hobby)
print('其他信息:', mes)
data('LIMING', '30', 'DBA', '足球', '跑步', '爬山')
三、函數(shù)的變量作用域
python中的作用域:局部作用域(L-Local)、閉包函數(shù)外的函數(shù)作用域(E-Enclosing)、全局作用域(G-Global)、內(nèi)建函數(shù)作用域(B-Built-in);
- 變量作用域由內(nèi)到外查找:L —>E—>G—>B
- 函數(shù)外聲明的是全局變量,函數(shù)內(nèi)聲明的是局部變量;
- 全局變量作用域是整個(gè)程序,局部變量作用域是定義該變量的子程序;
- 當(dāng)全局變量與局部變量同名時(shí):在定義局部變量的子程序內(nèi),局部變量起作用;在其它地方全局變量起作用。
- 正常情況下,局部環(huán)境變量無法修改全局變量;
a = 0
def number(arg1, arg2):
'''
:param arg1:
:param arg2:
:return:
'''
a = arg1 + arg2
print('函數(shù)內(nèi)a的值: ',a)
print('函數(shù)內(nèi)a的內(nèi)存地址: ',id(a))
number(1, 2)
print('函數(shù)外a的值: ', a)
print('函數(shù)外a的內(nèi)存地址: ', id(a))
執(zhí)行結(jié)果:
函數(shù)內(nèi)a的值: 3
函數(shù)內(nèi)a的內(nèi)存地址: 492495664
函數(shù)外a的值: 0
函數(shù)外a的內(nèi)存地址: 492495616
- 通過
global修改全局變量
a = 0
def number(arg1, arg2):
'''
:param arg1:
:param arg2:
:return:
'''
global a
a = arg1 + arg2
print('函數(shù)內(nèi)a的值: ',a)
print('函數(shù)內(nèi)a的內(nèi)存地址: ',id(a))
number(1, 2)
print('函數(shù)外a的值: ', a)
print('函數(shù)外a的內(nèi)存地址: ', id(a))
執(zhí)行結(jié)果:
函數(shù)內(nèi)a的值: 3
函數(shù)內(nèi)a的內(nèi)存地址: 492495664
函數(shù)外a的值: 3
函數(shù)外a的內(nèi)存地址: 492495664
- 通過
nonlocal修改閉包函數(shù)外的函數(shù)變量
a = 0
def number():
'''
:param arg1:
:param arg2:
:return:
'''
a = 1
print('number()函數(shù)內(nèi)a的內(nèi)存地址: ', id(a))
def soure():
nonlocal a #修改的是外層函數(shù)a=1的值
a = 2
print('soure()函數(shù)內(nèi)a的內(nèi)存地址: ', id(a))
soure()
print('soure()函數(shù)外a的內(nèi)存地址: ', id(a))
number()
print('函數(shù)外a的內(nèi)存地址: ', id(a))
- lambda表達(dá)式
lambda表達(dá)式語法:冒號(hào)左邊放原函數(shù)的參數(shù),可以有多個(gè)參數(shù),用逗號(hào)隔開即可,冒號(hào)右邊是返回值。
def calc(x,y):
runturn x*y
print(calc(3,4))
用lambda表達(dá)式如下
calc = lambda x,y:x*y
print(calc(3,4))
四、遞歸函數(shù)
在函數(shù)內(nèi)部,可以調(diào)用其他函數(shù)。如果一個(gè)函數(shù)在內(nèi)部調(diào)用自身本身,這個(gè)函數(shù)就是遞歸函數(shù)。
遞歸特性:
- 自己調(diào)用自己;
- 必須有一個(gè)明確的結(jié)束條件;
- 每次進(jìn)入更深一層遞歸時(shí),問題規(guī)模相比上次遞歸都應(yīng)有所減少;
- 遞歸效率不高,遞歸層次過多會(huì)導(dǎo)致棧溢出(在計(jì)算機(jī)中,函數(shù)調(diào)用是通過棧(stack)這種數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)的,每當(dāng)進(jìn)入一個(gè)函數(shù)調(diào)用,棧就會(huì)加一層棧幀,每當(dāng)函數(shù)返回,棧就會(huì)減一層棧幀。由于棧的大小不是無限的,所以,遞歸調(diào)用的次數(shù)過多,會(huì)導(dǎo)致棧溢出);
data = range(0,1000000)
def digui(data,find):
if len(data) > 0:
middle_pos = int(len(data)/2)
if data[middle_pos] == find:
print('find_name:',find)
elif data[middle_pos] < find:
print('\033[31;1m 右邊的值:%s\033[0m',data[middle_pos+1:])
digui(data[middle_pos+1:],find)
else:
print('\033[32;1m 左邊的值:%s\033[0m',data[0:middle_pos])
digui(data[0:middle_pos],find)
else:
print('沒有找到!')
digui(data,451232)
def sum_number(n):
if n <= 0:
return 0
return n+sum_number(n-1)
print(sum_number(100))
五、推導(dǎo)式
- 列表推導(dǎo)式
list = [i*i for i in range(10)] #列表推導(dǎo)式,用中括號(hào)表示
print(list)
list1 = []
for i in range(10):
list1.append(i*i)
print(list1)
其他事例:
list = [i*i for i in range(10) if i%2 == 0]
print(list)
list = [x*y for x in range(1, 10) for y in range(1, 10) if x >= y]
print(list)
- 字典推導(dǎo)式
dic = {i:i*i for i in range(5)} #大括號(hào)內(nèi)冒號(hào)左右分別是key、value組合
print(dic)
- 集合推導(dǎo)式
s = {i for i in 'hello world' if i not in 'w'} #集合與字典推導(dǎo)式的區(qū)別是key、value組合
print(s)
- 元組推導(dǎo)式
tup = tuple(i for i in range(5)) #tuple
print(tup)
****
result = [lambda x:x + i for i in range(5)]
print(result[0](10)) #調(diào)用函數(shù)時(shí)循環(huán)結(jié)束i的值為4,所以結(jié)果為10+4=14
14
result = [lambda x,y=i:x + y for i in range(5)]
print(result[0](10)) #每次循環(huán)將i賦值給y,結(jié)果為0+10=10
print(result[1](10)) #每次循環(huán)將i賦值給y,結(jié)果為1+10=11
六、迭代器
迭代:通過for循環(huán)遍歷對(duì)象每個(gè)元素的過程
我們已經(jīng)知道,可以直接作用于for循環(huán)的數(shù)據(jù)類型有以下幾種:
- 一類是集合數(shù)據(jù)類型,如list、tuple、dict、set、str等;
- 一類是generator,包括生成器和帶yield的generator function;
以上這些統(tǒng)稱為可迭代對(duì)象(Iterable)
可以通過python內(nèi)置的方法Iterable來測(cè)試數(shù)據(jù)類型是否為可迭代對(duì)象
from collections import Iterable
print(isinstance('Hello', Iterable)) #字符串是可迭代對(duì)象
print(isinstance([1, 2, 3], Iterable)) #列表是可迭代對(duì)象
print(isinstance({'a':2, 'b':3}, Iterable)) #字典是可迭代對(duì)象
print(isinstance((1, 2, 3), Iterable)) #元組是可迭代對(duì)象
print(isinstance({1, 2, 3}, Iterable)) #集合是可迭代對(duì)象
print(isinstance(1, Iterable)) #整數(shù)是不可迭代對(duì)象
運(yùn)行結(jié)果:
True
True
True
True
True
False
可以迭代并且可以被next()函數(shù)和iter()調(diào)用,并不斷返回下一個(gè)值的對(duì)象就稱為迭代器(Iterator);迭代器對(duì)象從集合的第一個(gè)元素開始訪問,直到所有的元素被訪問完結(jié)束。迭代器只能往后遍歷不能回溯,不像列表,你隨時(shí)可以取后面的數(shù)據(jù),也可以返回頭取前面的數(shù)據(jù)。
通過Iterator可以測(cè)試上面的可迭代對(duì)象是否為迭代器
from collections import Iterator
print(isinstance('Hello', Iterator)) #字符串不是迭代器
print(isinstance([1, 2, 3], Iterator)) #列表不是迭代器
print(isinstance({'a':2, 'b':3}, Iterator)) #字典不是迭代器
print(isinstance((1, 2, 3), Iterator)) #元組不是迭代器
print(isinstance({1, 2, 3}, Iterator)) #集合不是迭代器
print(isinstance(1, Iterator)) #整數(shù)是不是迭代器
運(yùn)行結(jié)果:
False
False
False
False
False
False
通過iter()函數(shù)創(chuàng)建迭代器
numb = [1, 2, 3, 4, 5] #創(chuàng)建的是列表,通過iter函數(shù)創(chuàng)建就是列表迭代器,如果是集合、字典、字符串那就是集合迭代器、字典迭代器、字符串迭代器;
it = iter(numb)
print(type(it))
運(yùn)行結(jié)果:
<class 'list_iterator'> #列表迭代器
通過next()函數(shù)取值
numb = 'hello'
it = iter(numb)
print(next(it))
print(next(it))
print(next(it))
print(next(it))
print(next(it))
運(yùn)行結(jié)果: #從第一個(gè)元素開始,到遍歷完成結(jié)束;
h
e
l
l
o
- 為什么list、dict、str等數(shù)據(jù)類型不是Iterator?
這是因?yàn)镻ython的Iterator對(duì)象表示的是一個(gè)數(shù)據(jù)流,Iterator對(duì)象可以被next()函數(shù)調(diào)用并不斷返回下一個(gè)數(shù)據(jù),直到?jīng)]有數(shù)據(jù)時(shí)拋出StopIteration錯(cuò)誤。可以把這個(gè)數(shù)據(jù)流看做是一個(gè)有序序列,但我們卻不能提前知道序列的長(zhǎng)度,只能不斷通過next()函數(shù)實(shí)現(xiàn)按需計(jì)算下一個(gè)數(shù)據(jù),所以Iterator的計(jì)算是惰性的,只有在需要返回下一個(gè)數(shù)據(jù)時(shí)它才會(huì)計(jì)算。
Iterator甚至可以表示一個(gè)無限大的數(shù)據(jù)流,例如全體自然數(shù)。而使用list是永遠(yuǎn)不可能存儲(chǔ)全體自然數(shù)的。
七、生成器
通過列表生成式,我們可以直接創(chuàng)建一個(gè)列表。但是,受到內(nèi)存限制,列表容量肯定是有限的。生成器的作用是一邊獲取一邊生成,用多少生成多少;
#推導(dǎo)式生成器
g = (i* i for i in range(4))
print(type(g))
運(yùn)行結(jié)果:
<class 'generator'> #類型為生成器
#通過yield,函數(shù)返回值會(huì)變成生成器
- 斐波那契數(shù)列
def fibonacci(n):
a, b, counter = 0, 1, 0
while True:
if counter > n:
return
yield a
a, b = b, a+b
counter = counter + 1
fib = fibonacci(10)
# print(type(fib))
for i in fib:
print(i, end=',')
運(yùn)行結(jié)果:
<class 'generator'> #print數(shù)據(jù)類型為生成器
0,1,1,2,3,5,8,13,21,34,55, #直接遍歷取出
八、裝飾器
裝飾器定義:裝飾器是函數(shù),只不過該函數(shù)可以具有特殊的含義,裝飾器用來裝飾函數(shù)或類,使用裝飾器可以在函數(shù)執(zhí)行前和執(zhí)行后添加相應(yīng)操作完全符合程序開發(fā)中,開放-封閉原則;不改變?cè)写a功能,不改變?cè)姓{(diào)用方式實(shí)現(xiàn)新功能的擴(kuò)張。
# -*- coding: UTF-8 -*-
# Author: LAIN
# Time: 2018-08-15
#裝飾器
user_status = False
def login(fund):
def inner():
user = 'LAIN'
pwd = '12345'
global user_status
if user_status == False:
username = input('USER:')
passwd = input('PASSWORD:')
if username == user and passwd == pwd:
print('登錄成功')
user_status = True
else:
print('賬號(hào)密碼錯(cuò)誤!')
if user_status == True:
fund()
return inner
def home():
print('-----商城首頁-----')
@login #語法糖,表明這是個(gè)裝飾器
def numerical():
print('-----電子數(shù)碼-----')
@login
def food():
print('-----食品生鮮-----')
@login
def department():
print('-----百貨商品-----')
home()
numerical() #運(yùn)行l(wèi)ogin函數(shù)后調(diào)用
food() #運(yùn)行l(wèi)ogin函數(shù)后調(diào)用
department() #運(yùn)行l(wèi)ogin函數(shù)后調(diào)用
