day21(python高級編程,property屬性,生成器,迭代器,閉包,裝飾器)

屬性property

私有屬性添加getter和setter方法

對于類對象的私有屬性,我們不能直接調用,可以添加方法來調用。

class Person:

????def __init__(self):

????????pass

????def setAge(self,age):

????????if 0<=age<=100:

????????????self.__age = age

????????else:

????????????self.__age = 16

????????????print('輸入的年齡不符合')

????def getAge(self):

????????return self.__age

p1 = Person()

p1.setAge(10)

print(p1.getAge())

p1.setAge(200)

print(p1.getAge())

結果:

10

輸入的年齡不符合

16

使用property升級getter和setter方法

class Person:

????def __init__(self):

????????pass

????def setAge(self,age):

????????if 0<=age<=100:

????????????self.__age = age

????????else:

????????????self.__age = 16

????????????print('輸入的年齡不符合')

????def getAge(self):

????????return self.__age

????????age = property(getAge,setAge)

p1 = Person()

p1.age = 10

print(p1.age)

p1.age = 200

print(p1.age)

結果:

10

入的年齡不符合

16

使用property取代getter和setter方法

class Person:

????def __init__(self):

????????pass

????@property

????def age(self):

????????return self.__age

????@age.setter

????def age(self,age):

????????if 0<=age<=100:

????????????self.__age = age

????????else:

????????????self.__age = 16

????????????print('輸入的年齡不符合')

p1 = Person()

p1.age = 10

print(p1.age)

p1.age = 200

print(p1.age)

結果:

10

輸入的年齡不符合

16

生成器

通過列表生成式,我們可以直接創建一個列表。但是,受到內存限制,列表容量肯定是有限的。而且,創建一個包含100萬個元素的列表,不僅占用很大的存儲空間,如果我們僅僅需要訪問前面幾個元素,那后面絕大多數元素占用的空間都白白浪費了。所以,如果列表元素可以按照某種算法推算出來,那我們是否可以在循環的過程中不斷推算出后續的元素呢?這樣就不必創建完整的list,從而節省大量的空間。在Python中,這種一邊循環一邊計算的機制,稱為生成器:generator。

創建生成器

1.把列表生成式的[]改成()

如:

[ x*2 for x in range(5)]

改為:

( x*2 for x in range(5))

如果想要打印,可以通過next()獲取生成器的下一個返回值,而且,generator也是可迭代的,所以也可以用循環遍歷。

2.有的比較復雜,用類似列表生成式的for循環無法實現的時候,還可以用函數來實現。

可以用yield

例如:

def fib(num):

????a,b = 0,1

????while num>0:

????????yield b

????????a,b = b,a+b

????????num-=1


f = fib(5)

print(' ',next(f))

print(' ',next(f))

for i in f:

????print(i)

在上面fib 的例子,我們在循環過程中不斷調用 yield ,就會不斷中斷。當然要給循環設置一個條件來退出循環,不然就會產生一個無限數列出來。同樣的,把函數改成generator后,我們基本上從來不會用 next() 來獲取下一個返回值,而是直接使用 for 循環來迭代。

但是用for循環調用generator時,發現拿不到generator的return語句的返回值。如果想要拿到返回值,必須捕獲StopIteration錯誤,返回值包含在StopIteration的value中。

send:

執行到yield時,gen函數作用暫時保存,返回i的值;temp接收下次c.send("python"),send發送過來的值,c.next()等價c.send(None)。

def nums():

????for i in range(10):

????????ret = yield i

????????if ret == '平方':

????????????print(i**2)

????????elif ret == '立方':

????????????print(i**3)

num = nums()

print(num)

print(next(num))

print(next(num))

print(next(num))

print(next(num))

print(next(num))

print('----------')

num1 = nums()

next(num1)

num1.send('平方')

num1.send('平方')

num1.send('平方')

num1.send('立方')

num1.send('立方')

num1.send('立方')

__next__:作為一個魔法方法,__next__等價于next()

生成器是這樣一個函數,它記住上一次返回時在函數體中的位置。對生成器函數的第二次(或第 n 次)調用跳轉至該函數中間,而上次調用的所有局部變量都保持不變。

生成器不僅“記住”了它數據狀態;生成器還“記住”了它在流控制構造(在命令式編程中,這種構造不只是數據值)中的位置。

生成器的特點:

節約內存

迭代到下一次的調用時,所使用的參數都是第一次所保留下的,即是說,在整個所有函數調用的參數都是第一次所調用時保留的,而不是新創建的

迭代器

迭代是訪問集合元素的一種方式。迭代器是一個可以記住遍歷的位置的對象。迭代器對象從集合的第一個元素開始訪問,直到所有的元素被訪問完結束。迭代器只能往前不會后退。

