屬性property
私有屬性添加getter和setter方法
對于類對象的私有屬性,我們不能直接調(diào)用,可以添加方法來調(diào)用。
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())
結(jié)果:
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)
結(jié)果:
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)
結(jié)果:
10
輸入的年齡不符合
16
生成器
通過列表生成式,我們可以直接創(chuàng)建一個列表。但是,受到內(nèi)存限制,列表容量肯定是有限的。而且,創(chuàng)建一個包含100萬個元素的列表,不僅占用很大的存儲空間,如果我們僅僅需要訪問前面幾個元素,那后面絕大多數(shù)元素占用的空間都白白浪費了。所以,如果列表元素可以按照某種算法推算出來,那我們是否可以在循環(huán)的過程中不斷推算出后續(xù)的元素呢?這樣就不必創(chuàng)建完整的list,從而節(jié)省大量的空間。在Python中,這種一邊循環(huán)一邊計算的機制,稱為生成器:generator。
創(chuàng)建生成器
1.把列表生成式的[]改成()
如:
[ x*2 for x in range(5)]
改為:
( x*2 for x in range(5))
如果想要打印,可以通過next()獲取生成器的下一個返回值,而且,generator也是可迭代的,所以也可以用循環(huán)遍歷。
2.有的比較復(fù)雜,用類似列表生成式的for循環(huán)無法實現(xiàn)的時候,還可以用函數(shù)來實現(xiàn)。
可以用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 的例子,我們在循環(huán)過程中不斷調(diào)用 yield ,就會不斷中斷。當(dāng)然要給循環(huán)設(shè)置一個條件來退出循環(huán),不然就會產(chǎn)生一個無限數(shù)列出來。同樣的,把函數(shù)改成generator后,我們基本上從來不會用 next() 來獲取下一個返回值,而是直接使用 for 循環(huán)來迭代。
但是用for循環(huán)調(diào)用generator時,發(fā)現(xiàn)拿不到generator的return語句的返回值。如果想要拿到返回值,必須捕獲StopIteration錯誤,返回值包含在StopIteration的value中。
send:
執(zhí)行到y(tǒng)ield時,gen函數(shù)作用暫時保存,返回i的值;temp接收下次c.send("python"),send發(fā)送過來的值,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()
生成器是這樣一個函數(shù),它記住上一次返回時在函數(shù)體中的位置。對生成器函數(shù)的第二次(或第 n 次)調(diào)用跳轉(zhuǎn)至該函數(shù)中間,而上次調(diào)用的所有局部變量都保持不變。
生成器不僅“記住”了它數(shù)據(jù)狀態(tài);生成器還“記住”了它在流控制構(gòu)造(在命令式編程中,這種構(gòu)造不只是數(shù)據(jù)值)中的位置。
生成器的特點:
節(jié)約內(nèi)存
迭代到下一次的調(diào)用時,所使用的參數(shù)都是第一次所保留下的,即是說,在整個所有函數(shù)調(diào)用的參數(shù)都是第一次所調(diào)用時保留的,而不是新創(chuàng)建的
迭代器
迭代是訪問集合元素的一種方式。迭代器是一個可以記住遍歷的位置的對象。迭代器對象從集合的第一個元素開始訪問,直到所有的元素被訪問完結(jié)束。迭代器只能往前不會后退。
可迭代對象
以直接作用于 for 循環(huán)的數(shù)據(jù)類型有以下幾種:
一類是集合數(shù)據(jù)類型,如 list 、 tuple 、 dict 、 set 、 str 等;
一類是 generator ,包括生成器和帶 yield 的generator function。
這些可以直接作用于 for 循環(huán)的對象統(tǒng)稱為可迭代對象: 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()函數(shù)調(diào)用并不斷返回下一個值的對象稱為迭代器:Iterator。
可以使用 isinstance() 判斷一個對象是否是 Iterator 對象。
iter()函數(shù)
生成器都是 Iterator 對象,但 list 、 dict 、 str 雖然是 Iterable ,卻不是 Iterator 。
把 list 、 dict 、 str 等 Iterable 變成 Iterator 可以使用 iter() 函數(shù)。
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)
閉包
函數(shù)引用
閉包概念:
在函數(shù)內(nèi)部再定義一個函數(shù),并且這個函數(shù)用到了外邊函數(shù)的變量,那么將這個函數(shù)以及用到的一些變量稱之為閉包。
def test(number):
????'''
????在函數(shù)內(nèi)部再定義一個函數(shù),并且這個函數(shù)用到了外邊函數(shù)的變量,
????那么將這個函數(shù)以及用到的一些變量稱之為閉包
????'''
????def test_in(number_in):
????????print("in test_in 函數(shù), number_in is %d"%number_in)
????????return number+number_in
????#其實這里返回的就是閉包的結(jié)果
????return test_in
#給test函數(shù)賦值,這個20就是給參數(shù)number
ret = test(20)
#注意這里的100其實給參數(shù)number_in
print(ret(100))
#注意這里的200其實給參數(shù)number_in
print(ret(200))
閉包思考:
1.閉包似優(yōu)化了變量,原來需要類對象完成的工作,閉包也可以完成
2.由于閉包引用了外部函數(shù)的局部變量,則外部函數(shù)的局部變量沒有及時釋放,消耗內(nèi)存
裝飾器
裝飾器,功能就是在運行原來功能基礎(chǔ)上,加上一些其它功能,比如權(quán)限的驗證,比如日志的記錄等等。不修改原來的代碼,進行功能的擴展。
比如java中的動態(tài)代理,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函數(shù)加載到內(nèi)存
2.@login
沒錯,?從表面上看解釋器僅僅會解釋這兩句代碼,因為函數(shù)在?沒有被調(diào)用之前其內(nèi)部代碼不會被執(zhí)行。
從表面上看解釋器著實會執(zhí)行這兩句,但是@login這一句代碼里卻有大文章,@函數(shù)名?是python的一種語法糖。
上例@login內(nèi)部會執(zhí)行一下操作:
執(zhí)行l(wèi)ogin函數(shù)
執(zhí)login1函數(shù)?,并將@login下面的函數(shù)作為login函數(shù)的參數(shù),即:@login等價于login(f1)所以,內(nèi)部就會去執(zhí)行。