day21(python高级编程,property属性,生成器,迭代器,闭包,装饰器) - Go语言中文社区

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

版权声明:本文来源简书,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://www.jianshu.com/p/e62a818f63b4
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2020-01-07 21:14:47
  • 阅读 ( 1400 )
  • 分类:

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