日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

函数、迭代器、生成器、装饰器

發布時間:2025/3/15 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 函数、迭代器、生成器、装饰器 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

函數

函數基礎

一、為什么要使用函數

把重復的代碼提取出來,節省代碼量

?

二、函數分類

內置函數,如len(),sun()

自定義函數

?

三、如何定義函數

def 函數名(參數1,參數2,參數3,...):'''注釋'''函數體return 返回的值

?

四、函數使用的原則:先定義,后使用

?

五、調用函數

1、如何調用函數:函數名加括號

2、函數的返回值

函數的返回值通常都是一個,如果出現 return a,b 這種情況,其實是表示一個元組

?

?六、函數的參數

#1、位置參數:按照從左到右的順序定義的參數

位置形參:必選參數

位置實參:按照位置給形參傳值,順序必須一一對應

?

#2、關鍵字參數:按照key=value的形式定義的實參

無需按照位置為形參傳值

注意的問題:

1. 關鍵字實參必須在位置實參右面

2. 對同一個形參不能重復傳值

?

#3、默認參數:形參在定義時就已經為其賦值

可以傳值也可以不傳值,經常需要變得參數定義成位置形參,變化較小的參數定義成默認參數(形參)

注意的問題:

1. 只在定義時賦值一次

2. 默認參數的定義應該在位置形參右面

3. 默認參數通常應該定義成不可變類型,舉例

def add_end(L=[]):print(id(L))L.append('END')return Lprint(add_end()) print(add_end())

結果:

2822355733768
['END']
2822355733768
['END', 'END']

?

解釋:python函數在定義好時,形參、內部參數等變量就已經有了固定的內存空間(變量始終指向那一塊內存,不會更改)。默認參數形參變量如果是可變的,下一次調用該函數時,默認參數就已經發生了變化。

?

#4、可變長參數: 可變長指的是實參值的個數不固定

而實參有按位置和按關鍵字兩種形式定義,針對這兩種形式的可變長,形參對應有兩種解決方案來完整地存放它們,分別是*args,**kwargs

===========*args===========

def foo(x,y,*args):
  print(x,y)
  print(args)
foo(1,2,3,4,5)

def foo(x,y,*args):
  print(x,y)
  print(args)
foo(1,2,*[3,4,5])

def foo(x,y,z):
  print(x,y,z)
foo(*[1,2,3])

當形參為*args,實參可以用 *()或者 *[] 的方式將若干個參數打包發送給形參

===========**kwargs===========

def foo(x,y,**kwargs):
  print(x,y)
  print(kwargs)
foo(1,y=2,a=1,b=2,c=3)

def foo(x,y,**kwargs):
  print(x,y)
  print(kwargs)
foo(1,y=2,**{'a':1,'b':2,'c':3})

def foo(x,y,z):
  print(x,y,z)
foo(**{'z':1,'x':2,'y':3})

當形參為**kwargs時,實參可以通過**{}的方式將若干參數打包發送給形參

?

===========*args+**kwargs===========

def foo(x,y):
  print(x,y)

def wrapper(*args,**kwargs):
  print('====>')
foo(*args,**kwargs)

?

#5、命名關鍵字參數:*后定義的參數,必須被傳值(有默認值的除外),且必須按照關鍵字實參的形式傳遞,可以保證,傳入的參數中一定包含某些關鍵字

和關鍵字參數**kw不同,命名關鍵字參數需要一個特殊分隔符*,*后面的參數被視為命名關鍵字參數(如果參數中已經有了可變參數*args,則不需要 * 來特別標明)

def foo(x,y,*args,a=1,b,**kwargs):print(x,y)print(args)print(a)print(b)print(kwargs) foo(1,2,3,4,5,b=3,c=4,d=5)
結果:
1 2 (3, 4, 5) 1 3 {'c': 4, 'd': 5}

?

閉包

一、函數是對象

函數可以當做參數傳遞,也可以返回一個函數

利用該特性,可以寫成一個類似C語言switch case語法的功能,取代多分支if

def foo():print('foo')def bar():print('bar')dic={'foo':foo,'bar':bar, } while True:choice=input('>>: ').strip()if choice in dic:dic[choice]()

?

二、函數嵌套、名稱空間、作用域的概念

1、函數嵌套調用

函數嵌套定義

?

2、名稱空間

存放名字的地方,x=1,1存3、放于內存中,那名字x存放在哪里呢?名稱空間是存放名字x與1綁定關系的地方,L = [1,2,3],L存放在名稱空間里,真正的列表在其他地方。

3、作用域?

#1、作用域即范圍

-全局范圍(內置名稱空間與全局名稱空間屬于該范圍):全局存活,全局有效  

-局部范圍(局部名稱空間屬于該范圍):臨時存活,局部有效

內部的函數可以訪問外部的變量,但是外面的函數訪問不了內部函數

?

#2、作用域關系是在函數定義階段就已經固定的,與函數的調用位置無關

?

#3、查看作用域:globals(),locals()

python中globals和nonlocals的用法

?

LEGB 代表名字查找順序: locals -> enclosing function -> globals -> __builtins__

locals 是函數內的名字空間,包括局部變量和形參

enclosing 外部嵌套函數的名字空間(閉包中常見)

globals 全局變量,函數定義所在模塊的名字空間

