属性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)所以,内部就会去执行。