屬性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í)行讼庇。