可迭代對象

以直接作用于 for 循環的數據類型有以下幾種:

一類是集合數據類型,如 list 、 tuple 、 dict 、 set 、 str 等;

一類是 generator ,包括生成器和帶 yield 的generator function。

這些可以直接作用于 for 循環的對象統稱為可迭代對象: Iterable 。

判斷是否可以迭代

可以使用 isinstance() 判斷一個對象是否是 Iterable 對象:

from collections import Iterable,Iterator

def f():

????yield 'hello'

print(isinstance(f(),Iterable))

print(isinstance(f(),Iterator))

print(isinstance('abc',Iterable))

print(isinstance('abc',Iterator))

迭代器

可以被next()函數調用并不斷返回下一個值的對象稱為迭代器:Iterator。

可以使用 isinstance() 判斷一個對象是否是 Iterator 對象。

iter()函數

生成器都是 Iterator 對象,但 list 、 dict 、 str 雖然是 Iterable ,卻不是 Iterator 。

把 list 、 dict 、 str 等 Iterable 變成 Iterator 可以使用 iter() 函數。

name = 'abc'

myIter = iter(name)

print(type(myIter))

print(isinstance(myIter,Iterator))

try:

????print(next(myIter))

????print(next(myIter))

????print(next(myIter))

????print(next(myIter))

except StopIteration as ex:

????print('迭代完了,%s'%ex)

閉包

函數引用

閉包概念:

在函數內部再定義一個函數,并且這個函數用到了外邊函數的變量,那么將這個函數以及用到的一些變量稱之為閉包。

def test(number):

????'''

????在函數內部再定義一個函數,并且這個函數用到了外邊函數的變量,

????那么將這個函數以及用到的一些變量稱之為閉包

????'''

????def test_in(number_in):

????????print("in test_in 函數, number_in is %d"%number_in)

????????return number+number_in

????#其實這里返回的就是閉包的結果

????return test_in

#給test函數賦值,這個20就是給參數number

ret = test(20)

#注意這里的100其實給參數number_in

print(ret(100))

#注意這里的200其實給參數number_in

print(ret(200))

閉包思考:

1.閉包似優化了變量,原來需要類對象完成的工作,閉包也可以完成

2.由于閉包引用了外部函數的局部變量,則外部函數的局部變量沒有及時釋放,消耗內存

裝飾器

裝飾器,功能就是在運行原來功能基礎上,加上一些其它功能,比如權限的驗證,比如日志的記錄等等。不修改原來的代碼,進行功能的擴展。

比如java中的動態代理,python的注解裝飾器

其實python的裝飾器,是修改了代碼。

def login(func):

????def inner(a,b):

????????user = input('請輸入用戶名:')

????????psd = input('請輸入密碼:')

????????if user == a and psd == b:

????????????print('Welcome in!')

????????????func(a,b)

????????else:

????????????print('Passward error!')

????return inner

@login

def f1(nowHaveUser,nowHavePsd):

print('f1')

def f2():

print('f2')

def f3():

print('f3')

def f4():

print('f4')

f1('haha','123456')


python解釋器就會從上到下解釋代碼,步驟如下:

1.def login(func):?==>將login函數加載到內存

2.@login

沒錯,?從表面上看解釋器僅僅會解釋這兩句代碼,因為函數在?沒有被調用之前其內部代碼不會被執行。

從表面上看解釋器著實會執行這兩句,但是@login這一句代碼里卻有大文章,@函數名?是python的一種語法糖。

上例@login內部會執行一下操作:

執行login函數

執login1函數?,并將@login下面的函數作為login函數的參數,即:@login等價于login(f1)所以,內部就會去執行。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 1.1==,is的使用 ·is是比較兩個引用是否指向了同一個對象(引用比較)。 ·==是比較兩個對象是否相等。 1...
    TENG書閱讀 745評論 0 0
  • 基礎1.r''表示''內部的字符串默認不轉義2.'''...'''表示多行內容3. 布爾值:True、False(...
    neo已經被使用閱讀 1,723評論 0 5
  • 住的這個小區也建好幾年了,怎么周圍一直在裝修,鉆啊鉆啊。于是開大音樂,擋住鉆的聲音,周期性重復的聲音實在是亂人心緒...
    KevinCool閱讀 839評論 1 1
  • 今晚吃秘魯菜,酸酸辣辣的味道,一不留神吃多了。席間,突然想起已經兩年多沒有跟納豆先生說:我從明天開始減肥這句話了...
    瘋小蝦閱讀 870評論 11 11
  • 有時候當被別人說到“你變了”之類的話,總是會不由自主的感到緊張焦慮 緊張別人說起自己的變是怎樣一種口吻和態度,更怕...
    藝妹哦耶耶閱讀 478評論 1 2