builtins 內置模塊的名字空間

?

閉包函數

內部函數包含對外部函數而非全局作用域的引用

def counter():n = 0def incr():nonlocal nx = nn += 1return xreturn incrc = counter() print(c()) print(c()) print(c()) print(c.__closure__[0].cell_contents) # 查看閉包的元素

?

結果:

0
1
2
3

?

閉包函數的意義:

返回的函數對象,不僅僅是一個函數,在該函數外還包裹了一個外層作用域(一般含是變量),這使得,該函數無論在何處調用,都優先使用自己外層包裹的作用域,相對于更外層的比如全局作用域。

實現延遲計算的功能:

普通函數調用后立即函數執行,閉包則是給函數包裹上了一層外層作用域,傳了參數的功能。

?

裝飾器

1、裝飾器是閉包函數的一種應用

2、裝飾器可以在不修改原函數功能的前提下,添加額外功能。開放封閉原則

?

#不帶參數的裝飾器

import time def timmer(func):def wrapper(*args,**kwargs):start_time=time.time()res=func(*args,**kwargs)stop_time=time.time()print('run time is %s' %(stop_time-start_time))return resreturn wrapper@timmer #相當于foo = timmer(foo) def foo():time.sleep(3)print('from foo') foo()

#利用閉包的特點:1、具有延遲計算的功能,函數不是立即執行;2、閉包相當于包裹了一個外層作用域的函數。
當timmer函數執行后,形參 func,原函數作為一個對象傳到了形參,傳給了內層函數 wrapper,即使timmer執行完畢了,形參會一直存在著。

?

#帶參數的裝飾器

def auth(driver='file'):def auth2(func):def wrapper(*args,**kwargs):name=input("user: ")pwd=input("pwd: ")if driver == 'file':if name == 'egon' and pwd == '123':print('login successful')res=func(*args,**kwargs) #原函數其實就一個調用,其他都是額外功能,裝飾作用return reselif driver == 'ldap':print('ldap')return wrapperreturn auth2@auth(driver='file') def foo(name):print(name)foo('egon')

?

迭代器

1、為什么要有迭代器:

有序序列,如列表,字符串可以通過索引的方式取出其中的元素,而對于字典,文件,集合等類型,是沒用索引的,所以需要通過不依靠索引的迭代方式,就是迭代器。

2、什么是可迭代對象:

可迭代對象指的是實現了__iter__方法的對象

3、什么是迭代器(對象):

可迭代對象執行obj.__iter__()得到的結果就是迭代器對象,同時,迭代器內部還有__next__方法

文件類型是可迭代器對象 open('a.txt').__iter__() open('a.txt').__next__()

注意:

迭代器對象一定是可迭代對象,而可迭代對象不一定是迭代器對象

?

迭代器對象的使用

dic = {'a':1, 'b':2, 'c':3}

iter_dic = dic.__iter__()? ?#得到一個迭代器

注意:迭代器.__iter__() 得到仍然是迭代器本身

print(iter_dic.__next__()) #等同于next(iter_dic)

print(iter_dic.__next__()) #等同于next(iter_dic)

print(iter_dic.__next__()) #等同于next(iter_dic)

print(iter_dic.__next__()) #拋出異常StopIteration,或者說結束標志

iter_dic=dic.__iter__() while 1:try:k=next(iter_dic)print(dic[k])except StopIteration:break
通過next方法從迭代器取數據,需要手動捕獲異常

?

?

for循環執行next方法,并且自動捕獲異常

dic={'a':1,'b':2,'c':3} for k in dic:print(dic[k])for循環的工作原理 1:執行in后對象的dic.__iter__()方法,得到一個迭代器對象iter_dic 2: 執行next(iter_dic),將得到的值賦值給k,然后執行循環體代碼 3: 重復過程2,直到捕捉到異常StopIteration,結束循環

?

生成器

概念:

只要函數內部包含有yield關鍵字,那么函數名()的到的結果就是生成器,加括號不會執行函數內部的代碼

注意:生成器是一種特殊的迭代器,生成器內置__next__,__iter__方法

?

send方法的使用:

def range2(n):count =0while count < n:print('count',count)count += 1sign = yield countprint('-------sign',sign)return 333new_range = range2(3) n1 = next(new_range)print('do sth else') new_range.send('stop!')

?

?

send與next的區別:

  兩者都可以喚醒生成器,來繼續執行

  send的作用:外界可以發送一個信號給生成器內部,表達式?sign = yield count,?而next是默認發送為None

  

只使用send的情況:

#yield關鍵字的另外一種使用形式:表達式形式的yield def eater(name):print('%s 準備開始吃飯啦' %name)food_list=[]while True:food=yield food_listprint('%s 吃了 %s' % (name,food))food_list.append(food)g=eater('egon') g.send(None) #對于表達式形式的yield,在使用時,第一次必須傳None,g.send(None)等同于next(g) g.send('蒸羊羔') g.send('蒸鹿茸') g.send('蒸熊掌') g.send('燒素鴨') g.close() g.send('燒素鵝') g.send('燒鹿尾')

?

轉載于:https://www.cnblogs.com/liyuexi/p/10702873.html

總結

以上是生活随笔為你收集整理的函数、迭代器、生成器、装饰器的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。